Estoy escribiendo un algoritmo de búsqueda de espacio de estado AI, y tengo una clase genérica que se puede usar para implementar rápidamente un algoritmo de búsqueda. Una subclase definiría las operaciones necesarias, y el algoritmo hace el resto.
Aquí es donde me quedo atascado: quiero evitar la regeneración del estado padre una y otra vez, por lo que tengo la siguiente función, que devuelve las operaciones que se pueden aplicar legalmente a cualquier estado:
def get_operations(self, include_parent=True):
ops = self._get_operations()
if not include_parent and self.path.parent_op:
try:
parent_inverse = self.invert_op(self.path.parent_op)
ops.remove(parent_inverse)
except NotImplementedError:
pass
return ops
Y la función invert_op arroja por defecto.
¿Hay alguna forma más rápida de verificar si la función no está definida que detectar una excepción?
Estaba pensando en algo en el sentido de verificar el presente en dir, pero eso no parece correcto. hasattr se implementa llamando a getattr y verificando si aumenta, que no es lo que quiero.
has_op = lambda obj, op: callable(getattr(obj, op, None))
hasattr(connection, 'invert_opt')
.Respuestas:
Sí, use
getattr()
para obtener el atributo ycallable()
para verificarlo es un método:Tenga en cuenta que
getattr()
normalmente arroja una excepción cuando el atributo no existe. Sin embargo, si especifica un valor predeterminado (None
en este caso), lo devolverá en su lugar.fuente
getattr
en este caso detecta una excepción silenciosamente y devuelve el valor predeterminado en su lugar, al igual que lohasattr
hace, contra lo que el OP estuvo por alguna razón.Funciona tanto en Python 2 como en Python 3.
hasattr
devuelveTrue
si el objeto de conexión tiene una funcióninvert_opt
definida. Aquí está la documentación para que pueda pastarhttps://docs.python.org/2/library/functions.html#hasattr https://docs.python.org/3/library/functions.html#hasattr
fuente
connection.invert_opt = 'foo'
.¿Por qué estás en contra de eso? En la mayoría de los casos de Pythonic, es mejor pedir perdón que permiso. ;-)
De nuevo, ¿por qué es eso? Lo siguiente es bastante pitónico:
O,
Tenga en cuenta, sin embargo, que
getattr(obj, attr, default)
básicamente se implementa al detectar una excepción también. ¡No hay nada de malo en eso en Python land!fuente
Las respuestas en este documento verifican si una cadena es el nombre de un atributo del objeto. Se necesita un paso adicional (usando invocable) para verificar si el atributo es un método.
Por lo tanto, se reduce a: ¿cuál es la forma más rápida de verificar si un objeto obj tiene un atributo attrib? La respuesta es
Esto es así porque un dict aprieta sus claves, por lo que verificar la existencia de la clave es rápido.
Ver comparaciones de tiempo a continuación.
fuente
__slots__
.__slots__
ayuda a acelerar el acceso a atributos en ~ 10%. stackoverflow.com/a/14119024/1459669Me gusta la respuesta de Nathan Ostgard y la voté. Pero otra forma en que podría resolver su problema sería usar un decorador de memorización, que almacenaría en caché el resultado de la llamada a la función. Entonces puede seguir adelante y tener una función costosa que resuelve algo, pero luego, cuando lo llama una y otra vez, las llamadas posteriores son rápidas; la versión memorizada de la función busca los argumentos en un dict, encuentra el resultado en el dict desde que la función real calculó el resultado y devuelve el resultado de inmediato.
Aquí hay una receta para un decorador memorable llamado "lru_cache" por Raymond Hettinger. Una versión de esto ahora es estándar en el módulo functools en Python 3.2.
http://code.activestate.com/recipes/498245-lru-and-lfu-cache-decorators/
http://docs.python.org/release/3.2/library/functools.html
fuente
Como cualquier cosa en Python, si te esfuerzas lo suficiente, puedes llegar a las entrañas y hacer algo realmente desagradable. Ahora, aquí está la parte desagradable:
Por favor, háganos un favor, solo siga haciendo lo que tiene en su pregunta y NO lo use nunca a menos que esté en el equipo de PyPy pirateando al intérprete de Python. Lo que tienes allí es Pythonic, lo que tengo aquí es puro MAL .
fuente
co_names
es igual a('NotImplementedError',)
. Sin embargo, no estoy seguro de si esto lo hace más o menos malvado.También puedes repasar la clase:
fuente
Si bien la búsqueda de atributos en la propiedad __dict__ es realmente rápida, no puede usar esto para los métodos, ya que no aparecen en el hash __dict__. Sin embargo, podría recurrir a una solución alternativa en su clase, si el rendimiento es tan crítico:
Luego verifique el método como:
Comparación de tiempo con
getattr
:No es que esté alentando este enfoque, pero parece funcionar.
[EDITAR] El aumento del rendimiento es aún mayor cuando el nombre del método no está en una clase dada:
fuente
__dict__
podría ser anulado No se puede confiar.