Iteracja atrybutów obiektów w Pythonie
Mam obiekt Pythona z kilkoma atrybutami i metodami. Chcę iterację nad atrybutami obiektu.
class my_python_obj(object):
attr1='a'
attr2='b'
attr3='c'
def method1(self, etc, etc):
#Statements
Chcę wygenerować słownik zawierający wszystkie atrybuty obiektów i ich bieżące wartości, ale chcę to zrobić w sposób dynamiczny(więc jeśli później dodam kolejny atrybut, nie muszę pamiętać o aktualizacji mojej funkcji).
W php zmienne mogą być używane jako klucze, ale obiekty w Pythonie są nieuscriptable i jeśli używam do tego notacji kropki tworzy nowy atrybut o nazwie My var, co nie jest moim zamiarem.
Żeby było jaśniej:
def to_dict(self):
'''this is what I already have'''
d={}
d["attr1"]= self.attr1
d["attr2"]= self.attr2
d["attr3"]= self.attr3
return d
·
def to_dict(self):
'''this is what I want to do'''
d={}
for v in my_python_obj.attributes:
d[v] = self.v
return d
Update: Z atrybutami mam na myśli tylko zmienne tego obiektu, a nie metody.
7 answers
Zakładając, że masz klasę taką jak
>>> class Cls(object):
... foo = 1
... bar = 'hello'
... def func(self):
... return 'call me'
...
>>> obj = Cls()
Wywołanie dir
na obiekcie zwraca wszystkie atrybuty tego obiektu, w tym specjalne atrybuty Pythona. Chociaż niektóre atrybuty obiektów są wywoływalne, takie jak metody.
>>> dir(obj)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'foo', 'func']
Zawsze możesz odfiltrować specjalne metody za pomocą rozumienia listy.
>>> [a for a in dir(obj) if not a.startswith('__')]
['bar', 'foo', 'func']
Lub jeśli wolisz mapy / filtry.
>>> filter(lambda a: not a.startswith('__'), dir(obj))
['bar', 'foo', 'func']
Jeśli chcesz odfiltrować metody, możesz użyć wbudowanego callable
jako szach.
>>> [a for a in dir(obj) if not a.startswith('__') and not callable(getattr(obj,a))]
['bar', 'foo']
Możesz również sprawdzić różnicę między klasą a jej rodzicem za pomocą.
>>> set(dir(Cls)) - set(dir(object))
set(['__module__', 'bar', 'func', '__dict__', 'foo', '__weakref__'])
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
2013-08-09 10:32:26
Ogólnie umieść metodę __iter__
w swojej klasie i powtarzaj przez atrybuty obiektu lub umieść tę klasę mixin w swojej klasie.
class IterMixin(object):
def __iter__(self):
for attr, value in self.__dict__.iteritems():
yield attr, value
Twoja klasa:
>>> class YourClass(IterMixin): pass
...
>>> yc = YourClass()
>>> yc.one = range(15)
>>> yc.two = 'test'
>>> dict(yc)
{'one': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], 'two': 'test'}
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
2013-11-26 10:29:39
Obiekty w Pythonie przechowują swoje atrybuty (w tym funkcje) w dict o nazwie __dict__
. Możesz (ale generalnie nie powinieneś) użyć tego, aby uzyskać bezpośredni dostęp do atrybutów. Jeśli potrzebujesz tylko listy, możesz również wywołać dir(obj)
, która zwraca iterowalną z wszystkimi nazwami atrybutów, które możesz następnie przekazać do getattr
.
Jednak, konieczność robienia czegokolwiek z nazwami zmiennych jest zwykle złym projektem. Dlaczego nie trzymać ich w kolekcji?
class Foo(object):
def __init__(self, **values):
self.special_values = values
Można następnie iterację nad kluczami z for key in obj.special_values:
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
2012-07-24 18:56:16
class someclass:
x=1
y=2
z=3
def __init__(self):
self.current_idx = 0
self.items = ["x","y","z"]
def next(self):
if self.current_idx < len(self.items):
self.current_idx += 1
k = self.items[self.current_idx-1]
return (k,getattr(self,k))
else:
raise StopIteration
def __iter__(self):
return self
Więc nazwij to jako iterable
s=someclass()
for k,v in s:
print k,"=",v
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
2012-07-24 19:05:21
Dla Pythona 3.6
class SomeClass:
def attr_list(self, should_print=False):
items = self.__dict__.items()
if should_print:
[print(f"attribute: {k} value: {v}") for k, v in items]
return items
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
2018-03-09 16:23:39
Dla Pythona 3.6
class SomeClass:
def attr_list1(self, should_print=False):
for k in self.__dict__.keys():
v = self.__dict__.__getitem__(k)
if should_print:
print(f"attr: {k} value: {v}")
def attr_list(self, should_print=False):
b = [(k, v) for k, v in self.__dict__.items()]
if should_print:
[print(f"attr: {a[0]} value: {a[1]}") for a in b]
return b
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
2018-03-09 15:54:50
Poprawna odpowiedź jest taka, że nie powinieneś. jeśli chcesz tego typu rzeczy albo po prostu użyj dict, albo będziesz musiał wyraźnie dodać atrybuty do jakiegoś kontenera. Możesz to zautomatyzować, ucząc się o dekoratorach.
W szczególności, przy okazji, method1 w twoim przykładzie jest tak samo dobry z atrybutu.
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
2012-07-24 18:55:52