पायथन में सी-जैसी संरचनाएं


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
@levesque लिखने की त्रुटियों के बिना फिर से कारक, करने के लिए कठिन कठिन एक नज़र में पढ़ने के लिए कोड स्कीम जबकि, की तुलना मेंMyStruct = namedtuple("MyStruct", "field1 field2 field3")
सैम boosalis

1
pandas.Series(a=42).aयदि आपका डेटा-वैज्ञानिक ...
मार्क होर्वाथ

जवाबों:


341

एक नामित टपल का उपयोग करें , जिसे पायथन 2.6 में मानक पुस्तकालय में संग्रह मॉड्यूल में जोड़ा गया था । यदि आप पायथन 2.4 का समर्थन करने की आवश्यकता है, तो रेमंड हेटिंगर की टुपल नुस्खा का उपयोग करना भी संभव है ।

यह आपके मूल उदाहरण के लिए अच्छा है, लेकिन आपके द्वारा बाद में चलाए जा सकने वाले किनारे मामलों का एक समूह भी शामिल करता है। ऊपर आपके टुकड़े के रूप में लिखा जाएगा:

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

नए बनाए गए प्रकार का उपयोग इस तरह किया जा सकता है:

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

आप नामित तर्कों का भी उपयोग कर सकते हैं:

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

164
... लेकिन नाम्तूपल अपरिवर्तनीय है। ओपी में उदाहरण परस्पर है।
मझौली

28
@Mhowison - मेरे मामले में, यह सिर्फ एक प्लस है।
ArtOfWarfare

3
अच्छा समाधान। आप इन tuples के एक सरणी के माध्यम से कैसे लूप करेंगे? मुझे लगता है कि 1-3 क्षेत्रों में टपल वस्तुओं के समान नाम होंगे।
माइकल स्मिथ

2
नेमटुपल में कम से कम चार तर्क हो सकते हैं ताकि हम इसी नामपट्ट के साथ अधिक डेटा सदस्यों के साथ संरचना का नक्शा कैसे बना सकें
कपिल

3
@ कपिल - नामांकित करने के लिए दूसरा तर्क सदस्यों के नामों की एक सूची होना चाहिए। वह सूची कोई भी हो सकती है।
आर्टऑफवर्फ

226

अपडेट : डेटा कक्षाएं

पायथन 3.7 में डेटा क्लासेस की शुरुआत के साथ हम बहुत करीब आ गए।

निम्न उदाहरण नीचे दिए गए NamedTuple उदाहरण के समान है , लेकिन परिणामी वस्तु परिवर्तनशील है और यह डिफ़ॉल्ट मानों के लिए अनुमति देता है।

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)

यदि आप अधिक विशिष्ट प्रकार के एनोटेशन का उपयोग करना चाहते हैं तो यह नए टाइपिंग मॉड्यूल के साथ अच्छी तरह से निभाता है ।

मैं इसके लिए सख्त प्रतीक्षा कर रहा हूं! यदि आप मुझसे पूछते हैं, डेटा क्लासेस और नया नामांकित घोषणा, टाइपिंग मॉड्यूल के साथ संयुक्त एक Godsend हैं!

बेहतर नामांकित घोषणा

पायथन 3.6 के बाद से यह काफी सरल और सुंदर (आईएमएचओ) बन गया, जब तक आप अपरिवर्तनीयता के साथ रह सकते हैं ।

NamedTuples घोषित करने का एक नया तरीका पेश किया गया था, जो टाइप एनोटेशन के लिए भी अनुमति देता है :

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मॉड्यूल अजगर 3.7 में नया है लेकिन आप कर सकते हैं pip install dataclasses। यह पाइथन 3.6 पर बैकपोर्ट है। pypi.org/project/dataclasses/#description
Lavande

बेहतर NamedTuple घोषणा के लिए +1। पुराना तरीका वास्तव में पढ़ने के लिए अप्रिय था अगर आपके पास कई चर थे ...
gebbissimo

@ लैवंडे मुझे पता है कि 3.6 और 3.7 के बीच क्या परिवर्तन हुए जो आपको एक मामूली संस्करण को वापस करना है ...?
पर्पल आइस

1
@PurpleIce यह PEP 557 का कार्यान्वयन था, डेटा क्लासेस @dataclassयहाँ विवरण हैं: pypi.org/project/dataclasses/#description
Lavande

96

आप बहुत सी चीजों के लिए टपल का उपयोग कर सकते हैं जहां आप C में एक संरचना का उपयोग करेंगे (उदाहरण के लिए x, y निर्देशांक या RGB रंग जैसा कुछ)।

सब कुछ के लिए आप शब्दकोश, या की तरह एक उपयोगिता वर्ग का उपयोग कर सकते यह एक :

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

मुझे लगता है कि "निश्चित" चर्चा यहाँ है , पायथन कुकबुक के प्रकाशित संस्करण में।


5
क्या एक खाली वर्ग सिर्फ इतना ही करेगा?
कर्ट लियू

44
ध्यान दें कि यदि आप अजगर के लिए नए हैं: ट्यूपल्स केवल सी
स्ट्रक्चर्स के

2
@ कर्टलियू नहीं, यह शायद कहेगाTypeError: this constructor takes no arguments
एवगेनी

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
यह उतना ही करीब है जितना कि यह बिना किसी तरीके के एक संरचना - लघु 'वर्ग' के लिए जाता है, डिफ़ॉल्ट मानों के साथ 'फ़ील्ड' (वर्ग गुण, मुझे पता है)। जब तक यह एक परिवर्तनशील प्रकार (तानाशाही, सूची) नहीं है, तब तक आप ठीक हैं। बेशक, आप पीईपी-8 या 'दोस्ताना' PyCharm के "वर्ग नहीं है की तरह आईडीई चेकों के खिलाफ हिट कर सकते हैं init विधि"।
टॉमस गैंडर

4
मैंने चैनिंग मूर द्वारा वर्णित साइड इफेक्ट का प्रयोग किया। selfयदि आप मुझसे पूछें तो कुछ कीवर्ड्स और कंस्ट्रक्टर लाइन की अर्थव्यवस्था के लायक नहीं हैं । मुझे खुशी होगी कि अगर जोस गलती से उदाहरणों को साझा करने के उदाहरणों के बारे में चेतावनी संदेश जोड़ने के लिए अपने जवाब को संपादित कर सकता है।
स्टीफन सी।

@ChanningMoore: मैंने आपके द्वारा बताए गए मुद्दे को फिर से बनाने की कोशिश की, लेकिन असफल रहा। क्या आप एक न्यूनतम काम करने का उदाहरण पेश कर सकते हैं, जहां मुद्दा पॉप हो जाता है?
जिबिसिमो २ '

67

एक शब्दकोश के बारे में कैसे?

कुछ इस तरह:

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

फिर आप इसका उपयोग मूल्यों में हेरफेर करने के लिए कर सकते हैं:

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

और मानों को तार नहीं होना चाहिए। वे बहुत किसी भी अन्य वस्तु हो सकती है।


34
यह मेरा दृष्टिकोण भी रहा है, लेकिन मुझे ऐसा लगता है कि यह वास्तव में खतरनाक है क्योंकि एक शब्दकोश एक कुंजी के लिए कुछ भी स्वीकार कर सकता है। जब मैं myStruct ["फ़ील्ड"] सेट करने का मतलब है, तो मैं अपने MyStruct ["ffield"] को सेट करने में कोई त्रुटि नहीं होगी। जब मैं myStruct ["फ़ील्ड"] का उपयोग कर रहा हूं या फिर से उपयोग कर रहा हूं तो समस्या (या नहीं) स्पष्ट हो सकती है। मुझे पाब्लो का दृष्टिकोण पसंद है।
मोबाबो

पाब्लो के साथ भी यही मुद्दा मौजूद है। निम्न कोड को उसके pt3.w = 1 print pt3.w साथ जोड़ने का प्रयास करें: एक भाषा में डिकट्स के साथ, उनका उपयोग करना बेहतर है, विशेष रूप से ऑब्जेक्ट्स को क्रमबद्ध किया जा रहा है, क्योंकि आप स्वचालित रूप से उन्हें और अन्य क्रमांकन पुस्तकालयों को बचाने के लिए आयात जसन का उपयोग कर सकते हैं जब तक कि आपके पास अजीब न हो। अपने हुक के अंदर सामान। डायट डेटा और लॉजिक को अलग रखने का उपाय है और उन लोगों के लिए स्ट्रक्चर्स से बेहतर है, जो कस्टम क्रमबद्ध और गैर-व्यवस्थित फ़ंक्शंस लिखना नहीं चाहते हैं और अचार जैसे गैर-पोर्टेबल सीरियलाइज़र का उपयोग नहीं करना चाहते हैं।
पोइकिलोस

27

dF: यह बहुत अच्छा है ... मुझे नहीं पता था कि मैं तानाशाही का उपयोग करके एक वर्ग में खेतों तक पहुंच सकता हूं।

मार्क: जिन स्थितियों में मैं चाहता हूं कि यह ठीक है जब मैं एक टपल चाहता हूं, लेकिन एक शब्दकोश के रूप में "भारी" के रूप में कुछ भी नहीं।

आप एक शब्दकोश का उपयोग करते हुए एक वर्ग के क्षेत्रों तक पहुंच सकते हैं क्योंकि एक वर्ग के क्षेत्र, इसकी विधियां और इसके सभी गुण आंतरिक रूप से dicts (कम से कम CPython) का उपयोग करके संग्रहीत किए जाते हैं।

... जो हमें आपकी दूसरी टिप्पणी की ओर ले जाता है। यह मानना ​​कि पायथन डाइकस "भारी" हैं, एक बहुत ही गैर-पाइथोनिस्टिक अवधारणा है। और इस तरह की टिप्पणियों को पढ़कर मेरे पाइथन ज़ेन की मौत हो जाती है। यह अच्छा नहीं है।

आप देखें, जब आप एक वर्ग की घोषणा करते हैं तो आप वास्तव में एक शब्दकोश के चारों ओर एक बहुत ही जटिल आवरण बना रहे होते हैं - इसलिए, यदि कुछ भी, आप एक साधारण शब्दकोश का उपयोग करके अधिक उपरि जोड़ रहे हैं। एक उपरि जो, वैसे, किसी भी मामले में अर्थहीन है। यदि आप प्रदर्शन महत्वपूर्ण अनुप्रयोगों पर काम कर रहे हैं, तो C या कुछ का उपयोग करें।


5
# 1, साइथन! = सीपीथॉन। मुझे लगता है कि आप सीपीथॉन के बारे में बात कर रहे थे, सी में लिखा अजगर का कार्यान्वयन, साइथॉन नहीं, सी कोड में पायथन कोड को पार करने की परियोजना। मैंने उसे ठीक करने के लिए आपके उत्तर को संपादित किया। # 2, मुझे लगता है कि जब उन्होंने कहा कि डायक्स भारी हैं, तो वे वाक्य रचना का जिक्र कर रहे थे। self['member']की तुलना में 3 वर्ण अधिक लंबा है self.member, और वे वर्ण सभी अपेक्षाकृत अन-कलाई के अनुकूल हैं।
आर्टऑफवर्फ

19

आप मानक लाइब्रेरी में उपलब्ध C संरचना को उप-वर्ग कर सकते हैं। 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

निश्चित रूप से स्लॉट्स के लिए दस्तावेज़ीकरण की जांच करें, लेकिन स्लॉट्स की एक त्वरित व्याख्या यह है कि यह कहने का अजगर का तरीका है: "यदि आप इन विशेषताओं और केवल इन विशेषताओं को कक्षा में लॉक कर सकते हैं, तो आप ऐसा करते हैं कि आप कक्षा में एक बार कोई नई विशेषता नहीं जोड़ेंगे त्वरित है (हाँ आप एक वर्ग उदाहरण में नई विशेषताएँ जोड़ सकते हैं, नीचे उदाहरण देखें) तो मैं बड़े मेमोरी आवंटन के साथ दूर करूँगा जो एक वर्ग उदाहरण में नई विशेषताओं को जोड़ने की अनुमति देता है और मुझे केवल इन सुव्यवस्थित विशेषताओं के लिए उपयोग की आवश्यकता है "।

श्रेणी उदाहरण में विशेषताएँ जोड़ने का उदाहरण (इस प्रकार स्लॉट का उपयोग नहीं):

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)।
जोनाथन कोमार

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'])

उन समय के लिए पूरी तरह से आसान है जब आपको "डेटा बैग की आवश्यकता होती है जो एक वर्ग नहीं है", और जब नामपट्ट के लिए समझ से बाहर हैं ...


मैं pandas.Series (एक = 42) ;-) का उपयोग
मार्क होर्वाथ

8

आप निम्नलिखित तरीके से अजगर में सी-स्टाइल संरचना का उपयोग करते हैं।

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

यदि आप केवल निर्माण की वस्तु का उपयोग करना चाहते हैं

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)

यदि आप क्रिप्ट की वस्तुओं की एक सरणी बनाना चाहते हैं

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)

नोट: 'cstruct' नाम के बजाय, कृपया var_i, var_f, var_str के बजाय अपने संरचना नाम का उपयोग करें, कृपया अपनी संरचना के सदस्य चर को परिभाषित करें।


3
क्या यह स्टैकओवरफ्लो . com/a/3761729/1877426 में मौजूद किसी से अलग है ?
लैगवेजे

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)

आरंभ:

>>> 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 / matchu ने एक डेकोरेटर संस्करण पोस्ट किया जो क्लीनर है। जब तक आप मेटाक्लस संस्करण का विस्तार नहीं करना चाहते, मैं आपको इसका उपयोग करने के लिए प्रोत्साहित करता हूँ।

>>> 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
आर्टऑफवर्फ

Func_code का उल्लेख करने के लिए +1। उस दिशा में खुदाई शुरू की और वहाँ बहुत सारी दिलचस्प चीजें मिलीं।
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

मुझे यहाँ यह उत्तर दिखाई नहीं दे रहा है, इसलिए मुझे लगता है कि मैं इसे अभी जोड़ दूंगा क्योंकि मैं अभी पायथन का झुकाव कर रहा हूँ और मैंने इसे खोज लिया है। अजगर ट्यूटोरियल (इस मामले में अजगर 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

यहां एक समाधान है जो डेटा धारण करने के लिए एक वर्ग (कभी भी त्वरित) का उपयोग नहीं करता है। मुझे पसंद है कि इस तरह से बहुत कम टाइपिंग शामिल है और किसी अतिरिक्त पैकेज आदि की आवश्यकता नहीं है

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

आप आवश्यकतानुसार बाद में और अधिक फ़ील्ड जोड़ सकते हैं:

myStruct.field3 = 3

मान प्राप्त करने के लिए, फ़ील्ड हमेशा की तरह एक्सेस किए जाते हैं:

>>> myStruct.field1
'one'

2

निजी तौर पर, मुझे यह वैरिएंट भी पसंद है। यह @ dF के उत्तर का विस्तार करता है ।

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')

अब हम C कोड से सभी नाम आयात कर सकते हैं:

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/159695Pyston3 में काम करता है।

और मैं इसे डिफ़ॉल्ट मान जोड़ने के लिए बढ़ाता हूं।

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

यदि आपके पास @dataclass के लिए 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

यदि iPython स्वतः पूर्णता समर्थन की आवश्यकता है, तो बस इस तरह 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
    })
})

आप इस तरह my_struct के अंदर मानों तक पहुँच सकते हैं:

print(my_struct.com1.inst)

=>[5]


0

NamedTuple आरामदायक है। लेकिन प्रदर्शन और भंडारण को कोई साझा नहीं करता है।

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__हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.