2013-02-17 2 views
26

У меня есть объект «myobject», который может вернуться None. Если она возвращает None, он не возвращает атрибут "id":Как вернуть значение по умолчанию для атрибута?

a = myobject.id 

Так что, когда MyObject является None, то stament выше результатов в AttributeError:

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

Если myobject его нет, то Я хочу, чтобы «a» был равен None. Как избежать этого исключения в одной строке оператора, например:

a= default(myobject.id, None) 

ответ

71

Вы должны использовать getattr обертку вместо непосредственного извлечения значения id.

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

Это, как говорят: «Я хотел бы получить атрибут id от объекта myobject, но если нет атрибута id внутри объекта myobject, а затем вернуться None вместо этого.» Но он делает это эффективно.

Некоторые объекты также поддерживают следующую форму getattr доступа:

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

По запросу 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') 

Простое объяснение:

Reduce подобен на месте рекурсивная функция.Что она делает в этом случае начинается с obj (Вселенной), а затем рекурсивно углубиться для каждого атрибута, вы пытаетесь получить доступ с помощью getattr, поэтому в вашем вопросе было бы так:

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

+1

+1, Это, наверное, лучшая идея, не знаю, почему я об этом не думал. –

+0

Ха, спасибо, собираюсь использовать ваше одобрение для бесстыдной саморекламы.: P –

+0

@Inbar Rose И что, если я хочу обтаться в атрибуте атрибута таким же образом, как 'a = myobject.id.number'? – alwbtc

10

Самый простой способ заключается в использовании тройной оператор:

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

Тройная оператор возвращает первое выражение, если среднее значение является true, иначе оно возвращает последнее выражение.

Обратите внимание, что вы могли бы сделать это по-другому, используя исключения:

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

Это соответствует идеалу Pythonic, что легче просить прощения, чем разрешения - то, что лучше всего будет зависеть от ситуации.

+0

ли это оценить быстро? У меня есть 30000 объектов для этой проверки. – alwbtc

+0

@alwbtc Попробуй и посмотри. Проверьте модуль 'timeit'. Если вы считаете, что большая часть значений будет «Нет», первый метод, вероятно, будет быстрее, иначе используется вторая. –

+0

ОК, Никаких значений не так много. Поэтому я буду использовать второй метод. Но мне также нужен код, состоящий из однострочных. Разве вы не считаете, что однострочные утверждения лучше? – alwbtc

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

Будет также работать и понятнее, IMO

+0

Я не специалист по python, но на большинстве языков, с которыми я имел дело, падение в выражении «except» имеет дополнительную стоимость, которая не является существенной. В простом случае, таком как этот, я бы рекомендовал «getattr «Предположим, что это менее дорогостоящее). Может ли кто-то из вас рассказать еще немного о методе getattr? –

+0

преждевременная оптимизация, хороший парень, преждевременная оптимизация – hd1

+2

Это не преждевременная оптимизация. Использование исключений для нормального поведения обычно считается плохим стилем – francoisr

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.

должно работать:

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

в моем классе объектов вы можете поместить переопределить

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

Если вы хотите, чтобы решить эту проблему в определении класса myobject (как в Black Diamond's answer) вы можете просто определить __getattr__ вернуться None:

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

Это работает, потому что __getattr__ вызывалась только когда пытаясь получить доступ к атрибуту, который не существует, тогда как __getattribute__ всегда вызывается первым независимо от имени атрибута. (Смотри также this SO post.)

Чтобы попробовать:

myobject = Myobject() 
print myobject.id 
myobject.id = 7 
print myobject.id 
Смежные вопросы