अजगर में शब्दकोश से सेट विशेषताएँ


102

क्या अजगर में एक शब्दकोष से इस तरह से एक वस्तु बनाना संभव है कि प्रत्येक कुंजी उस वस्तु का एक गुण है?

कुछ इस तरह:

 d = { 'name': 'Oscar', 'lastName': 'Reyes', 'age':32 }

 e = Employee(d) 
 print e.name # Oscar 
 print e.age + 10 # 42 

मुझे लगता है कि यह इस सवाल का उलटा होगा: पायथन डिक्शनरी किसी वस्तु के क्षेत्र से

जवाबों:


172

ज़रूर, कुछ इस तरह:

class Employee(object):
    def __init__(self, initial_data):
        for key in initial_data:
            setattr(self, key, initial_data[key])

अपडेट करें

जैसा कि ब्रेंट नैश सुझाव देते हैं, आप कीवर्ड तर्क के साथ-साथ इसे और अधिक लचीला बना सकते हैं:

class Employee(object):
    def __init__(self, *initial_data, **kwargs):
        for dictionary in initial_data:
            for key in dictionary:
                setattr(self, key, dictionary[key])
        for key in kwargs:
            setattr(self, key, kwargs[key])

तो आप इसे इस तरह से कॉल कर सकते हैं:

e = Employee({"name": "abc", "age": 32})

या इस तरह:

e = Employee(name="abc", age=32)

या यहां तक ​​कि इस तरह:

employee_template = {"role": "minion"}
e = Employee(employee_template, name="abc", age=32)

4
यदि आप प्रारंभिक डेटा पास करते हैं, तो आपको def __init__(self,**initial_data)एक init विधि होने का अतिरिक्त लाभ मिलता है, जो कीवर्ड तर्क भी कर सकता है (उदाहरण के लिए "e = कर्मचारी (नाम = 'ऑस्कर')" या बस एक शब्दकोश में लें (उदाहरण के लिए "e = Employee () ** तानाशाह) ")।
ब्रेंट राइट्स कोड

2
दोनों Employee(some_dict)और Employee(**some_dict)एपीआई की पेशकश असंगत है। जो भी बेहतर हो आपूर्ति की जानी चाहिए।
माइक ग्राहम

4
यदि आप ()इसके बजाय अपने arg की डिफॉल्ट सेट करते हैं None, तो आप ऐसा कर सकते हैं def __init__(self, iterable=(), **kwargs): self.__dict__.update(iterable, **kwargs):।
मैट एंडरसन

4
मैं इसे पुराने सवाल यह है कि पता है, लेकिन मैं तो बस को जोड़ने के लिए है कि यह सूची समझ के साथ दो पंक्तियों में किया जा सकता उदाहरण के लिए, चाहते हैं:[[setattr(self,key,d[key]) for key in d] for d in some_dict]
TZ

2
मुझे यह जानकर अच्छा लगेगा कि यह कुछ सरल तरीके से अजगर में क्यों नहीं बनाया गया है। मैं इसका इस्तेमाल कर रहा हूं कि अजगर जियोआईपी 2 एपीआई को फेंकने AddressNotFoundErrorके लिए (उस मामले में सही डेटा को वापस करने के बजाय) - उड़ाने के बजाय मैंने पाया कि यह पागल है कि PHP में कुछ इतना आसान है ( (object) ['x' => 'y']) Python में इतने cruft की आवश्यकता है
Someguy123

46

इस तरह से विशेषताओं को सेट करना निश्चित रूप से किसी समस्या को हल करने का सबसे अच्छा तरीका नहीं है। कोई एक:

  1. आप जानते हैं कि सभी क्षेत्रों को समय से पहले होना चाहिए। उस स्थिति में, आप सभी विशेषताओं को स्पष्ट रूप से सेट कर सकते हैं। ऐसा लगेगा

    class Employee(object):
        def __init__(self, name, last_name, age):
            self.name = name
            self.last_name = last_name
            self.age = age
    
    d = {'name': 'Oscar', 'last_name': 'Reyes', 'age':32 }
    e = Employee(**d) 
    
    print e.name # Oscar 
    print e.age + 10 # 42 
    

    या

  2. आप नहीं जानते कि सभी क्षेत्रों को समय से पहले क्या होना चाहिए। इस स्थिति में, आपको ऑब्जेक्ट्स नामस्थान को प्रदूषित करने के बजाय डेटा को एक संग्रह के रूप में संग्रहीत करना चाहिए। विशेषताएँ स्थिर पहुँच के लिए हैं। यह मामला जैसा लगेगा

    class Employee(object):
        def __init__(self, data):
            self.data = data
    
    d = {'name': 'Oscar', 'last_name': 'Reyes', 'age':32 }
    e = Employee(d) 
    
    print e.data['name'] # Oscar 
    print e.data['age'] + 10 # 42 
    

एक और समाधान जो मूल रूप से केस 1 के बराबर है एक का उपयोग करना है collections.namedtuple। कैसे लागू करने के लिए वैन का जवाब देखें।


और क्या होगा अगर परिदृश्य आपके दो चरम सीमाओं के बीच कहीं है? इसके लिए ठीक यही उपयोग मामला है, और वर्तमान में AFAICT में DRY और पायथोनिक तरीके से ऐसा करने का कोई तरीका नहीं है।
डायलनयुंग

15

आप किसी ऑब्जेक्ट की विशेषताओं तक पहुंच सकते हैं __dict__, और उस पर अपडेट विधि को कॉल कर सकते हैं:

>>> class Employee(object):
...     def __init__(self, _dict):
...         self.__dict__.update(_dict)
... 


>>> dict = { 'name': 'Oscar', 'lastName': 'Reyes', 'age':32 }

>>> e = Employee(dict)

>>> e.name
'Oscar'

>>> e.age
32

3
__dict__एक कार्यान्वयन कलाकृति है और इसका उपयोग नहीं किया जाना चाहिए। इसके अलावा, यह वर्ग पर वर्णनकर्ताओं के अस्तित्व की उपेक्षा करता है।
इग्नासियो वाज़क्वेज़-अब्राम्स

1
@ इग्नासियो "कार्यान्वयन कलाकृतियों" से आपका क्या अभिप्राय है? क्या हम इसके बारे में पता नहीं होना चाहिए? या कि यह विभिन्न प्लेटफार्मों में मौजूद नहीं हो सकता है? (उदा। विंडोज बनाम लिनक्स में पायथन लिनक्स पर) एक स्वीकार्य जवाब क्या होगा?
ऑस्कररेज़

12
__dict__भाषा का एक प्रलेखित हिस्सा है, कार्यान्वयन कलाकृतियों का नहीं।
डेव किर्बी

3
का उपयोग करना सीधे setattrपहुंच के लिए बेहतर है __dict__। आपको बहुत सी चीजों को ध्यान में रखना होगा जो कि __dict__आपके उपयोग करने के दौरान वहां नहीं होने या जो आप चाहते हैं वह नहीं कर सकते हैं __dict__, लेकिन setattrवास्तव में वास्तव में करने के लिए समान है foo.bar = baz
माइक ग्राहम

1
@DaveKirby: ऐसा लगता है कि इसके सामान्य उपयोग के __dict__खिलाफ सलाह दी जाती है: docs.python.org/tutorial/classes.html#id2
equaeghe

11

सिर्फ एक शब्दकोश की कुंजी के रूप में विशेषता नामों का उपयोग क्यों न करें?

class StructMyDict(dict):

     def __getattr__(self, name):
         try:
             return self[name]
         except KeyError as e:
             raise AttributeError(e)

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

आप नामित तर्कों, ट्यूल की सूची या शब्दकोश, या व्यक्तिगत विशेषता असाइनमेंट, जैसे:

nautical = StructMyDict(left = "Port", right = "Starboard") # named args

nautical2 = StructMyDict({"left":"Port","right":"Starboard"}) # dictionary

nautical3 = StructMyDict([("left","Port"),("right","Starboard")]) # tuples list

nautical4 = StructMyDict()  # fields TBD
nautical4.left = "Port"
nautical4.right = "Starboard"

for x in [nautical, nautical2, nautical3, nautical4]:
    print "%s <--> %s" % (x.left,x.right)

वैकल्पिक रूप से, विशेषता त्रुटि को बढ़ाने के बजाय, आप अज्ञात मानों के लिए कोई भी वापस नहीं कर सकते। (Web2py स्टोरेज क्लास में इस्तेमाल की जाने वाली ट्रिक)


7

मुझे लगता है कि उत्तर का उपयोग settattrकरने का तरीका है अगर आपको वास्तव में समर्थन करने की आवश्यकता है dict

लेकिन अगर Employeeऑब्जेक्ट सिर्फ एक संरचना है, जिसे आप ताना वाक्यविन्यास ( .name) के बजाय डॉट सिंटैक्स ( ) के साथ एक्सेस ['name']कर सकते हैं, तो आप इस तरह से नामांकित का उपयोग कर सकते हैं :

from collections import namedtuple

Employee = namedtuple('Employee', 'name age')
e = Employee('noname01', 6)
print e
#>> Employee(name='noname01', age=6)

# create Employee from dictionary
d = {'name': 'noname02', 'age': 7}
e = Employee(**d)
print e
#>> Employee(name='noname02', age=7)
print e._asdict()
#>> {'age': 7, 'name': 'noname02'}

आपके पास _asdict()सभी गुणों को शब्दकोश के रूप में एक्सेस करने की विधि है, लेकिन आप बाद में अतिरिक्त विशेषताओं को नहीं जोड़ सकते हैं , केवल निर्माण के दौरान।


6

उदाहरण के लिए कहो

class A():
    def __init__(self):
        self.x=7
        self.y=8
        self.z="name"

यदि आप एक ही बार में विशेषताएँ सेट करना चाहते हैं

d = {'x':100,'y':300,'z':"blah"}
a = A()
a.__dict__.update(d)

1
आप सुविधा के लिए कुंजी / मान का उपयोग कर सकते हैं:a.__dict__.update(x=100, y=300, z="blah")
simno

1

एक तानाशाह का उपयोग करने के समान, आप बस कागज़ का उपयोग कर सकते हैं:

class Person:
   def __init__(self, **kwargs):
       self.properties = kwargs

   def get_property(self, key):
       return self.properties.get(key, None)

   def main():
       timmy = Person(color = 'red')
       print(timmy.get_property('color')) #prints 'red'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.