2012-01-20 11 views
11

Niedawno znalazłem się pisania kodu jak poniżej:Iterate nad obiektem za „publiczne” atrybuty

 
for name in dir(object): 
    if name.startswith('__') : continue 
    ... 

Czy istnieje bardziej pythonic sposobem dostępu do przestrzeni nazw obiektu „publiczne”?

+2

jaki problem rozwiązujesz w pierwszej kolejności, że ten konstrukt jest przydatny? – SingleNegationElimination

+0

Co z 'dla nazwy w filtrze (lambda x: nie x.startswith ('_'), dir (obj)):'? Należy zauważyć, że w Pythonie nawet jedno podkreślenie ('_') ma na celu wskazanie *" prywatnego "atrybutu *. –

+2

@NiklasR 'dla nazwy (x dla x w dir (obj), jeśli nie x.startswith ('_')):' nie potrzebuje filtra –

Odpowiedz

15

Można przygotować listę „publiczne” atrybutów (jak liście lub jako generator) przed:

>>> public_props = (name for name in dir(object) if not name.startswith('_')) 
>>> for name in public_props: 
    print name 

Ale proszę przeczytać notatkę o dir() funkcję w dokumentacji:

Note Because dir() is supplied primarily as a convenience for use at an interactive prompt, it tries to supply an interesting set of names more than it tries to supply a rigorously or consistently defined set of names, and its detailed behavior may change across releases. For example, metaclass attributes are not in the result list when the argument is a class.

Powinieneś należy także pamiętać, że każda klasa może implementować metodę __dir__(), która może zwrócić listę nazw, które niekoniecznie odpowiadają nazwom atrybutów. Innymi słowy, dir(something) nie gwarantuje, że wynik zwróci atrybuty something.

+1

Czy istnieje powód, aby preferować 'dir (object)' do 'object .__ dict__'? – Dave

+1

obiekt .__ dict__ niekoniecznie zwraca atrybuty, które chcesz, przynajmniej z moich wyników testu, tak jest. –

15

Zamiast tego można użyć vars function.

Na przykład:

>>> class C(object): 
... def __init__(self): 
...  self.__foo = 'foo' 
... 
>>> c = C() 
>>> dir(c) 
['_C__foo', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__',  
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',  
'__weakref__'] 
>>> vars(c) 
{'_C__foo': 'foo'} 

zauważyć, że jak Niklas R wskazał, zmienne z pojedynczym podkreślenia są również traktowane jako prywatne. Jednak funkcja vars() ma tę zaletę, że eliminuje wszystkie oprócz zmiennych instancji.

+2

Otrzymuję argument TypeError: vars() musi mieć atrybut __dict__' przy próbie tego na innych obiektach. – wim

+2

Tak, funkcja 'vars()' może być używana tylko dla obiektów, które mają '__dict__'. Na przykład, jeśli na twojej klasie zdefiniowano '__slots__', nie będziesz mógł użyć funkcji' vars() '. – srgerg

+1

Zauważ, że nie dostaniesz niczego, co jest własnością, więc nie tylko rzeczy z '__slots__' nie będą działały. –

1

Czuję Iterowanie nad listą zrozumienie jest nieco bardziej pythonic niż przy użyciu słowa kluczowego continue, ale może to być po prostu kwestia gustu. To prawda, że ​​nie jest o wiele bardziej elegancka niż to, co już masz.

for attr in (a for a in dir(object) if not a.startswith('_')): 
    pass 

Uwaga: pojedyncze podkreślenia atrybuty nie są też "publiczne".

Powiązane problemy