¿Cómo puedo devolver un valor predeterminado para un atributo? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

Tengo un objeto "myobject", que podría devolver None. Si devuelve None, no devolverá un atributo "id":

a = myobject.id

Así que cuando myobject es None, el stament anterior resulta en un AttributeError:

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

Si myobject es Ninguno, entonces quiero que "a" sea igual a Ninguno. ¿Cómo puedo evitar esta excepción en una declaración de línea, como:

a= default(myobject.id, None)
Author: Martin Thoma, 2013-02-17

7 answers

Debe utilizar el getattr wrapper en lugar de recuperar directamente el valor de id.

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

Esto es como decir "Me gustaría recuperar el atributo id del objeto myobject, pero si no hay ningún atributo id dentro del objeto myobject, entonces devuelve None en su lugar."Pero lo hace eficientemente.

Algunos objetos también admiten la siguiente forma de acceso getattr:

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

Según la solicitud de 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')

Simple explicación:

Reduce es como una función recursiva en el lugar. Lo que hace en este caso es comenzar con el obj (universo) y luego recursivamente obtener más profundo para cada atributo que intenta acceder usando getattr, por lo que en su pregunta sería así:

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

 79
Author: Inbar Rose,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-25 16:23:32

La forma más sencilla es usar el operador ternario:

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

El operador ternario devuelve la primera expresión si el valor medio es true, de lo contrario devuelve la última expresión.

Tenga en cuenta que también podría hacer esto de otra manera, utilizando excepciones:

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

Esto encaja con el ideal pitónico de que es más fácil pedir perdón que permiso - lo que es mejor dependerá de la situación.

 10
Author: Gareth Latty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-17 16:49:44

En mi clase object puedes poner override

class Foo(object):
   def __getattribute__(self, name):
      if not name in self;
        return None;
      else:
        # Default behaviour
        return object.__getattribute__(self, name)
 6
Author: Black Diamond,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-17 16:57:12

Ayuda sobre la función integrada getattr en el módulo builtins:

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

Obtiene un atributo con nombre de un objeto; getattr(x, 'y') es equivalente a x.y. Cuando se da un argumento predeterminado, se devuelve cuando el atributo no existe; sin ella, se plantea una excepción en ese caso.

Lo siguiente debería funcionar:

a = getattr(myobject, 'id', None)
 2
Author: shantanoo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-17 16:59:57

Si desea resolver el problema en la definición de la clase de myobject (como en Black Diamond's answer ), simplemente puede definir __getattr__ para devolver None:

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

Esto funciona porque __getattr__ solo se llama cuando se intenta acceder a un atributo que no existe, mientras que __getattribute__ siempre se llama primero sin importar el nombre del atributo. (Véase también este post.)

Para probar:

myobject = Myobject()
print myobject.id 
myobject.id = 7
print myobject.id
 1
Author: matec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-30 18:45:35
try:
    a = myobject.id
except AttributeError:
    a = None

También funcionará y es más claro, IMO

 0
Author: hd1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-17 16:51:17
a=myobect.id if myobject else None
 0
Author: Anil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-17 16:53:54