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
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)
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:
-
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
-
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ć.
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
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)
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.
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)
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'
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