एक विशेषता की तरह प्रमुख कुंजियों तक पहुँचना?


303

मुझे obj.fooइसके बजाय तानाशाही कुंजियों का उपयोग करना अधिक सुविधाजनक लगता है obj['foo'], इसलिए मैंने यह स्निपेट लिखा:

class AttributeDict(dict):
    def __getattr__(self, attr):
        return self[attr]
    def __setattr__(self, attr, value):
        self[attr] = value

हालाँकि, मुझे लगता है कि कुछ कारण होना चाहिए कि पायथन बॉक्स से बाहर इस कार्यक्षमता प्रदान नहीं करता है। इस तरीके से तानाशाही चाबियों तक पहुँचने के क्या-क्या नुकसान और नुकसान होंगे?


16
यदि आप हर जगह एक निश्चित आकार के सीमित सेट से हार्डकोड कीज़ एक्सेस कर रहे हैं, तो आप उन वस्तुओं को बनाने से बेहतर हो सकते हैं जो इन्हें रखती हैं। collections.namedtupleइसके लिए बहुत उपयोगी है।

6
stackoverflow.com/questions/3031219/… के पास एक समान समाधान है, लेकिन एक कदम आगे चला जाता है
केफ्लाइविच

1
इसके लिए github.com/bcj/AttrDict पर एक मॉड्यूल मिला । मुझे नहीं पता कि यह यहाँ और संबंधित प्रश्नों में समाधान की तुलना कैसे करता है।
मैट विल्की

मैंने भी इसी तरह के हैक्स का इस्तेमाल किया, अब मैं इस्तेमाल करता हूंeasydict.EasyDict
23:52

''। के साथ शब्दकोश सदस्यों तक पहुँचने के और तरीके। : stackoverflow.com/questions/2352181/…
पीला ब्लू डॉट

जवाबों:


304

इसका सबसे अच्छा तरीका है:

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

कुछ पेशेवरों:

  • यह वास्तव में काम करता है!
  • कोई शब्दकोश वर्ग विधियाँ छायांकित नहीं हैं (उदा .keys()। बस ठीक काम करें। जब तक - निश्चित रूप से - आप उन्हें कुछ मूल्य प्रदान करते हैं, नीचे देखें)
  • विशेषताएँ और आइटम हमेशा सिंक में होते हैं
  • गैर-मौजूद कुंजी को एक विशेषता के रूप में एक्सेस करने की कोशिश करने के AttributeErrorबजाय सही ढंग से उठता हैKeyError

विपक्ष:

  • यदि इनकमिंग डेटा द्वारा अधिलेखित हो जाते हैं तो जैसे तरीके ठीक नहीं.keys() होंगे
  • पायथन में स्मृति रिसाव का कारण बनता है <2.7.4 / Python3 <3.2.3
  • Pylint केले के साथ चला जाता है E1123(unexpected-keyword-arg)औरE1103(maybe-no-member)
  • बिन बुलाए के लिए यह शुद्ध जादू की तरह लगता है।

यह कैसे काम करता है, इस पर एक संक्षिप्त विवरण

  • सभी अजगर ऑब्जेक्ट आंतरिक रूप से एक शब्दकोश में अपनी विशेषताओं को संग्रहीत करते हैं जिसे नाम दिया गया है __dict__
  • इस बात की कोई आवश्यकता नहीं है कि आंतरिक शब्दकोश __dict__को "बस एक सादा तानाशाही" होना चाहिए, इसलिए हम dict()आंतरिक शब्दकोश के किसी भी उपवर्ग को निर्दिष्ट कर सकते हैं ।
  • हमारे मामले में हम बस AttrDict()उदाहरण देते हैं कि हम तात्कालिक हैं (जैसा कि हम हैं __init__)।
  • फोन करके super()की __init__()विधि हम यकीन है कि यह (पहले से ही) वास्तव में एक शब्दकोश की तरह, बर्ताव करता है कि समारोह सभी कॉल के बाद से किए गए शब्दकोश इन्स्टेन्शियशन कोड।

पायथन बॉक्स के बाहर इस कार्यक्षमता प्रदान नहीं करता है एक कारण

जैसा कि "विपक्ष" सूची में उल्लेख किया गया है, यह संग्रहित कुंजियों के नामस्थान को जोड़ती है (जो कि मनमाने ढंग से और / या सौंपे गए डेटा से आ सकता है!) बिलिन की तानाशाही विधियों के नामस्थान के साथ। उदाहरण के लिए:

d = AttrDict()
d.update({'items':["jacket", "necktie", "trousers"]})
for k, v in d.items():    # TypeError: 'list' object is not callable
    print "Never reached!"

1
क्या आपको लगता है कि स्मृति रिसाव एक साधारण वस्तु के साथ होता है जैसे: >>> वर्ग MyD (वस्तु): ... init __ (स्वयं, d): ... स्व .__ तानाशाह = d
Rafe

2.7 में भी रिसाव का कारण बनता है
पी।

1
वह <= 2.7.3 बनाओ, जैसा कि मैं उपयोग कर रहा हूं।
पी।

1
2.7.4 रिलीज नोट में वे इसका उल्लेख करते हैं (पहले नहीं)।
रॉबर्ट सेमर

1
@viveksinghggits सिर्फ इसलिए क्योंकि आप चीजों को एक्सेस कर रहे हैं ., आप भाषा के नियमों को तोड़ नहीं सकते हैं :) और मैं AttrDictस्पेस-युक्त फ़ील्ड्स को स्वचालित रूप से कुछ अलग में बदलना नहीं चाहूंगा ।
यूरीक

125

यदि आप सरणी संकेतन का उपयोग करते हैं, तो आपके पास कुंजी के भाग के रूप में सभी कानूनी स्ट्रिंग वर्ण हो सकते हैं। उदाहरण के लिए,obj['!#$%^&*()_']


1
@ इज़कट हाँ। एसई के बारे में मजेदार बात यह है कि आमतौर पर एक 'शीर्ष प्रश्न' होता है। शीर्षक, और एक 'निचला सवाल', शायद इसलिए कि एसई "शीर्षक यह सब कहता है" सुनना पसंद नहीं करता है; 'केवेट' यहाँ सबसे नीचे है।
n611x007

2
ऐसा नहीं है कि जावास्क्रिप्ट प्रोग्रामिंग भाषा का एक विशेष रूप से अच्छा उदाहरण है, लेकिन जेएस में ऑब्जेक्ट्स विशेषता अभिगम और सरणी संकेतन दोनों का समर्थन करते हैं, जो सामान्य मामले की सुविधा और प्रतीकों के लिए एक सामान्य वापसी की अनुमति देता है जो कानूनी विशेषता नाम नहीं हैं।
एंड्रे कैरन

@ इज़कट यह सवाल का जवाब कैसे देता है। यह उत्तर केवल यह कहता है कि कुंजियों का कोई भी नाम हो सकता है।
मेला

4
@Melab प्रश्न What would be the caveats and pitfalls of accessing dict keys in this manner?(विशेषताओं के अनुसार) है, और इसका उत्तर यह है कि यहाँ दिखाए गए अधिकांश वर्ण उपयोगी नहीं होंगे।
इज़्काता

83

से यह अन्य तो सवाल यह एक महान कार्यान्वयन उदाहरण है कि अपने मौजूदा कोड को सरल नहीं है। कैसा रहेगा:

class AttributeDict(dict): 
    __getattr__ = dict.__getitem__
    __setattr__ = dict.__setitem__

बहुत अधिक संक्षिप्त और भविष्य में आपके __getattr__और __setattr__कार्यों में हो रही अतिरिक्त कमी के लिए कोई जगह नहीं छोड़ता है ।


क्या आप इस पद्धति का उपयोग करके AttributeDict.update या AttributeDict.get को कॉल कर पाएंगे?
डोर

13
आप को ध्यान में रखना है कि यदि आप रनटाइम पर नई विशेषताओं को जोड़ने वे dict खुद के लिए, लेकिन करने के लिए नहीं जोड़ा जाता है dict विशेषता। जैसे d = AttributeDict(foo=1)d.bar = 1बार विशेषता को तानाशाह विशेषता के अंदर संग्रहीत किया जाता है, लेकिन स्वयं में नहीं। मुद्रण dकेवल फू आइटम दिखाता है।
P3trus

7
+1 क्योंकि यह पूरी तरह से काम करता है जहाँ तक मैं बता सकता हूँ। @GringoSuave, @Izkata, @ P3trus मैं किसी से भी यह दावा करने में विफल रहने का अनुरोध करता हूं कि ऐसा उदाहरण नहीं है जो मेरे लिए काम नहीं करता है d = AttributeDict(foo=1);d.bar = 1;print d>> {'foo': 1, 'bar': 1}मेरे लिए काम करता है!
डेव अब्राहम

4
@DaveAbrahams पूरा प्रश्न पढ़ें और Hery, Ryan, और TheCommunistDuck के उत्तर देखें। यह के बारे में पूछ नहीं कर रहा है कि कैसे यह करने के लिए, लेकिन के बारे में समस्या पैदा हो सकता
इज़काता

6
आपको ऐसी __getattr__विधि प्रदान करनी चाहिए AttributeErrorजो दी गई विशेषता के मौजूद न होने पर उठाती है, अन्यथा getattr(obj, attr, default_value)काम नहीं करने जैसी चीजें (यानी default_valueअगर attrवह मौजूद नहीं है तो वापस नहीं आती obj)
jcdude

83

जिसमें मैंने उस प्रश्न का उत्तर दिया जो पूछा गया था

अजगर बॉक्स से बाहर की पेशकश क्यों नहीं करता है?

मुझे संदेह है कि यह पायथन के ज़ेन के साथ करना है : "एक होना चाहिए - और अधिमानतः ऐसा करने के लिए केवल एक - स्पष्ट तरीका।" यह शब्दकोशों से मूल्यों तक पहुंचने के दो स्पष्ट तरीके पैदा करेगा: obj['key']और obj.key

कैविट्स और नुकसान

इनमें कोड में स्पष्टता और भ्रम की संभावित कमी शामिल है। यानी, निम्नलिखित किसी और को भ्रमित कर सकता है जो बाद की तारीख में आपके कोड को बनाए रखने के लिए जा रहा है, या यहां तक ​​कि आपके लिए, यदि आप थोड़ी देर के लिए इसमें वापस नहीं जा रहे हैं। ज़ेन से फिर से : "पठनीयता मायने रखती है!"

>>> KEY = 'spam'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1

अगर dतत्काल किया जाता है या KEY परिभाषित किया जाता है या d[KEY] जहां d.spamइस्तेमाल किया जा रहा है, उससे बहुत दूर सौंपा गया है, तो यह आसानी से भ्रम में डाल सकता है कि क्या किया जा रहा है, क्योंकि यह आमतौर पर इस्तेमाल किया जाने वाला मुहावरा नहीं है। मुझे पता है कि इसमें मुझे भ्रमित करने की क्षमता होगी।

Additonally, यदि आप KEYनिम्न के मान को बदलते हैं (लेकिन बदलने से चूक जाते हैं d.spam), तो अब आपको मिलेंगे:

>>> KEY = 'foo'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
AttributeError: 'C' object has no attribute 'spam'

IMO, प्रयास के लायक नहीं है।

अन्य सामान

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

>>> d = {(2, 3): True,}
>>> assert d[(2, 3)] is True
>>> 

कानूनी है, लेकिन

>>> C = type('C', (object,), {(2, 3): True})
>>> d = C()
>>> assert d.(2, 3) is True
  File "<stdin>", line 1
  d.(2, 3)
    ^
SyntaxError: invalid syntax
>>> getattr(d, (2, 3))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: getattr(): attribute name must be string
>>> 

नहीं है। यह आपको अपने शब्दकोश कुंजियों के लिए प्रिंट करने योग्य वर्णों या अन्य धोने योग्य वस्तुओं की पूरी श्रृंखला तक पहुंच प्रदान करता है, जो आपके पास ऑब्जेक्ट विशेषता को एक्सेस करते समय नहीं होता है। यह कैश्ड ऑब्जेक्ट मेटाक्लास के रूप में इस तरह के जादू को संभव बनाता है, जैसे कि पायथन कुकबुक (च। 9) से नुस्खा ।

जिसमें मैं संपादकीय लिखता हूं

मैं spam.eggsओवर के सौंदर्यशास्त्र को पसंद करता spam['eggs']हूं (मुझे लगता है कि यह साफ दिखता है), और मैं वास्तव में इस कार्यक्षमता को तरसना शुरू कर दिया जब मैं मिला namedtuple। लेकिन निम्न करने में सक्षम होने की सुविधा इसे ट्रम्प करती है।

>>> KEYS = 'spam eggs ham'
>>> VALS = [1, 2, 3]
>>> d = {k: v for k, v in zip(KEYS.split(' '), VALS)}
>>> assert d == {'spam': 1, 'eggs': 2, 'ham': 3}
>>>

यह एक सरल उदाहरण है, लेकिन मैं अक्सर अपने आप को अलग-अलग स्थितियों में dicts का उपयोग करने की तुलना में पाता हूं obj.key, जबकि मैं नोटेशन का उपयोग करता हूं (यानी, जब मुझे एक्सएमएल फ़ाइल से प्रीफ़्स पढ़ने की आवश्यकता होती है)। अन्य मामलों में, जहां मैं एक गतिशील वर्ग को तुरंत आकर्षित करने के लिए लुभाता हूं और सौंदर्य संबंधी कारणों से कुछ विशेषताओं को थप्पड़ मारता हूं, मैं पठनीयता बढ़ाने के लिए निरंतरता के लिए एक तानाशाही का उपयोग करना जारी रखता हूं।

मुझे यकीन है कि ओपी ने लंबे समय से अपनी संतुष्टि के लिए इसे हल किया है, लेकिन अगर वह अभी भी इस कार्यक्षमता को चाहता है, तो मेरा सुझाव है कि वह पीपीआई से एक पैकेज डाउनलोड करता है जो इसे प्रदान करता है:

  • गुच्छा वह है जिससे मैं अधिक परिचित हूं। उपवर्गdict, तो आपके पास वह सब कार्यक्षमता है।
  • AttrDict भी लग रहा है यह भी बहुत अच्छा है, लेकिन मैं इसे से परिचित के रूप में नहीं कर रहा हूँ और अधिक से अधिक विवरण के रूप में में स्रोत के माध्यम से देखा नहीं किया है के रूप में मेरे पास है जैसे गुच्छा
  • व्यसनी सक्रिय रूप से बनाए रखा है और attr की तरह पहुँच प्रदान करता है और अधिक।
  • के रूप में Rotareti द्वारा टिप्पणी में बताया गया है, गुच्छा पदावनत किया गया है, लेकिन वहाँ एक सक्रिय बुलाया कांटा है मंच

हालांकि, उनके कोड की पठनीयता में सुधार करने के लिए मैं दृढ़ता से सलाह देता हूं कि वह अपनी संकेतन शैलियों को मिलाएं। यदि वह इस संकेतन को पसंद करता है, तो उसे बस एक गतिशील वस्तु को तुरंत भेजना चाहिए, उसमें अपनी वांछित विशेषताएं जोड़ना चाहिए, और इसे एक दिन कहना चाहिए:

>>> C = type('C', (object,), {})
>>> d = C()
>>> d.spam = 1
>>> d.eggs = 2
>>> d.ham = 3
>>> assert d.__dict__ == {'spam': 1, 'eggs': 2, 'ham': 3}


जिसमें मैं अद्यतन करता हूं, टिप्पणियों में एक अनुवर्ती प्रश्न का उत्तर देने के लिए

टिप्पणियों में (नीचे), एल्मो पूछता है:

क्या होगा यदि आप एक गहराई तक जाना चाहते हैं? (टाइप करने का जिक्र ... ())

हालांकि मैंने इस उपयोग के मामले का उपयोग कभी नहीं किया (फिर, मैं नेस्टेड का उपयोग सुसंगतता के लिए करता हूं dict), निम्न कोड काम करता है:

>>> C = type('C', (object,), {})
>>> d = C()
>>> for x in 'spam eggs ham'.split():
...     setattr(d, x, C())
...     i = 1
...     for y in 'one two three'.split():
...         setattr(getattr(d, x), y, i)
...         i += 1
...
>>> assert d.spam.__dict__ == {'one': 1, 'two': 2, 'three': 3}

1
बंच को हटा दिया गया है, लेकिन इसका एक सक्रिय कांटा है: github.com/Infinidat/munch
रोटारेटी

@ रोरैटी - हेड-अप के लिए धन्यवाद! यह मेरे द्वारा उपयोग की जाने वाली कार्यक्षमता नहीं है, इसलिए मैं इससे अनजान था।
डग आर।

क्या होगा यदि आप एक गहराई तक जाना चाहते हैं? (टाइप करने का जिक्र (...)
ओले एल्ड्रिक

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

21

कैविट एम्प्टर: कुछ कारणों से इस तरह की कक्षाएं मल्टीप्रोसेसिंग पैकेज को तोड़ती प्रतीत होती हैं। मैं सिर्फ इस एसओ को खोजने से पहले थोड़ी देर के लिए इस बग के साथ संघर्ष किया: अजगर बहुउद्देशीय में अपवाद ढूँढना


19

आप मानक लाइब्रेरी से एक सुविधाजनक कंटेनर क्लास खींच सकते हैं:

from argparse import Namespace

कोड बिट्स के आसपास कॉपी करने से बचने के लिए। कोई मानक डिक्शनरी एक्सेस नहीं है, लेकिन यदि आप वास्तव में चाहते हैं तो एक वापस प्राप्त करना आसान है। Argparse में कोड सरल है,

class Namespace(_AttributeHolder):
    """Simple object for storing attributes.

    Implements equality by attribute names and values, and provides a simple
    string representation.
    """

    def __init__(self, **kwargs):
        for name in kwargs:
            setattr(self, name, kwargs[name])

    __hash__ = None

    def __eq__(self, other):
        return vars(self) == vars(other)

    def __ne__(self, other):
        return not (self == other)

    def __contains__(self, key):
        return key in self.__dict__

2
मानक पुस्तकालय को संदर्भित करने के लिए प्लस 1, जो ओपी द्वारा पहली टिप्पणी को संबोधित करता है।
गॉर्डन बीन

4
पायथन में उस मामले के लिए एक तेज़ वर्ग (C में लागू) शामिल है: types.SimpleNamespace docs.python.org/dev/library/types.html#types.SimpleNamespace
Nuno André

18

क्या होगा यदि आप एक कुंजी चाहते थे जो एक विधि थी, जैसे कि __eq__या __getattr__?

और आप एक प्रविष्टि के लिए सक्षम नहीं होंगे जो एक पत्र के साथ शुरू नहीं हुई थी, इसलिए 0343853कुंजी के रूप में उपयोग करना बाहर है।

और क्या होगा यदि आप एक स्ट्रिंग का उपयोग नहीं करना चाहते हैं?


वास्तव में, या उदाहरण के लिए कुंजी के रूप में अन्य वस्तुओं। हालाँकि मैं उस त्रुटि को 'अपेक्षित व्यवहार' के रूप में वर्गीकृत करूँगा - अपने प्रश्न के साथ मैं अप्रत्याशित की ओर अधिक लक्ष्य कर रहा था।
इज़-दीन रुहुलसिन

pickle.dumpका उपयोग करता है__getstate__
Cees Timmerman

12

tuples का उपयोग तानाशाही चाबियों के लिए किया जा सकता है। आप अपने निर्माण में कैसे काम करेंगे?

इसके अलावा, नेमटुपल एक सुविधाजनक संरचना है जो विशेषता पहुंच के माध्यम से मान प्रदान कर सकती है।


7
नेमटुपल्स का दोष यह है कि वे अपरिवर्तनीय हैं।
इज़-दीन रुहुलसिन

10
कुछ लोग कहेंगे कि अपरिवर्तनीय होना बग नहीं है बल्कि ट्यूपल्स की विशेषता है।
बेन लेखक

9

प्रोडक्शन के बारे में , थोड़ा पायथन वर्ग जो मैंने उन सभी पर शासन करने के लिए लिखा था :)

साथ ही, आपको ऑटो कोड पूरा , पुनरावर्ती ऑब्जेक्ट इंस्टेंटिएशन और ऑटो टाइप रूपांतरण प्राप्त होता है !

आप वही कर सकते हैं जो आपने मांगा था:

p = Prodict()
p.foo = 1
p.bar = "baz"

उदाहरण 1: टाइप हिंटिंग

class Country(Prodict):
    name: str
    population: int

turkey = Country()
turkey.name = 'Turkey'
turkey.population = 79814871

ऑटो कोड पूरा

उदाहरण 2: ऑटो प्रकार रूपांतरण

germany = Country(name='Germany', population='82175700', flag_colors=['black', 'red', 'yellow'])

print(germany.population)  # 82175700
print(type(germany.population))  # <class 'int'>

print(germany.flag_colors)  # ['black', 'red', 'yellow']
print(type(germany.flag_colors))  # <class 'list'>

2
पाइप के माध्यम से
python2

2
@ एंट 6 एन को प्रकार के एनोटेशन के कारण अजगर 3.6+ की आवश्यकता होती है
रमजान

8

यह सामान्यता में काम नहीं करता है। सभी वैध तानाशाह कुंजी पता योग्य विशेषताएँ ("कुंजी") नहीं बनाते हैं। तो, आपको सावधान रहने की आवश्यकता होगी।

पायथन ऑब्जेक्ट्स मूल रूप से शब्दकोष हैं। इसलिए मुझे संदेह है कि बहुत प्रदर्शन या अन्य जुर्माना है।


8

यह मूल प्रश्न को संबोधित नहीं करता है, लेकिन ऐसे लोगों के लिए उपयोगी होना चाहिए, जो मेरी तरह, यह कार्यक्षमता प्रदान करने वाले एक दायित्व की तलाश में यहां समाप्त होते हैं।

दीवानी यह इस के लिए एक महान lib है: https://github.com/mewwts/addict यह कई पिछले जवाब में बताया गया चिंताओं का ख्याल रखता है।

डॉक्स से एक उदाहरण:

body = {
    'query': {
        'filtered': {
            'query': {
                'match': {'description': 'addictive'}
            },
            'filter': {
                'term': {'created_by': 'Mats'}
            }
        }
    }
}

व्यसनी के साथ:

from addict import Dict
body = Dict()
body.query.filtered.query.match.description = 'addictive'
body.query.filtered.filter.term.created_by = 'Mats'

8

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

सौभाग्य से, इस कार्यक्षमता को प्रदान करने के लिए कई खुले स्रोत पैकेज हैं, जो पाइप स्थापित करने के लिए तैयार हैं! दुर्भाग्य से, कई पैकेज हैं। दिसंबर 2019 तक, यहां एक सारांश है।

दावेदार (सबसे हालिया मास्टर के लिए प्रतिबद्ध हैं। #commits | #contribs | कवरेज%):

अब अनुरक्षित या कम-अनुरक्षित नहीं है:

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

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

नशे की लत पेशेवरों:

  • पुनरावर्ती आरंभीकरण (foo.abc = 'bar'), तानाशाही-जैसे तर्क व्यसनी हो जाते हैं

व्यसनी विपक्ष:

  • typing.Dictयदि आप छायाfrom addict import Dict
  • कोई कुंजी जाँच नहीं। पुनरावर्ती init की अनुमति देने के कारण, यदि आप एक कुंजी को गलत करते हैं, तो आप KeyError के बजाय एक नया गुण बनाते हैं (धन्यवाद AljoSt)

चबाना पेशेवरों:

  • अद्वितीय नामकरण
  • JSON और YAML के लिए अंतर्निहित सेर / डे फ़ंक्शंस

चबाना विपक्ष:

  • कोई पुनरावर्ती init / केवल एक बार में एक attr init नहीं कर सकता

जिसमें मैं संपादकीय लिखता हूं

कई चंद्रमाओं से पहले, जब मैं केवल अपने या एक अन्य देव के साथ परियोजनाओं पर अजगर को लिखने के लिए पाठ संपादकों का उपयोग करता था, तो मुझे तानाशाह-शैली की शैली पसंद थी, सिर्फ घोषणा करके चाबियाँ डालने की क्षमता foo.bar.spam = eggs। अब मैं टीमों पर काम करता हूं, और हर चीज के लिए एक आईडीई का उपयोग करता हूं, और मैं स्थैतिक विश्लेषण, कार्यात्मक तकनीकों और प्रकार के संकेत के पक्ष में डेटा संरचनाओं और सामान्य रूप से गतिशील टाइपिंग से दूर चला गया हूं। मैंने इस तकनीक के साथ प्रयोग करना शुरू कर दिया है, अपने स्वयं के डिज़ाइन की वस्तुओं के साथ Pstruct को उप-वर्ग करना:

class  BasePstruct(dict):
    def __getattr__(self, name):
        if name in self.__slots__:
            return self[name]
        return self.__getattribute__(name)

    def __setattr__(self, key, value):
        if key in self.__slots__:
            self[key] = value
            return
        if key in type(self).__dict__:
            self[key] = value
            return
        raise AttributeError(
            "type object '{}' has no attribute '{}'".format(type(self).__name__, key))


class FooPstruct(BasePstruct):
    __slots__ = ['foo', 'bar']

यह आपको एक वस्तु देता है जो अभी भी एक तानाशाह की तरह व्यवहार करता है, लेकिन आपको बहुत अधिक कठोर फैशन में, विशेषताओं की तरह उपयोग करने देता है। यहाँ लाभ मैं (या आपके कोड के असहाय उपभोक्ताओं) को पता है कि वास्तव में कौन से क्षेत्र मौजूद हैं और क्या नहीं हो सकते हैं, और IDE स्वत: पूर्ण फ़ील्ड बना सकता है। इसके अलावा उपविभाजित वैनिला का dictमतलब है कि जसन क्रमांकन आसान है। मुझे लगता है कि इस विचार में अगला विकास एक कस्टम प्रोटोफ्यू जनरेटर होगा जो इन इंटरफेस का उत्सर्जन करता है, और एक अच्छा नॉक-ऑन आपको लगभग मुफ्त में जीआरपीसी के माध्यम से क्रॉस-भाषा डेटा संरचनाएं और आईपीसी मिलता है।

यदि आप attr-dicts के साथ जाने का निर्णय लेते हैं, तो यह आवश्यक है कि आपके (और आपके टीम के साथी) पवित्रता के लिए क्या फ़ील्ड्स की अपेक्षा की जाए।

हाल ही में रखने के लिए इस पोस्ट को संपादित / अपडेट करने के लिए स्वतंत्र महसूस करें!


2
इसके लिए एक बड़ा चोर addictयह है कि जब आप किसी विशेषता Dictको मिस करते हैं, तो यह अपवाद नहीं बढ़ाएगा, क्योंकि यह एक नया रिटर्न देगा (यह काम करने के लिए foo.abc = 'bar' के लिए आवश्यक है)।
अलजस्ट

5

यहाँ अंतर्निहित अभिलेखों के उपयोग से अपरिवर्तनीय रिकॉर्ड का एक छोटा उदाहरण दिया गया है collections.namedtuple:

def record(name, d):
    return namedtuple(name, d.keys())(**d)

और एक उपयोग उदाहरण:

rec = record('Model', {
    'train_op': train_op,
    'loss': loss,
})

print rec.loss(..)

5

बस उत्तर में कुछ विविधता जोड़ने के लिए, विज्ञान-किट सीखें इसे इस रूप में लागू किया गया है Bunch:

class Bunch(dict):                                                              
    """ Scikit Learn's container object                                         

    Dictionary-like object that exposes its keys as attributes.                 
    >>> b = Bunch(a=1, b=2)                                                     
    >>> b['b']                                                                  
    2                                                                           
    >>> b.b                                                                     
    2                                                                           
    >>> b.c = 6                                                                 
    >>> b['c']                                                                  
    6                                                                           
    """                                                                         

    def __init__(self, **kwargs):                                               
        super(Bunch, self).__init__(kwargs)                                     

    def __setattr__(self, key, value):                                          
        self[key] = value                                                       

    def __dir__(self):                                                          
        return self.keys()                                                      

    def __getattr__(self, key):                                                 
        try:                                                                    
            return self[key]                                                    
        except KeyError:                                                        
            raise AttributeError(key)                                           

    def __setstate__(self, state):                                              
        pass                       

आप सभी की जरूरत है setattrऔर getattrतरीकों को प्राप्त करने के लिए है - getattrतानाशाही कुंजी के लिए जाँच और वास्तविक विशेषताओं के लिए जाँच करने के लिए आगे बढ़ता है। setstaetअचार / unpickling "गुच्छों के लिए" ठीक करने के लिए एक ठीक है - अगर inerested जांच https://github.com/scikit-learn/scikit-learn/issues/6196


3

अपने खुद के रूप में लिखने के लिए कोई ज़रूरत नहीं setattr () और getattr () पहले से ही मौजूद हैं।

कक्षा की वस्तुओं का लाभ संभवतः कक्षा की परिभाषा और विरासत में आता है।


3

मैंने इसे इस थ्रेड से इनपुट के आधार पर बनाया है। मुझे हालांकि ओडिट का उपयोग करने की आवश्यकता है, इसलिए मुझे एटीआर प्राप्त करना और सेट करना ओवरराइड करना पड़ा। मुझे लगता है कि यह विशेष उपयोग के बहुमत के लिए काम करना चाहिए।

उपयोग इस तरह दिखता है:

# Create an ordered dict normally...
>>> od = OrderedAttrDict()
>>> od["a"] = 1
>>> od["b"] = 2
>>> od
OrderedAttrDict([('a', 1), ('b', 2)])

# Get and set data using attribute access...
>>> od.a
1
>>> od.b = 20
>>> od
OrderedAttrDict([('a', 1), ('b', 20)])

# Setting a NEW attribute only creates it on the instance, not the dict...
>>> od.c = 8
>>> od
OrderedAttrDict([('a', 1), ('b', 20)])
>>> od.c
8

कक्षा:

class OrderedAttrDict(odict.OrderedDict):
    """
    Constructs an odict.OrderedDict with attribute access to data.

    Setting a NEW attribute only creates it on the instance, not the dict.
    Setting an attribute that is a key in the data will set the dict data but 
    will not create a new instance attribute
    """
    def __getattr__(self, attr):
        """
        Try to get the data. If attr is not a key, fall-back and get the attr
        """
        if self.has_key(attr):
            return super(OrderedAttrDict, self).__getitem__(attr)
        else:
            return super(OrderedAttrDict, self).__getattr__(attr)


    def __setattr__(self, attr, value):
        """
        Try to set the data. If attr is not a key, fall-back and set the attr
        """
        if self.has_key(attr):
            super(OrderedAttrDict, self).__setitem__(attr, value)
        else:
            super(OrderedAttrDict, self).__setattr__(attr, value)

यह एक बहुत अच्छा पैटर्न है जो पहले से ही थ्रेड में उल्लिखित है, लेकिन यदि आप केवल एक तानाशाही लेना चाहते हैं और इसे एक ऑब्जेक्ट में बदलना चाहते हैं जो एक IDE, आदि में ऑटो-पूर्ण के साथ काम करता है:

class ObjectFromDict(object):
    def __init__(self, d):
        self.__dict__ = d

3

जाहिरा तौर पर अब इसके लिए एक पुस्तकालय है - https://pypi.python.org/pypi/attrdict - जो इस सटीक कार्यक्षमता और पुनरावर्ती विलय और json लोडिंग को लागू करता है। देखने लायक हो सकता है।


3

यही है वह जो मेरे द्वारा उपयोग किया जाता है

args = {
        'batch_size': 32,
        'workers': 4,
        'train_dir': 'train',
        'val_dir': 'val',
        'lr': 1e-3,
        'momentum': 0.9,
        'weight_decay': 1e-4
    }
args = namedtuple('Args', ' '.join(list(args.keys())))(**args)

print (args.lr)

यह एक अच्छा त्वरित और गंदा जवाब है। मेरा एकमात्र अवलोकन / टिप्पणी यह ​​है कि मुझे लगता है कि नामांकित निर्माणकर्ता तार की एक सूची को स्वीकार करेगा, इसलिए आपके समाधान को सरल बनाया जा सकता है (मुझे लगता है):namedtuple('Args', list(args.keys()))(**args)
Dan Nguyen

2

आप इसे इस वर्ग का उपयोग कर सकते हैं जिसे मैंने अभी बनाया है। इस वर्ग के साथ आप Mapऑब्जेक्ट को दूसरे शब्दकोश (json serialization सहित) या डॉट नोटेशन के साथ उपयोग कर सकते हैं । मुझे आशा है कि आपकी मदद करेंगे:

class Map(dict):
    """
    Example:
    m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
    """
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self[k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                self[k] = v

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]

उपयोग के उदाहरण:

m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
# Add new key
m.new_key = 'Hello world!'
print m.new_key
print m['new_key']
# Update values
m.new_key = 'Yay!'
# Or
m['new_key'] = 'Yay!'
# Delete key
del m.new_key
# Or
del m['new_key']

1
ध्यान दें कि यह dictतरीकों को छाया कर सकता है , जैसे: m=Map(); m["keys"] = 42; m.keys()देता है TypeError: 'int' object is not callable
bfontaine

@bfontaine यह विचार एक प्रकार का है field/attributeऔर एक नहीं है method, लेकिन यदि आप एक संख्या के बजाय एक विधि निर्दिष्ट करते हैं, तो आप उस पद्धति तक पहुँच सकते हैं m.method()
एपील

2

मुझे एक और कार्यान्वयन करने दें, जो किन्नियों के उत्तर पर आधारित है, लेकिन http://databio.org/posts/python_AttributeDict.html में प्रस्तावित एट्रीब्यूटडक्ट से विचारों को एकीकृत करता है ।

इस संस्करण का लाभ यह है कि यह नेस्टेड शब्दकोशों के लिए भी काम करता है:

class AttrDict(dict):
    """
    A class to convert a nested Dictionary into an object with key-values
    that are accessible using attribute notation (AttrDict.attribute) instead of
    key notation (Dict["key"]). This class recursively sets Dicts to objects,
    allowing you to recurse down nested dicts (like: AttrDict.attr.attr)
    """

    # Inspired by:
    # http://stackoverflow.com/a/14620633/1551810
    # http://databio.org/posts/python_AttributeDict.html

    def __init__(self, iterable, **kwargs):
        super(AttrDict, self).__init__(iterable, **kwargs)
        for key, value in iterable.items():
            if isinstance(value, dict):
                self.__dict__[key] = AttrDict(value)
            else:
                self.__dict__[key] = value

1
class AttrDict(dict):

     def __init__(self):
           self.__dict__ = self

if __name__ == '____main__':

     d = AttrDict()
     d['ray'] = 'hope'
     d.sun = 'shine'  >>> Now we can use this . notation
     print d['ray']
     print d.sun

1

समाधान है:

DICT_RESERVED_KEYS = vars(dict).keys()


class SmartDict(dict):
    """
    A Dict which is accessible via attribute dot notation
    """
    def __init__(self, *args, **kwargs):
        """
        :param args: multiple dicts ({}, {}, ..)
        :param kwargs: arbitrary keys='value'

        If ``keyerror=False`` is passed then not found attributes will
        always return None.
        """
        super(SmartDict, self).__init__()
        self['__keyerror'] = kwargs.pop('keyerror', True)
        [self.update(arg) for arg in args if isinstance(arg, dict)]
        self.update(kwargs)

    def __getattr__(self, attr):
        if attr not in DICT_RESERVED_KEYS:
            if self['__keyerror']:
                return self[attr]
            else:
                return self.get(attr)
        return getattr(self, attr)

    def __setattr__(self, key, value):
        if key in DICT_RESERVED_KEYS:
            raise AttributeError("You cannot set a reserved name as attribute")
        self.__setitem__(key, value)

    def __copy__(self):
        return self.__class__(self)

    def copy(self):
        return self.__copy__()

1

इस तरीके से तानाशाही चाबियों तक पहुँचने के क्या-क्या नुकसान और नुकसान होंगे?

जैसा कि @ हेनरी सुझाव देते हैं, एक कारण डॉटेड-एक्सेस का उपयोग डिकट्स में नहीं किया जा सकता है कि यह प्रमुख कुंजी नामों को अजगर-मान्य चर में सीमित करता है, जिससे सभी संभावित नामों को प्रतिबंधित किया जाता है।

निम्नलिखित उदाहरण इस बात पर दिए गए हैं कि डॉटेड-एक्सेस सामान्य रूप से सहायक क्यों नहीं होगा, एक तानाशाही d:

वैधता

पायथन में निम्नलिखित विशेषताएँ अमान्य होंगी:

d.1_foo                           # enumerated names
d./bar                            # path names
d.21.7, d.12:30                   # decimals, time
d.""                              # empty strings
d.john doe, d.denny's             # spaces, misc punctuation 
d.3 * x                           # expressions  

अंदाज

PEP8 सम्मेलनों में विशेषता नामकरण पर एक नरम बाधा होगी:

ए। आरक्षित कीवर्ड (या निर्मित फ़ंक्शन) नाम:

d.in
d.False, d.True
d.max, d.min
d.sum
d.id

यदि किसी फ़ंक्शन तर्क का नाम आरक्षित कीवर्ड के साथ टकराता है, तो आमतौर पर एकल ट्रेलिंग अंडरस्कोर को जोड़ना बेहतर होता है ...

B. विधियों और चर नामों पर मामला नियम :

चर नाम फ़ंक्शन नाम के समान कन्वेंशन का अनुसरण करते हैं।

d.Firstname
d.Country

फ़ंक्शन नामकरण नियमों का उपयोग करें: पठनीयता में सुधार के लिए आवश्यक के रूप में अंडरस्कोर द्वारा अलग किए गए शब्दों के साथ लोअरकेस।


कभी-कभी इन चिंताओं को पुस्तकालयों में उठाया जाता है जैसे पांडा , जो नाम से DataFrame कॉलम की डॉटेड-एक्सेस की अनुमति देता है। नामकरण प्रतिबंधों को हल करने के लिए डिफ़ॉल्ट तंत्र भी सरणी-संकेतन है - ब्रैकेट के भीतर एक स्ट्रिंग।

यदि ये बाधाएं आपके उपयोग के मामले में लागू नहीं होती हैं, तो डॉटेड-एक्सेस डेटा संरचनाओं पर कई विकल्प हैं ।


1

आप dict_to_obj https://pypi.org/project/dict-to-obj/ का उपयोग कर सकते हैं, यह आपके लिए ठीक वैसा ही है जैसा आप चाहते हैं

From dict_to_obj import DictToObj
a = {
'foo': True
}
b = DictToObj(a)
b.foo
True

1
यह आपके लिए .ideaकिसी भी उपयोगकर्ता-विशिष्ट या IDE जनरेट की गई फ़ाइल को डालने का अच्छा तरीका है .gitignore
DeusXMachina

1

यह एक 'अच्छा' उत्तर नहीं है, लेकिन मुझे लगा कि यह निफ्टी है (यह मौजूदा रूप में नेस्टेड डक्ट्स को संभालता नहीं है)। बस एक समारोह में अपने हुक लपेटो:

def make_funcdict(d=None, **kwargs)
    def funcdict(d=None, **kwargs):
        if d is not None:
            funcdict.__dict__.update(d)
        funcdict.__dict__.update(kwargs)
        return funcdict.__dict__
    funcdict(d, **kwargs)
    return funcdict

अब आपके पास थोड़ा अलग सिंटैक्स है। विशेषताओं के रूप में प्रमुख वस्तुओं को अभिव्यक्त करने के लिए f.key। सामान्य तरीके से तानाशाह वस्तुओं (और अन्य तानाशाह तरीकों) का उपयोग करने के लिए f()['key']और हम आसानी से कीवर्ड तर्कों और / या एक शब्दकोश के साथ फोन करके तानाशाह को अपडेट कर सकते हैं।

उदाहरण

d = {'name':'Henry', 'age':31}
d = make_funcdict(d)
>>> for key in d():
...     print key
... 
age
name
>>> print d.name
... Henry
>>> print d.age
... 31
>>> d({'Height':'5-11'}, Job='Carpenter')
... {'age': 31, 'name': 'Henry', 'Job': 'Carpenter', 'Height': '5-11'}

और वहाँ यह है। अगर किसी को इस पद्धति के लाभ और कमियां बताए तो मुझे खुशी होगी।


0

डौग द्वारा उल्लेख के रूप में एक बंच पैकेज है जिसे आप obj.keyकार्यक्षमता को प्राप्त करने के लिए उपयोग कर सकते हैं । वास्तव में एक नया संस्करण कहा जाता है

NeoBunch

हालांकि यह एक महान सुविधा है जो अपने नियोबॉन्चाइज़ फ़ंक्शन के माध्यम से अपने कमांड को NeoBunch ऑब्जेक्ट में परिवर्तित करता है। मैं माको टेम्प्लेट का बहुत अधिक उपयोग करता हूं और डेटा पास करता हूं क्योंकि NeoBunch ऑब्जेक्ट उन्हें अधिक पठनीय बनाता है, इसलिए यदि आप अपने पायथन प्रोग्राम में एक सामान्य तानाशाही का उपयोग करते हुए समाप्त होते हैं, लेकिन चाहते हैं कि माको टेम्पलेट में डॉट नोटेशन आप इस तरह से उपयोग कर सकें:

from mako.template import Template
from neobunch import neobunchify

mako_template = Template(filename='mako.tmpl', strict_undefined=True)
data = {'tmpl_data': [{'key1': 'value1', 'key2': 'value2'}]}
with open('out.txt', 'w') as out_file:
    out_file.write(mako_template.render(**neobunchify(data)))

और Mako टेम्पलेट की तरह लग सकता है:

% for d in tmpl_data:
Column1     Column2
${d.key1}   ${d.key2}
% endfor

NeoBunch का लिंक 404 है
DeusXMachina

0

सबसे आसान तरीका यह है कि एक वर्ग को परिभाषित करें जिसे हम नेमस्पेस कहते हैं। जो वस्तु को तानाशाही पर .update () का उपयोग करता है । फिर, हुकुम को एक वस्तु के रूप में माना जाएगा।

class Namespace(object):
    '''
    helps referencing object in a dictionary as dict.key instead of dict['key']
    '''
    def __init__(self, adict):
        self.__dict__.update(adict)



Person = Namespace({'name': 'ahmed',
                     'age': 30}) #--> added for edge_cls


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