পাইথনে সি-জাতীয় কাঠামো


447

পাইথনে সি-জাতীয় কাঠামোটি সুবিধামত সংজ্ঞায়িত করার কোনও উপায় আছে কি? আমি স্টাফ লিখতে ক্লান্ত হয়ে পড়েছি:

class MyStruct():
    def __init__(self, field1, field2, field3):
        self.field1 = field1
        self.field2 = field2
        self.field3 = field3

5
আধা-সম্পর্কিত, বীজগণিতের ডেটা ধরণের একদম দুর্দান্ত লাগবে তবে এগুলি ভালভাবে ব্যবহার করতে আপনার সাধারণত প্যাটার্ন মেলানো দরকার।
এডওয়ার্ড জেড। ইয়াং

51
লেখার জন্য ক্লান্তিকর ছাড়া এই পদ্ধতিতে কি কিছু ভুল আছে?
লেভেস্ক

2
আপনি ডস্ট্রাক্ট দরকারী খুঁজে পেতে পারেন: github.com/dorkitude/dstruct
কাইল ওয়াইল্ড

10
টাইপস ছাড়াই @ লেভেস্ককে শক্তিশালী করা কঠিন, স্কিমিং কোডের চেয়ে এক নজরে পড়া আরও শক্তMyStruct = namedtuple("MyStruct", "field1 field2 field3")
সাম বুসালিস

1
pandas.Series(a=42).aআপনার ডেটা-সায়েন্টিস্ট হলে এটি করা উচিত ...
মার্ক হরভাথ

উত্তর:


341

একটি নামযুক্ত টুপল ব্যবহার করুন , যা পাইথন ২.6 এর স্ট্যান্ডার্ড লাইব্রেরিতে সংগ্রহ মডিউলটিতে যুক্ত হয়েছিল । আপনার পাইথন ২.৪ সমর্থন করার প্রয়োজন হলে রেমন্ড হেটিঙ্গারের নামকৃত টিপল রেসিপি ব্যবহার করাও সম্ভব ।

এটি আপনার মৌলিক উদাহরণের জন্য দুর্দান্ত, তবে আপনি পরেও চালাতে পারেন এমন এক প্রান্তের কেসগুলি কভার করে। আপনার উপরের অংশটি এইভাবে লেখা হবে:

from collections import namedtuple
MyStruct = namedtuple("MyStruct", "field1 field2 field3")

নতুনভাবে তৈরি টাইপটি এটি ব্যবহার করা যেতে পারে:

m = MyStruct("foo", "bar", "baz")

আপনি নামযুক্ত যুক্তিগুলি ব্যবহার করতে পারেন:

m = MyStruct(field1="foo", field2="bar", field3="baz")

164
... তবে নেমটুপল অপরিবর্তনীয়। ওপিতে উদাহরণটি পরিবর্তনীয়।
mhowison

28
@ মিউইউইসন - আমার ক্ষেত্রে এটি কেবল একটি প্লাস।
আর্টঅফ ওয়ারফেয়ার

3
সুন্দর সমাধান। আপনি এই টিপলসগুলির একটি অ্যারের মধ্য দিয়ে কীভাবে লুপ করবেন? আমি ধরে নেব যে ক্ষেত্রের 1-3 এর টিউপল অবজেক্টগুলির একই নাম থাকতে হবে।
মাইকেল স্মিথ

2
নেমডটপলে প্রায় চারটি আর্গুমেন্ট থাকতে পারে যাতে করে আমরা কীভাবে সম্পর্কিত নেম টুপল সহ আরও ডেটা সদস্যদের সাথে কাঠামো ম্যাপ করতে পারি
কাপিল

3
@ ক্যাপিল - নামপত্রে দ্বিতীয় যুক্তিতে সদস্যদের নামের তালিকা থাকা উচিত। এই তালিকা যে কোনও দৈর্ঘ্য হতে পারে।
আর্টঅফ ওয়ারফেয়ার

226

আপডেট : ডেটা ক্লাস

প্রবর্তনের সঙ্গে ডেটা ক্লাস মধ্যে পাইথন 3.7 আমরা খুব কাছাকাছি পেতে।

নীচের উদাহরণটি নীচের নেমেডটুপলের উদাহরণের সাথে সমান , তবে ফলস্বরূপ বস্তুটি পরিবর্তনীয় এবং এটি ডিফল্ট মানগুলির জন্য অনুমতি দেয়।

from dataclasses import dataclass


@dataclass
class Point:
    x: float
    y: float
    z: float = 0.0


p = Point(1.5, 2.5)

print(p)  # Point(x=1.5, y=2.5, z=0.0)

আপনি আরও সুনির্দিষ্ট ধরণের টিকা ব্যবহার করতে চান ক্ষেত্রে এটি নতুন টাইপিং মডিউলের সাথে দুর্দান্তভাবে খেলবে ।

আমি এর জন্য মরিয়া অপেক্ষা করছিলাম! আপনি যদি আমাকে জিজ্ঞাসা করেন, টাইপিং মডিউলের সাথে মিলিয়ে ডেটা ক্লাস এবং নতুন নেমডটপল ডিক্লেয়ারেশন, গডসেন্ড !

নামের উন্নত নাম ঘোষণা up

পাইথন ৩.6 এর পর থেকে এটি বেশ সহজ এবং সুন্দর হয়ে উঠেছে (আইএমএইচও), যতক্ষণ আপনি অপরিবর্তনীয়তার সাথে বাঁচতে পারবেন ।

নামডটপলস ঘোষণার একটি নতুন উপায় চালু করা হয়েছিল, যা টাইপ টীকাগুলির জন্যও অনুমতি দেয় :

from typing import NamedTuple


class User(NamedTuple):
    name: str


class MyStruct(NamedTuple):
    foo: str
    bar: int
    baz: list
    qux: User


my_item = MyStruct('foo', 0, ['baz'], User('peter'))

print(my_item) # MyStruct(foo='foo', bar=0, baz=['baz'], qux=User(name='peter'))

6
সাথী, আপনি সবেমাত্র আমার দিনটি তৈরি করেছেন - অপরিবর্তনীয়
ডিক্টস

10
dataclassপাইথন ৩.7- এ মডিউলটি নতুন তবে আপনি পারেন pip install dataclasses। এটি পাইথন ৩.6 এর ব্যাকপোর্ট। পিপাই.আর.জি.
প্রকল্প /

উন্নত নেমডটপল ঘোষণার জন্য +1। পুরানো
উপায়টি

@ লাভান্ডে আমি কি জানতে পারি যে breaking.6 থেকে ৩.7 এর মধ্যে কোন ব্রেকিং পরিবর্তন ঘটেছে যে আপনাকে একটি ছোটখাটো সংস্করণ ব্যাকপোর্ট করতে হবে ...?
বেগুনি বরফ

1
@ পুরপিসি এটি পিইপি 557, ডেটা ক্লাসের একটি বাস্তবায়ন ছিল বিশদগুলি @dataclassএখানে: পিপাই.আর.জি.
প্রকল্প /

96

আপনি অনেকগুলি জিনিসের জন্য একটি টিপল ব্যবহার করতে পারেন যেখানে আপনি সিতে স্ট্রাক্ট ব্যবহার করবেন (উদাহরণস্বরূপ x, y স্থানাঙ্ক বা আরজিবি রঙের মতো)।

অন্য সব কিছুর জন্য আপনি অভিধান বা এগুলির মতো একটি ইউটিলিটি বর্গ ব্যবহার করতে পারেন এই এক :

>>> class Bunch:
...     def __init__(self, **kwds):
...         self.__dict__.update(kwds)
...
>>> mystruct = Bunch(field1=value1, field2=value2)

আমি মনে করি পাইথন কুকবুকের প্রকাশিত সংস্করণে "সুনির্দিষ্ট" আলোচনাটি এখানে রয়েছে


5
খালি শ্রেণি কি একই কাজ করবে?
কর্ট লিউ

44
আপনি অজগর থেকে নতুন হন নোট করুন: সি স্ট্রাক্টের বিপরীতে
টিউপলগুলি

2
@KurtLiu না, এটা সম্ভবত বলতে হবেTypeError: this constructor takes no arguments
Evgeni Sergeev

84

সম্ভবত আপনি নির্মাতারা ছাড়াই স্ট্রাক্টসের সন্ধান করছেন:

class Sample:
  name = ''
  average = 0.0
  values = None # list cannot be initialized here!


s1 = Sample()
s1.name = "sample 1"
s1.values = []
s1.values.append(1)
s1.values.append(2)
s1.values.append(3)

s2 = Sample()
s2.name = "sample 2"
s2.values = []
s2.values.append(4)

for v in s1.values:   # prints 1,2,3 --> OK.
  print v
print "***"
for v in s2.values:   # prints 4 --> OK.
  print v

5
আপনি এখানে যা করছেন তা প্রযুক্তিগতভাবে কাজ করে তবে এটি কেন কাজ করে তা অনেক ব্যবহারকারীদের কাছে এটি তাত্ক্ষণিকভাবে স্পষ্ট নয় । আপনার ঘোষণাগুলির অধীনে class Sample:তাত্ক্ষণিকভাবে কিছু করবেন না; তারা বর্গ বৈশিষ্ট্য সেট। এগুলি সর্বদা উদা হিসাবে ব্যবহার করা যেতে পারে Sample.name
মুর

22
আপনি আসলে যা করছেন তা হ'ল বস্তুগুলিতে s1এবং s2রানটাইমগুলিতে উদাহরণ বৈশিষ্ট্য যুক্ত করা । অন্যথায় নিষিদ্ধ না হলে আপনি nameক্লাসের কোনও nameবৈশিষ্ট্য আছে কিনা তা যে কোনও সময়ে যে কোনও শ্রেণীর যেকোন পরিস্থিতিতে অ্যাট্রিবিউটটি যুক্ত বা সংশোধন করতে পারেন । সম্ভবত এটি করার সবচেয়ে বড় কার্যকরী সমস্যাটি হ'ল একই শ্রেণীর বিভিন্ন উদাহরণ আপনি সেট করেছেন কিনা তার উপর নির্ভর করে ভিন্ন আচরণ করবে name। আপনি যদি আপডেট করেন তবে Sample.nameসুস্পষ্টভাবে সেট করা nameসম্পত্তি ব্যতীত যে কোনও অবজেক্ট নতুন ফিরিয়ে দেবে name
মুর

2
এটি কোনও স্ট্রাক্ট-শর্ট 'ক্লাসে' যেমন কোনও পদ্ধতি ছাড়াই, ডিফল্ট মান সহ 'ক্ষেত্র' (শ্রেণীর বৈশিষ্ট্য, আমি জানি) কাছে যেতে এটিই তত কাছাকাছি। যতক্ষণ না এটি কোনও পরিবর্তনীয় প্রকার নয় (ডিক্ট, তালিকা), আপনি ভাল আছেন। অবশ্যই, আপনি PEP-8 অথবা "বন্ধুত্বপূর্ণ" PyCharm এর "বর্গ কোন হয়েছে মত আইডিই চেক বিরুদ্ধে মারতে পারেন Init পদ্ধতি"।
টমসজ গেন্ডার

4
আমি চ্যানিং মুর দ্বারা বর্ণিত পার্শ্ব প্রতিক্রিয়াটি পরীক্ষা করেছিলাম। selfআপনি যদি আমাকে জিজ্ঞাসা করেন তবে কয়েকটি কীওয়ার্ড এবং কনস্ট্রাক্টর লাইনের অর্থনীতির মূল্য নেই । আমি কৃতজ্ঞ যে যদি জোস তার উত্তরটি সম্পাদনা করতে পারে তবে ঘটনাক্রমে ঘটনাক্রমে মানগুলি ভাগ করে নেওয়ার ঝুঁকি সম্পর্কে একটি সতর্কতা বার্তা যুক্ত করতে পারে।
স্টাফেন সি।

@ চ্যানিংমুর: আপনি যে বিষয়টি বর্ণনা করছেন তা পুনরায় তৈরি করার চেষ্টা করেছি, কিন্তু ব্যর্থ হয়েছিল। আপনি এখানে একটি ন্যূনতম কাজের উদাহরণ উপস্থাপন করতে পারেন যেখানে সমস্যাটি পপ আপ হয়?
gebbissimo

67

কীভাবে একটি অভিধান?

এটার মতো কিছু:

myStruct = {'field1': 'some val', 'field2': 'some val'}

তারপরে আপনি মানগুলি হস্তান্তর করতে এটি ব্যবহার করতে পারেন:

print myStruct['field1']
myStruct['field2'] = 'some other values'

এবং মানগুলি স্ট্রিং হতে হবে না। এগুলি অন্য কোনও বস্তু হতে পারে।


34
এটিও আমার মতামত ছিল, তবে আমার মনে হয় এটি বিপজ্জনকভাবে বিপজ্জনক কারণ একটি অভিধান কোনও কীটির জন্য যে কোনও কিছু গ্রহণ করতে পারে। আমি যখন আমার স্ট্রাক্ট ["ফিল্ড"] সেট করতে চেয়েছি তখন আমি মাইস্ট্রাস্ট ["এফফিল্ড"] সেট করলে কোনও ত্রুটি হবে না। পরে যখন মাইস্ট্রাস্ট ["ক্ষেত্র"] ব্যবহার করছি বা পুনরায় ব্যবহার করব তখন বিষয়টি সম্ভবত (বা নাও) স্পষ্ট হয়ে উঠবে। আমি পাবলোগের পদ্ধতির পছন্দ করি।
মোবাবু

পাবলোগের সাথে একই সমস্যা বিদ্যমান। নিম্নলিখিত কোডটি তার সাথে যুক্ত করার চেষ্টা করুন: pt3.w = 1 print pt3.w ডিক্ট যুক্ত ভাষায় এগুলি ব্যবহার করা ভাল, বিশেষত অবজেক্টগুলি সিরিয়ালকরণের জন্য, যেহেতু আপনি অদ্ভুত না থাকেন ততক্ষণ আপনি সেগুলি এবং অন্যান্য সিরিয়ালাইজেশন লাইব্রেরিগুলি সংরক্ষণ করতে স্বয়ংক্রিয়ভাবে আমদানি জেসন ব্যবহার করতে পারেন আপনার ডিক এর ভিতরে স্টাফ ডিক্টস হ'ল ডেটা এবং লজিককে আলাদা রাখার সমাধান এবং এমন লোকদের পক্ষে স্ট্রাক্টের চেয়ে ভাল যারা কাস্টম সিরিয়ালাইজ এবং আনসিরিয়াল ফাংশন লিখতে চান না এবং আচারের মতো অ-বহনযোগ্য সিরিয়ালাইজার ব্যবহার করতে চান না।
পোইকিলোস

27

ডিএফ: এটি বেশ দুর্দান্ত ... আমি জানতাম না যে আমি ডিক ব্যবহার করে কোনও ক্লাসের ক্ষেত্রগুলি অ্যাক্সেস করতে পারি।

চিহ্নিত করুন: আমার যে পরিস্থিতিগুলির আমি ইচ্ছা করি সেগুলি হুবহু আমি যখন টুপল চাইতাম তবে অভিধান হিসাবে "ভারী" কিছুই না।

আপনি অভিধান ব্যবহার করে কোনও শ্রেণীর ক্ষেত্রগুলি অ্যাক্সেস করতে পারেন কারণ কোনও শ্রেণীর ক্ষেত্র, তার পদ্ধতি এবং এর সমস্ত বৈশিষ্ট্য dicts (অন্তত সিপিথনে) ব্যবহার করে অভ্যন্তরীণভাবে সঞ্চিত রয়েছে।

... যা আমাদের দ্বিতীয় মন্তব্যে নিয়ে যায়। পাইথন ডিসটিক্সগুলি "ভারী" বলে বিশ্বাস করা একটি অত্যন্ত অ-পাইথোনস্টিক ধারণা। এবং এই জাতীয় মন্তব্য পড়লে আমার পাইথন জেনকে হত্যা করা হয়। এটা ভালো না.

আপনি দেখুন, যখন আপনি কোনও শ্রেণি ঘোষণা করেন আপনি আসলে কোনও অভিধানের চারপাশে একটি বেশ জটিল মোড়ক তৈরি করছেন - সুতরাং, যদি কিছু হয় তবে আপনি একটি সাধারণ অভিধান ব্যবহার করে বেশি ওভারহেড যুক্ত করছেন। একটি ওভারহেড যা কোনওভাবেই অর্থহীন। আপনি যদি পারফরম্যান্স সমালোচনামূলক অ্যাপ্লিকেশনগুলিতে কাজ করছেন তবে সি বা কিছু ব্যবহার করুন।


5
# 1, সিথন! = সিপিথন আমি মনে করি আপনি সিপিথন, সিটিতে লিখিত পাইথন প্রয়োগের কথা বলছিলেন, সিথন নয়, সি কোডে পাইথন কোডটি সংকলন করার জন্য একটি প্রকল্প। আমি ঠিক করেছি আপনার উত্তর সম্পাদনা। # 2, আমার মনে হয় যখন তিনি বলেছিলেন পোকাগুলি ভারী, তিনি সিনট্যাক্সের কথা উল্লেখ করছিলেন। self['member']এর চেয়ে 3 টি অক্ষর দীর্ঘ self.memberএবং সেই অক্ষরগুলি সমস্ত তুলনামূলকভাবে কব্জি-বান্ধব।
আর্টঅফ ওয়ারফেয়ার

19

আপনি স্ট্যান্ডার্ড লাইব্রেরিতে যে সি কাঠামো উপলভ্য তা সাবক্লাস করতে পারেন। Ctypes মডিউল একটি উপলব্ধ গঠন বর্গ । দস্তাবেজগুলির উদাহরণ:

>>> from ctypes import *
>>> class POINT(Structure):
...     _fields_ = [("x", c_int),
...                 ("y", c_int)]
...
>>> point = POINT(10, 20)
>>> print point.x, point.y
10 20
>>> point = POINT(y=5)
>>> print point.x, point.y
0 5
>>> POINT(1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ValueError: too many initializers
>>>
>>> class RECT(Structure):
...     _fields_ = [("upperleft", POINT),
...                 ("lowerright", POINT)]
...
>>> rc = RECT(point)
>>> print rc.upperleft.x, rc.upperleft.y
0 5
>>> print rc.lowerright.x, rc.lowerright.y
0 0
>>>

18

আমি সলট ব্যবহার করে এমন একটি সমাধান যুক্ত করতে চাই :

class Point:
    __slots__ = ["x", "y"]
    def __init__(self, x, y):
        self.x = x
        self.y = y

অবশ্যই স্লটগুলির জন্য ডকুমেন্টেশন যাচাই করুন তবে স্লটগুলির দ্রুত ব্যাখ্যাটি হ'ল এটি অজগরটির বলার উপায়: "আপনি যদি এই বৈশিষ্ট্যগুলি এবং কেবলমাত্র এই বৈশিষ্ট্যগুলিকে শ্রেণিতে লক করতে পারেন তবে আপনি প্রতিশ্রুতি দেন যে আপনি ক্লাসে একবারে কোনও নতুন বৈশিষ্ট্য যুক্ত করবেন না commit ইনস্ট্যান্টেশনযুক্ত (হ্যাঁ আপনি একটি শ্রেণীর উদাহরণে নতুন বৈশিষ্ট্যগুলি যুক্ত করতে পারেন, নীচের উদাহরণটি দেখুন) তবে আমি বৃহত মেমরির বরাদ্দ সরিয়ে ফেলব যা একটি শ্রেণীর উদাহরণগুলিতে নতুন বৈশিষ্ট্য যুক্ত করার অনুমতি দেয় এবং এই স্লটযুক্ত বৈশিষ্ট্যের জন্য আমার যা প্রয়োজন তা কেবল ব্যবহার করব "।

শ্রেণীর উদাহরণগুলিতে গুণাবলী যুক্ত করার উদাহরণ (এইভাবে স্লট ব্যবহার না করা):

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

p1 = Point(3,5)
p1.z = 8
print(p1.z)

আউটপুট: 8

শ্রেণীর উদাহরণগুলিতে যেখানে স্লট ব্যবহার করা হয়েছিল তাতে বৈশিষ্ট্যগুলি যুক্ত করার চেষ্টা করার উদাহরণ:

class Point:
    __slots__ = ["x", "y"]
    def __init__(self, x, y):
        self.x = x
        self.y = y

p1 = Point(3,5)
p1.z = 8

আউটপুট: অ্যাট্রিবিউটআরার: 'পয়েন্ট' অবজেক্টের কোনও 'z' বৈশিষ্ট্য নেই

এটি কার্যকরভাবে স্ট্রাক হিসাবে কাজ করতে পারে এবং ক্লাসের তুলনায় কম স্মৃতি ব্যবহার করে (স্ট্রাক্টের মতো, যদিও আমি ঠিক কতটা গবেষণা করে নি)। আপনি যদি বস্তুটির প্রচুর পরিমাণে উদাহরণ তৈরি করেন এবং বৈশিষ্ট্যগুলি যুক্ত করার প্রয়োজন না হয় তবে স্লটগুলি ব্যবহার করার পরামর্শ দেওয়া হচ্ছে। একটি পয়েন্ট অবজেক্ট এটির একটি ভাল উদাহরণ কারণ এটি সম্ভবত একটি ডেটাসেট বর্ণনা করার জন্য অনেকগুলি পয়েন্ট ইনস্ট্যান্টিয়েট করতে পারে।


17

আপনি অবস্থান অনুসারে উদাহরণের ভেরিয়েবলগুলিতেও init পরামিতিগুলি পাস করতে পারেন

# Abstract struct class       
class Struct:
    def __init__ (self, *argv, **argd):
        if len(argd):
            # Update by dictionary
            self.__dict__.update (argd)
        else:
            # Update by position
            attrs = filter (lambda x: x[0:2] != "__", dir(self))
            for n in range(len(argv)):
                setattr(self, attrs[n], argv[n])

# Specific class
class Point3dStruct (Struct):
    x = 0
    y = 0
    z = 0

pt1 = Point3dStruct()
pt1.x = 10

print pt1.x
print "-"*10

pt2 = Point3dStruct(5, 6)

print pt2.x, pt2.y
print "-"*10

pt3 = Point3dStruct (x=1, y=2, z=3)
print pt3.x, pt3.y, pt3.z
print "-"*10

7
অবস্থান অনুসারে আপডেট করা বৈশিষ্ট্যের ঘোষণার ক্রম উপেক্ষা করে এবং পরিবর্তে তাদের বর্ণমালা বাছাই ব্যবহার করে। সুতরাং আপনি যদি Point3dStructঘোষণায় লাইনের ক্রমটি পরিবর্তন করেন তবে Point3dStruct(5, 6)প্রত্যাশার মতো কাজ করবে না। এটি আশ্চর্যজনক যে সমস্ত 6 বছরে কেউ এটি লেখেনি।
ল্যাপিস

আপনার দুর্দান্ত কোডটিতে পাইথন 3 সংস্করণ যুক্ত করতে পারবেন? মহান কাজ! আমি পছন্দ করি যে আপনি বিমূর্ত কিছু নিয়েছেন এবং এটি দ্বিতীয় নির্দিষ্ট শ্রেণীর সাথে স্পষ্ট করে তুলেছেন। এটি ত্রুটি পরিচালনা / ধরার জন্য ভাল হওয়া উচিত। পাইথন 3 এর জন্য, কেবল>> এবং > পরিবর্তন printকরুন (ফিল্টার এখন তার নিজস্ব পুনরাবৃত্ত বস্তু এবং প্রয়োজনীয় )। print()attrs[n]next(attrs)next
জোনাথন কোমার 17'17

10

যখনই আমার একটি "তাত্ক্ষণিক ডেটা অবজেক্ট প্রয়োজন যা অভিধানের মতো আচরণ করে" (আমি সি স্ট্রাক্টের কথা ভাবি না !) আমি এই চতুর হ্যাকটি মনে করি:

class Map(dict):
    def __init__(self, **kwargs):
        super(Map, self).__init__(**kwargs)
        self.__dict__ = self

এখন আপনি কেবল বলতে পারেন:

struct = Map(field1='foo', field2='bar', field3=42)

self.assertEquals('bar', struct.field2)
self.assertEquals(42, struct['field3'])

আপনার যখন "ডেটা ব্যাগ যা কোনও শ্রেণি নয়" প্রয়োজন হয় সেই সময়গুলির জন্য পুরোপুরি কার্যকর, এবং যখন নামকরণকৃত শিক্ষার্থীরা বোধগম্য নয় ...


আমি পান্ডাস ব্যবহার করি eriesসরিজগুলি (a = 42) ;-)
মার্ক হরভথ

8

আপনি পাইথনগুলিতে সি-স্টাইল স্ট্রাক্টটি নিম্নলিখিত উপায়ে অ্যাক্সেস করুন।

class cstruct:
    var_i = 0
    var_f = 0.0
    var_str = ""

আপনি যদি শুধু cstruct অবজেক্ট ব্যবহার করতে চান

obj = cstruct()
obj.var_i = 50
obj.var_f = 50.00
obj.var_str = "fifty"
print "cstruct: obj i=%d f=%f s=%s" %(obj.var_i, obj.var_f, obj.var_str)

আপনি যদি cstruct এর অবজেক্টের একটি অ্যারে তৈরি করতে চান

obj_array = [cstruct() for i in range(10)]
obj_array[0].var_i = 10
obj_array[0].var_f = 10.00
obj_array[0].var_str = "ten"

#go ahead and fill rest of array instaces of struct

#print all the value
for i in range(10):
    print "cstruct: obj_array i=%d f=%f s=%s" %(obj_array[i].var_i, obj_array[i].var_f, obj_array[i].var_str)

দ্রষ্টব্য: 'সিস্ট্রাক্ট' নামের পরিবর্তে দয়া করে আপনার কাঠামোর নামটি var_i, var_f, var_str এর পরিবর্তে ব্যবহার করুন, দয়া করে আপনার কাঠামোর সদস্য ভেরিয়েবলটি সংজ্ঞায়িত করুন।



8

এখানে কয়েকটি উত্তর ব্যাপকভাবে বিস্তৃত। আমি খুঁজে পাওয়া সবচেয়ে সহজ বিকল্পটি হ'ল ( http://norvig.com/python-iaq.html থেকে ):

class Struct:
    "A structure that can have any fields defined."
    def __init__(self, **entries): self.__dict__.update(entries)

Initialising:

>>> options = Struct(answer=42, linelen=80, font='courier')
>>> options.answer
42

আরও যুক্ত করা:

>>> options.cat = "dog"
>>> options.cat
dog

সম্পাদনা: দুঃখিত, ইতিমধ্যে আরও নীচে এই উদাহরণটি দেখেনি।


5

এটি কিছুটা দেরিতে হতে পারে তবে আমি পাইথন মেটা-ক্লাসগুলি (নীচে সজ্জা সংস্করণ) ব্যবহার করে একটি সমাধান করেছি।

__init__রান রান চলাকালীন যখন ডাকা হয়, তখন এটি প্রতিটি আর্গুমেন্ট এবং তাদের মান ধরে এবং আপনার ক্লাসে উদাহরণ ভেরিয়েবল হিসাবে নির্ধারিত করে। এইভাবে আপনি প্রতিটি মান ম্যানুয়ালি নির্ধারণ না করে একটি কাঠামোর মতো শ্রেণি তৈরি করতে পারেন।

আমার উদাহরণটিতে চেক করার কোনও ত্রুটি নেই তাই এটি অনুসরণ করা সহজ।

class MyStruct(type):
    def __call__(cls, *args, **kwargs):
        names = cls.__init__.func_code.co_varnames[1:]

        self = type.__call__(cls, *args, **kwargs)

        for name, value in zip(names, args):
            setattr(self , name, value)

        for name, value in kwargs.iteritems():
            setattr(self , name, value)
        return self 

এখানে এটি কার্যকর হয়।

>>> class MyClass(object):
    __metaclass__ = MyStruct
    def __init__(self, a, b, c):
        pass


>>> my_instance = MyClass(1, 2, 3)
>>> my_instance.a
1
>>> 

আমি এটি reddit এ পোস্ট করেছি এবং / u / ম্যাচু একটি সজ্জা সংস্করণ পোস্ট করেছেন যা পরিষ্কার er আপনি যদি মেটাক্লাস সংস্করণটি প্রসারিত না করতে চান তবে আমি এটি ব্যবহার করতে উত্সাহিত করব।

>>> def init_all_args(fn):
    @wraps(fn)
    def wrapped_init(self, *args, **kwargs):
        names = fn.func_code.co_varnames[1:]

        for name, value in zip(names, args):
            setattr(self, name, value)

        for name, value in kwargs.iteritems():
            setattr(self, name, value)

    return wrapped_init

>>> class Test(object):
    @init_all_args
    def __init__(self, a, b):
        pass


>>> a = Test(1, 2)
>>> a.a
1
>>> 

ড্যামনিট - আমি আজ আমার নিজের সাজসজ্জাটি লিখে দুটি ঘন্টা ব্যয় করেছি এবং আমি এটি পেয়েছি। যাইহোক, আমার পোস্ট করা কারণ এটি ডিফল্ট মানগুলি পরিচালনা করে যখন আপনার হয় না। stackoverflow.com/a/32448434/901641
ArtOfWarfare

+1 func_code উল্লেখ করার জন্য। সেই দিকে খোঁড়াখুঁড়ি শুরু করে এবং সেখানে প্রচুর আকর্ষণীয় জিনিস পেয়েছে found
wombatonfire

5

আমি একটি সাজসজ্জা লিখেছিলাম যা আপনি এটি তৈরির জন্য যে কোনও পদ্ধতিতে ব্যবহার করতে পারেন যাতে সমস্ত আর্গুমেন্ট বা কোনও ডিফল্টকে উদাহরণ হিসাবে বরাদ্দ করা হয়।

def argumentsToAttributes(method):
    argumentNames = method.func_code.co_varnames[1:]

    # Generate a dictionary of default values:
    defaultsDict = {}
    defaults = method.func_defaults if method.func_defaults else ()
    for i, default in enumerate(defaults, start = len(argumentNames) - len(defaults)):
        defaultsDict[argumentNames[i]] = default

    def newMethod(self, *args, **kwargs):
        # Use the positional arguments.
        for name, value in zip(argumentNames, args):
            setattr(self, name, value)

        # Add the key word arguments. If anything is missing, use the default.
        for name in argumentNames[len(args):]:
            setattr(self, name, kwargs.get(name, defaultsDict[name]))

        # Run whatever else the method needs to do.
        method(self, *args, **kwargs)

    return newMethod

একটি দ্রুত বিক্ষোভ। মনে রাখবেন যে আমি একটি অবস্থানগত আর্গুমেন্ট ব্যবহার করি a, এর জন্য ডিফল্ট মান bএবং একটি নামযুক্ত যুক্তি ব্যবহার করি c। আমি তখন সমস্ত 3 রেফারেন্সিং মুদ্রণ করি তা selfদেখানোর জন্য যে পদ্ধতিটি প্রবেশের আগে তাদের যথাযথভাবে অর্পণ করা হয়েছে।

class A(object):
    @argumentsToAttributes
    def __init__(self, a, b = 'Invisible', c = 'Hello'):
        print(self.a)
        print(self.b)
        print(self.c)

A('Why', c = 'Nothing')

মনে রাখবেন যে আমার ডেকোরেটরটি কোনও পদ্ধতি দিয়েই কাজ করা উচিত, কেবল নয় __init__


5

আমি এই উত্তরটি এখানে দেখছি না, তাই আমি এখনই পাইথনকে ঝুঁকিয়ে রেখেছি এবং এটি সন্ধান করেছি বলে আমি এটি যুক্ত করব figure পাইথন টিউটোরিয়াল (এই ক্ষেত্রে পাইথন 2) নিম্নলিখিত সহজ এবং কার্যকরী উদাহরণ দেয়:

class Employee:
    pass

john = Employee()  # Create an empty employee record

# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000

অর্থাৎ, একটি খালি শ্রেণি অবজেক্ট তৈরি করা হয়, তারপরে তাত্ক্ষণিকভাবে এবং ক্ষেত্রগুলি গতিশীলভাবে যুক্ত হয়।

এর উপরের অংশটি এটি সত্যই সহজ। খারাপ দিকটি এটি বিশেষত স্ব-ডকুমেন্টিং নয় (উদ্দেশ্যযুক্ত সদস্যদের "সংজ্ঞা" শ্রেণিতে কোথাও তালিকাভুক্ত করা হয়নি) এবং আনসেট ক্ষেত্রগুলি অ্যাক্সেস পেলে সমস্যা দেখা দিতে পারে। এই দুটি সমস্যার সমাধান করা যেতে পারে:

class Employee:
    def __init__ (self):
        self.name = None # or whatever
        self.dept = None
        self.salary = None

এখন এক নজরে আপনি কমপক্ষে প্রোগ্রামটি কোন ক্ষেত্রের প্রত্যাশা করবে তা দেখতে পারেন।

উভয় টাইপোর ঝুঁকিপূর্ণ, john.slarly = 1000সফল হবে। এখনও, এটি কাজ করে।


4

এখানে একটি সমাধান রয়েছে যা ডেটা ধরে রাখতে কোনও শ্রেণি (কখনও তাত্ক্ষণিক নয়) ব্যবহার করে। আমি পছন্দ করি যে এইভাবে খুব কম টাইপিং জড়িত এবং কোনও অতিরিক্ত প্যাকেজ ইত্যাদির প্রয়োজন নেই etc.

class myStruct:
    field1 = "one"
    field2 = "2"

প্রয়োজন অনুসারে আপনি আরও ক্ষেত্রগুলি যুক্ত করতে পারেন:

myStruct.field3 = 3

মানগুলি পেতে, ক্ষেত্রগুলি যথারীতি অ্যাক্সেস করা হয়:

>>> myStruct.field1
'one'

2

ব্যক্তিগতভাবে, আমি এই বৈকল্পিকটিও পছন্দ করি। এটি @ ডিএফ এর উত্তর প্রসারিত করে ।

class struct:
    def __init__(self, *sequential, **named):
        fields = dict(zip(sequential, [None]*len(sequential)), **named)
        self.__dict__.update(fields)
    def __repr__(self):
        return str(self.__dict__)

এটি সূচনা করার দুটি পদ্ধতি সমর্থন করে (এটি মিশ্রিত করা যেতে পারে):

# Struct with field1, field2, field3 that are initialized to None.
mystruct1 = struct("field1", "field2", "field3") 
# Struct with field1, field2, field3 that are initialized according to arguments.
mystruct2 = struct(field1=1, field2=2, field3=3)

এছাড়াও, এটি উত্তম প্রিন্ট করে:

print(mystruct2)
# Prints: {'field3': 3, 'field1': 1, 'field2': 2}

2

কোনও কাঠামোর নিম্নলিখিত সমাধানটি নেমটুপল বাস্তবায়ন এবং পূর্ববর্তী কয়েকটি উত্তর দ্বারা অনুপ্রাণিত হয়। তবে নামকরণের তুলনায় এটি পরিবর্তনযোগ্য, এর মানগুলিতে, তবে সি / স্টাইলের কাঠামোর মতো নাম / বৈশিষ্ট্যগুলিতে অপরিবর্তনীয়, যা একটি সাধারণ শ্রেণি বা আদেশ নয়।

_class_template = """\
class {typename}:
def __init__(self, *args, **kwargs):
    fields = {field_names!r}

    for x in fields:
        setattr(self, x, None)            

    for name, value in zip(fields, args):
        setattr(self, name, value)

    for name, value in kwargs.items():
        setattr(self, name, value)            

def __repr__(self):
    return str(vars(self))

def __setattr__(self, name, value):
    if name not in {field_names!r}:
        raise KeyError("invalid name: %s" % name)
    object.__setattr__(self, name, value)            
"""

def struct(typename, field_names):

    class_definition = _class_template.format(
        typename = typename,
        field_names = field_names)

    namespace = dict(__name__='struct_%s' % typename)
    exec(class_definition, namespace)
    result = namespace[typename]
    result._source = class_definition

    return result

ব্যবহার:

Person = struct('Person', ['firstname','lastname'])
generic = Person()
michael = Person('Michael')
jones = Person(lastname = 'Jones')


In [168]: michael.middlename = 'ben'
Traceback (most recent call last):

  File "<ipython-input-168-b31c393c0d67>", line 1, in <module>
michael.middlename = 'ben'

  File "<string>", line 19, in __setattr__

KeyError: 'invalid name: middlename'

2

এই উদ্দেশ্যে ঠিক একটি পাইথন প্যাকেজ রয়েছে। দেখতে cstruct2py

cstruct2pyসি কোড থেকে পাইথন ক্লাস তৈরি করতে এবং ডেটা প্যাক এবং আনপ্যাক করতে এগুলি ব্যবহার করার জন্য একটি খাঁটি পাইথন গ্রন্থাগার। লাইব্রেরি সি হেডারগুলি (স্ট্রাক্ট, ইউনিয়ন, এনাম এবং অ্যারে ঘোষণার) পার্স করতে পারে এবং এগুলিকে অজগরে অনুকরণ করতে পারে। উত্পন্ন পাইথোনিক ক্লাসগুলি ডেটা পার্স এবং প্যাক করতে পারে।

উদাহরণ স্বরূপ:

typedef struct {
  int x;
  int y;
} Point;

after generating pythonic class...
p = Point(x=0x1234, y=0x5678)
p.packed == "\x34\x12\x00\x00\x78\x56\x00\x00"

ব্যবহারবিধি

প্রথমে আমাদের পাইথোনিক স্ট্রাকগুলি তৈরি করতে হবে:

import cstruct2py
parser = cstruct2py.c2py.Parser()
parser.parse_file('examples/example.h')

এখন আমরা সি কোড থেকে সমস্ত নাম আমদানি করতে পারি:

parser.update_globals(globals())

আমরা সরাসরি এটিও করতে পারি:

A = parser.parse_string('struct A { int x; int y;};')

সি কোড থেকে প্রকার এবং সংজ্ঞা ব্যবহার করে

a = A()
a.x = 45
print a
buf = a.packed
b = A(buf)
print b
c = A('aaaa11112222', 2)
print c
print repr(c)

আউটপুটটি হবে:

{'x':0x2d, 'y':0x0}
{'x':0x2d, 'y':0x0}
{'x':0x31316161, 'y':0x32323131}
A('aa111122', x=0x31316161, y=0x32323131)

ক্লোন

ক্লোন cstruct2pyরান করার জন্য:

git clone https://github.com/st0ky/cstruct2py.git --recursive

0

আমি মনে করি পাইথন স্ট্রাকচার অভিধানটি এই প্রয়োজনের জন্য উপযুক্ত।

d = dict{}
d[field1] = field1
d[field2] = field2
d[field2] = field3

0

https://stackoverflow.com/a/32448434/159695 পাইথন 3 এ কাজ করে না।

https://stackoverflow.com/a/35993/159695 পাইথন 3 এ কাজ করে।

এবং আমি এটি ডিফল্ট মান যুক্ত করতে প্রসারিত করি।

class myStruct:
    def __init__(self, **kwds):
        self.x=0
        self.__dict__.update(kwds) # Must be last to accept assigned member variable.
    def __repr__(self):
        args = ['%s=%s' % (k, repr(v)) for (k,v) in vars(self).items()]
        return '%s(%s)' % ( self.__class__.__qualname__, ', '.join(args) )

a=myStruct()
b=myStruct(x=3,y='test')
c=myStruct(x='str')

>>> a
myStruct(x=0)
>>> b
myStruct(x=3, y='test')
>>> c
myStruct(x='str')

0

আপনার যদি @ ডাডাক্লাসের 3.7 না থাকে এবং পরিবর্তনের প্রয়োজন হয় তবে নিম্নলিখিত কোডটি আপনার পক্ষে কাজ করতে পারে। এটি বেশ স্ব-ডকুমেন্টিং এবং আইডিই বান্ধব (স্বতঃসম্পূর্ণ), দু'বার লেখা রোধ করে, সহজেই প্রসারণযোগ্য এবং সমস্ত দৃষ্টান্তের ভেরিয়েবলগুলি সম্পূর্ণ আরম্ভ করা হয় তা পরীক্ষা করা খুব সহজ:

class Params():
    def __init__(self):
        self.var1 : int = None
        self.var2 : str = None

    def are_all_defined(self):
        for key, value in self.__dict__.items():
            assert (value is not None), "instance variable {} is still None".format(key)
        return True


params = Params()
params.var1 = 2
params.var2 = 'hello'
assert(params.are_all_defined)

0

এখানে একটি দ্রুত এবং নোংরা কৌশল:

>>> ms = Warning()
>>> ms.foo = 123
>>> ms.bar = 'akafrit'

এটি কিভাবে কাজ করে? এটি কেবল বিল্টিন ক্লাসটি পুনরায় ব্যবহার করে Warning(উত্পন্ন Exception) এবং এটি যেমন আপনি নিজেরাই নির্ধারিত বর্গ হিসাবে ব্যবহার করেন।

ভাল পয়েন্টগুলি হ'ল আপনাকে প্রথমে কোনও কিছু আমদানি বা সংজ্ঞায়িত করার দরকার নেই, "সতর্কতা" একটি ছোট নাম এবং এটিও স্পষ্ট করে দেয় যে আপনি এমন নোংরামি করছেন যা আপনার একটি ছোট স্ক্রিপ্টের চেয়ে অন্য কোথাও ব্যবহার করা উচিত নয়।

যাইহোক, আমি এর মতো আরও সাধারণ কিছু সন্ধান করার চেষ্টা করেছি ms = object()কিন্তু পারেনি (এটি শেষ উদাহরণটি কাজ করছে না)। আপনার যদি একটি থাকে তবে আমি আগ্রহী।


0

এটি করার সবচেয়ে ভাল উপায়টি হ'ল এই পোস্টে বর্ণিত কাস্টম অভিধানের ক্লাসটি ব্যবহার করা: https://stackoverflow.com/a/14620633/8484485

আইপাইথন স্বতঃপূরণ সমর্থন যদি প্রয়োজন হয়, তবে সহজেই dir () ফাংশনটি এভাবে সংজ্ঞায়িত করুন :

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self
    def __dir__(self):
        return self.keys()

তারপরে আপনি নিজের সিউডো স্ট্রাক্টটি এর মতো সংজ্ঞায়িত করুন: (এটি একটি নেস্টেড)

my_struct=AttrDict ({
    'com1':AttrDict ({
        'inst':[0x05],
        'numbytes':2,
        'canpayload':False,
        'payload':None
    })
})

তারপরে আপনি আমার_স্ট্রাক্টের মধ্যে এই জাতীয় মানগুলি অ্যাক্সেস করতে পারবেন:

print(my_struct.com1.inst)

=>[5]


0

নামডটুপল আরামদায়ক। তবে সেখানে কেউ পারফরম্যান্স এবং স্টোরেজ ভাগ করে না।

from typing import NamedTuple
import guppy  # pip install guppy
import timeit


class User:
    def __init__(self, name: str, uid: int):
        self.name = name
        self.uid = uid


class UserSlot:
    __slots__ = ('name', 'uid')

    def __init__(self, name: str, uid: int):
        self.name = name
        self.uid = uid


class UserTuple(NamedTuple):
    # __slots__ = ()  # AttributeError: Cannot overwrite NamedTuple attribute __slots__
    name: str
    uid: int


def get_fn(obj, attr_name: str):
    def get():
        getattr(obj, attr_name)
    return get
if 'memory test':
    obj = [User('Carson', 1) for _ in range(1000000)]      # Cumulative: 189138883
    obj_slot = [UserSlot('Carson', 1) for _ in range(1000000)]          # 77718299  <-- winner
    obj_namedtuple = [UserTuple('Carson', 1) for _ in range(1000000)]   # 85718297
    print(guppy.hpy().heap())  # Run this function individually. 
    """
    Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0 1000000    24 112000000 34 112000000  34 dict of __main__.User
     1 1000000    24 64000000  19 176000000  53 __main__.UserTuple
     2 1000000    24 56000000  17 232000000  70 __main__.User
     3 1000000    24 56000000  17 288000000  87 __main__.UserSlot
     ...
    """

if 'performance test':
    obj = User('Carson', 1)
    obj_slot = UserSlot('Carson', 1)
    obj_tuple = UserTuple('Carson', 1)

    time_normal = min(timeit.repeat(get_fn(obj, 'name'), repeat=20))
    print(time_normal)  # 0.12550550000000005

    time_slot = min(timeit.repeat(get_fn(obj_slot, 'name'), repeat=20))
    print(time_slot)  # 0.1368690000000008

    time_tuple = min(timeit.repeat(get_fn(obj_tuple, 'name'), repeat=20))
    print(time_tuple)  # 0.16006120000000124

    print(time_tuple/time_slot)  # 1.1694481584580898  # The slot is almost 17% faster than NamedTuple on Windows. (Python 3.7.7)

যদি আপনি __dict__ব্যবহার না করে থাকেন তবে দয়া করে __slots__(উচ্চতর পারফরম্যান্স এবং সঞ্চয়স্থান) এবং NamedTuple(পড়ার এবং ব্যবহারের জন্য পরিষ্কার) এর মধ্যে চয়ন করুন

আরও তথ্য পেতে আপনি এই লিঙ্কটি ( স্লটের ব্যবহার ) পর্যালোচনা করতে পারেন __slots__

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.