2013-02-17 17 views
26

Mam obiekt "myobject", który może zwrócić None. Jeśli zwróci None, nie powróci atrybut "id":Jak mogę zwrócić wartość domyślną dla atrybutu?

a = myobject.id 

Więc kiedy MyObject jest None The stament powyżej wyników w AttributeError:

AttributeError: 'NoneType' object has no attribute 'id' 

jeśli myobject ma nikogo, a następnie Chcę, aby "a" było równe None. Jak uniknąć ten wyjątek w jednym sprawozdaniu linii, takich jak:

a= default(myobject.id, None) 

Odpowiedz

71

Należy użyć getattr opakowanie zamiast bezpośredniego pobierania wartości id.

a = getattr(myobject, 'id', None) 

To jakby powiedzieć: „Chciałbym, aby pobrać atrybut id od obiektu myobject, ale jeśli nie ma atrybut id wewnątrz obiektu myobject, a następnie powrócić None zamiast”. Ale robi to sprawnie.

Niektóre obiekty także wspierać następujące formy getattr dostępu:

a = myobject.getattr('id', None) 

Jak na żądanie OP 'deep getattr':

def deepgetattr(obj, attr): 
    """Recurses through an attribute chain to get the ultimate value.""" 
    return reduce(getattr, attr.split('.'), obj) 
# usage: 
print deepgetattr(universe, 'galaxy.solarsystem.planet.name') 

Proste wyjaśnienie:

Reduce jest jak w miejscu funkcja rekursywna.Co robi w tym przypadku jest zacząć od obj (wszechświata), a następnie rekurencyjnie dostać głębiej dla każdego atrybutu próby uzyskania dostępu za pomocą getattr, więc w swoim pytaniu byłoby tak:

a = getattr(getattr(myobject, 'id', None), 'number', None)

+1

+1, To jest chyba najlepszy pomysł, nie wiem, dlaczego nie myślałem o tym –

+0

@Inbar Rose A co jeśli chcę obta w atrybucie atrybut w ten sam sposób, jak 'a = myobject.id.number'? – alwbtc

+0

@alwbtc Dodano do mojej odpowiedzi. –

10

Najprostszym sposobem jest użycie potrójny operatora:

a = myobject.id if myobject is not None else None 

Operator trójargumentowy zwraca pierwszy wyraz jeżeli wartość środkowa jest prawda, w przeciwnym razie zwraca to ostatnie wyrażenie.

Zauważ, że można też zrobić to w inny sposób, stosując wyjątki:

try: 
    a = myobject.id 
except AttributeError: 
    a = None 

ten pasuje do pythonic ideał że łatwiej jest prosić o przebaczenie niż pozwolenie - co najlepiej będzie zależeć od sytuacji.

+0

Czy oceniać szybko? Mam 30000 obiektów do wykonania tego sprawdzenia. – alwbtc

+0

@alwbtc Spróbuj i zobacz. Sprawdź moduł 'timeit'. Jeśli sądzisz, że najprawdopodobniej duża część wartości będzie miała wartość "Brak", pierwsza metoda będzie prawdopodobnie szybsza, w przeciwnym razie użyj drugiej. –

+0

OK, wartości None nie są zbyt duże. Więc użyję drugiej metody. Ale chcę również kod składający się z jednej liniowej. Nie sądzisz, że zdania jednoliniowe są lepsze? – alwbtc

0
try: 
    a = myobject.id 
except AttributeError: 
    a = None 

będzie również pracować i jest jaśniejszy, IMO

+0

Nie jestem specjalistą od Pythona, ale w większości języków, z którymi miałem do czynienia, uwzględnienie w oświadczeniu "Wyjątek" wiąże się z dodatkowymi kosztami, które nie są znaczące. W prostym przypadku, takim jak ten, polecam "getattr" "approch (zakładając, że jest to mniej kosztowne) Czy niektórzy z was mogą powiedzieć coś więcej o metodzie getattr? –

+0

przedwczesna optymalizacja, dobry chłopak, przedwczesna optymalizacja – hd1

+2

To nie jest przedwczesna optymalizacja.Za używanie wyjątków do obsługi normalnego zachowania jest ogólnie uważane za zły styl – francoisr

0
a=myobect.id if myobject else None 
1

Help on built-in function getattr in module builtins:

getattr(...) 
    getattr(object, name[, default]) -> value 

Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y. When a default argument is given, it is returned when the attribute doesn't exist; without it, an exception is raised in that case.

obserwuję powinno działać:

a = getattr(myobject, 'id', None) 
6

w moim obiektu klasy można umieścić przesłonić

class Foo(object): 
    def __getattribute__(self, name): 
     if not name in self; 
     return None; 
     else: 
     # Default behaviour 
     return object.__getattribute__(self, name) 
0

Jeśli chcesz, aby rozwiązać problem w definicji klasy myobject (jak w Black Diamond's answer) można po prostu określić __getattr__ wrócić None:

class Myobject: 
    def __getattr__(self, name): 
     return None 

To działa, ponieważ __getattr__ nazywa się tylko wtedy, gdy próbuje uzyskać dostęp do atrybutu, który nie istnieje, natomiast __getattribute__ jest zawsze wywoływany jako pierwszy bez względu na nazwę atrybutu. (Patrz również this SO post.)

Aby wypróbować:

myobject = Myobject() 
print myobject.id 
myobject.id = 7 
print myobject.id 
Powiązane problemy