IC # robimy to poprzez refleksję. W Javascript jest to proste:
for(var propertyName in objectName)
var currentPropertyValue = objectName[propertyName];
Jak to zrobić w Pythonie?
python
reflection
properties
Jader Dias
źródło
źródło
@property
.Odpowiedzi:
for property, value in vars(theObject).items(): print(property, ":", value)
Należy pamiętać, że w rzadkich przypadkach istnieje
__slots__
właściwość, której takie klasy często nie mają__dict__
.źródło
__setattr__()
. Ustawienie wartości bezpośrednio w słowniku pomija metodę ustawiającą obiektu (i / lub jego rodziców). W Pythonie dość często zdarza się, że więcej rzeczy niż na pierwszy rzut oka dzieje się w tle podczas ustawiania atrybutów (np. Higieny), używaniesetattr()
zapewnia, że nie przegapisz lub jesteś zmuszony do samodzielnego obsługiwania ich.vars()
zwraca tylko statyczne składowe (tj. atrybuty obiektów i metody zarejestrowane z tymi obiektami__dict__
). To nie nie powrócić dynamiczne członków (tj atrybuty obiektów i metod dynamicznie zdefiniowane przez ten obiekt w__getattr__()
metodzie lub podobnej magii). Najprawdopodobniej pożądanafile.ImplementationName
właściwość jest definiowana dynamicznie i dlatego nie jest dostępna dlavars()
anidir()
.Zobacz
inspect.getmembers(object[, predicate])
.>>> [name for name,thing in inspect.getmembers([])] ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__','__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] >>>
źródło
attributes
zamiastmembers
(czy jest jakaś różnica między nimi?). Mogli poprawić nazwę w Pythonie 3.0, aby była spójna.__dict__
, przepraszam.inspect.getmembers()
otaczadir()
(przeważnie pomijalne) korzyści uboczne (A), w tym dynamiczne atrybuty klas i atrybuty metaklasy oraz (B) wykluczenie elementów członkowskich nie pasujących do przekazanego predykatu. Ziewać, prawda?inspect.getmembers()
jest odpowiedni dla bibliotek innych firm, które ogólnie obsługują wszystkie możliwe typy obiektów. Jednak w przypadku standardowych zastosowań jest todir()
absolutnie wystarczające.dir()
to prosty sposób. Spójrz tutaj:Przewodnik po introspekcji w Pythonie
źródło
dir()
dziękuję.__dict__
Właściwość obiektu jest słownikiem wszystkich innych określonych właściwościach. Zauważ, że klasy Pythona mogą przesłonić getattr i sprawić, że rzeczy wyglądają jak właściwości, ale ich nie ma__dict__
. Jest również wbudowane funkcjevars()
idir()
które są różne w subtelny sposób. I__slots__
może zastąpić__dict__
w niektórych nietypowych klasach.Obiekty są skomplikowane w Pythonie.
__dict__
to właściwe miejsce do rozpoczęcia programowania w stylu refleksji.dir()
to miejsce, od którego możesz zacząć, jeśli hakujesz w interaktywnej powłoce.źródło
print vars.__doc__
wskazuje, żeWith an argument, equivalent to object.__dict__
Więc jakie byłyby subtelne różnice?dla statków jednoliniowych:
print vars(theObject)
źródło
Jeśli szukasz odzwierciedlenia wszystkich właściwości, powyższe odpowiedzi są świetne.
Jeśli po prostu szukasz kluczy ze słownika (który różni się od „obiektu” w Pythonie), użyj
my_dict.keys()
my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' } my_dict.keys() > ['abc', 'def', 'ghi']
źródło
obj['key']
porównaniu zobj.property
) i pytanie dotyczyło właściwości obiektów. Umieściłem tutaj swoją odpowiedź, ponieważ między nimi jest łatwo.Jest to całkowicie objęte innymi odpowiedziami, ale wyjaśnię to wyraźnie. Obiekt może mieć atrybuty klas oraz statyczne i dynamiczne atrybuty instancji.
class foo: classy = 1 @property def dyno(self): return 1 def __init__(self): self.stasis = 2 def fx(self): return 3
stasis
jest statyczny,dyno
dynamiczny (por. dekorator właściwości) iclassy
jest atrybutem klasy. Jeśli po prostu to zrobimy,__dict__
albovars
dostaniemy tylko statyczny.o = foo() print(o.__dict__) #{'stasis': 2} print(vars(o)) #{'stasis': 2}
Więc jeśli chcemy, inni
__dict__
dostaną wszystko (i więcej). Obejmuje to magiczne metody i atrybuty oraz normalne metody związane. Unikajmy więc tych:d = {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'} print(d) #{'stasis': 2, 'classy': 1, 'dyno': 1}
type
Wywołana z własności urządzone metody (atrybut dynamiczny) daje typ zwracanej wartości, niemethod
. Aby to udowodnić, json stringify it:import json print(json.dumps(d)) #{"stasis": 2, "classy": 1, "dyno": 1}
Gdyby to była metoda, zawaliłaby się.
TL; DR. spróbuj wezwać
extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}
wszystkie trzy, ale nie metody ani magię.źródło
Myślę, że warto pokazać różnicę między różnymi wymienionymi opcjami - często obraz jest wart tysiąca słów.
>>> from pprint import pprint >>> import inspect >>> >>> class a(): x = 1 # static class member def __init__(self): self.y = 2 # static instance member @property def dyn_prop(self): # dynamic property print('DYNPROP WAS HERE') return 3 def test(self): # function member pass @classmethod def myclassmethod(cls): # class method; static methods behave the same pass >>> i = a() >>> pprint(i.__dict__) {'y': 2} >>> pprint(vars(i)) {'y': 2} >>> pprint(dir(i)) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'dyn_prop', 'myclassmethod', 'test', 'x', 'y'] >>> pprint(inspect.getmembers(i)) DYNPROP WAS HERE [('__class__', <class '__main__.a'>), ('__delattr__', <method-wrapper '__delattr__' of a object at 0x000001CB891BC7F0>), ('__dict__', {'y': 2}), ('__dir__', <built-in method __dir__ of a object at 0x000001CB891BC7F0>), ('__doc__', None), ('__eq__', <method-wrapper '__eq__' of a object at 0x000001CB891BC7F0>), ('__format__', <built-in method __format__ of a object at 0x000001CB891BC7F0>), ('__ge__', <method-wrapper '__ge__' of a object at 0x000001CB891BC7F0>), ('__getattribute__', <method-wrapper '__getattribute__' of a object at 0x000001CB891BC7F0>), ('__gt__', <method-wrapper '__gt__' of a object at 0x000001CB891BC7F0>), ('__hash__', <method-wrapper '__hash__' of a object at 0x000001CB891BC7F0>), ('__init__', <bound method a.__init__ of <__main__.a object at 0x000001CB891BC7F0>>), ('__init_subclass__', <built-in method __init_subclass__ of type object at 0x000001CB87CA6A70>), ('__le__', <method-wrapper '__le__' of a object at 0x000001CB891BC7F0>), ('__lt__', <method-wrapper '__lt__' of a object at 0x000001CB891BC7F0>), ('__module__', '__main__'), ('__ne__', <method-wrapper '__ne__' of a object at 0x000001CB891BC7F0>), ('__new__', <built-in method __new__ of type object at 0x00007FFCA630AB50>), ('__reduce__', <built-in method __reduce__ of a object at 0x000001CB891BC7F0>), ('__reduce_ex__', <built-in method __reduce_ex__ of a object at 0x000001CB891BC7F0>), ('__repr__', <method-wrapper '__repr__' of a object at 0x000001CB891BC7F0>), ('__setattr__', <method-wrapper '__setattr__' of a object at 0x000001CB891BC7F0>), ('__sizeof__', <built-in method __sizeof__ of a object at 0x000001CB891BC7F0>), ('__str__', <method-wrapper '__str__' of a object at 0x000001CB891BC7F0>), ('__subclasshook__', <built-in method __subclasshook__ of type object at 0x000001CB87CA6A70>), ('__weakref__', None), ('dyn_prop', 3), ('myclassmethod', <bound method a.myclassmethod of <class '__main__.a'>>), ('test', <bound method a.test of <__main__.a object at 0x000001CB891BC7F0>>), ('x', 1), ('y', 2)]
Podsumowując:
vars()
i__dict__
zwracają tylko właściwości lokalne instancji;dir()
zwraca wszystko, ale tylko jako listę nazw członków łańcucha; właściwości dynamiczne nie są wywoływane;inspect.getmembers()
zwraca wszystko jako listę krotek(name, value)
; faktycznie uruchamia właściwości dynamiczne i przyjmuje opcjonalnypredicate
argument, który może odfiltrować elementy członkowskie według wartości .Tak więc moje zdroworozsądkowe podejście polega zwykle na używaniu
dir()
w wierszu poleceń iwgetmembers()
programach, chyba że mają zastosowanie szczególne względy wydajności.Zauważ, że aby zachować czystość, nie uwzględniłem
__slots__
- jeśli był obecny, został wyraźnie umieszczony w celu odpytywania i powinien być używany bezpośrednio. Nie opisałem też metaklas, które mogą być trochę owłosione (większość ludzi i tak nigdy ich nie użyje).źródło