Ustawianie atrybutów ze słownika w Pythonie

Czy jest możliwe stworzenie obiektu ze słownika w Pythonie w taki sposób, że każdy klucz jest atrybutem tego obiektu?

Coś takiego:

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

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

Myślę, że byłoby to prawie odwrotność tego pytania: słownik Pythona z pól obiektu

Author: smci, 2010-03-18

7 answers

Jasne, coś takiego:

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

Update

Jak sugeruje Brent Nash, możesz uczynić to bardziej elastycznym, dopuszczając również argumenty słów kluczowych:

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

Wtedy możesz nazwać to tak:

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

Lub tak:

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

Lub nawet tak:

employee_template = {"role": "minion"}
e = Employee(employee_template, name="abc", age=32)
 120
Author: Ian Clelland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-17 22:55:32

Ustawianie atrybutów w ten sposób prawie na pewno nie jest najlepszym sposobem rozwiązania problemu. Albo:

  1. Wiesz, co wszystkie pola powinny być wcześniej. W takim przypadku można jawnie ustawić wszystkie atrybuty. Wyglądałoby to tak:

    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 
    

    Lub

  2. Nie wiesz, co wszystkie pola powinny być wcześniej. W takim przypadku powinieneś przechowywać dane jako dict zamiast zanieczyszczać przestrzeń nazw obiektów. Atrybuty są dla dostępu statycznego. Ta sprawa would look like

    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 
    

Innym rozwiązaniem, które jest zasadniczo równoważne z przypadkiem 1, jest użycie collections.namedtuple. Zobacz odpowiedź Vana, jak to wdrożyć.

 31
Author: Mike Graham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-17 22:39:26

Możesz uzyskać dostęp do atrybutów obiektu za pomocą __dict__ i wywołać na nim metodę update:

>>> 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
 9
Author: Dave Kirby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-17 22:02:00

Dlaczego nie używać nazw atrybutów jako kluczy do słownika?

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

Możesz inicjalizować za pomocą nazwanych argumentów, listy krotek lub słownika, lub przypisania poszczególnych atrybutów, np.:

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)

Alternatywnie, zamiast wywoływać błąd atrybutu, możesz zwrócić None dla nieznanych wartości. (Sztuczka używana w klasie pamięci web2py)

 6
Author: RufusVS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-13 18:08:42

Myślę, że ta odpowiedź za pomocą settattr jest droga do zrobienia, jeśli naprawdę trzeba wspierać dict.

Ale jeśli Employee obiekt jest tylko strukturą, do której możesz uzyskać dostęp za pomocą składni dot (.name) zamiast składni dict (['name']), możesz użyć nazwastuple w następujący sposób:

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

Masz metodę _asdict(), aby uzyskać dostęp do wszystkich właściwości jako słownika, ale nie możesz dodać dodatkowych atrybutów później, tylko podczas budowy.

 5
Author: van,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-17 22:53:05

Powiedzmy na przykład

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

Jeśli chcesz ustawić atrybuty na raz

d = {'x':100,'y':300,'z':"blah"}
a = A()
a.__dict__.update(d)
 4
Author: islam ezzat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-03 19:14:23

Podobnie jak przy użyciu dict, można po prostu użyć kwargów w ten sposób:

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'
 1
Author: Alex Spencer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-30 22:27:22