¿Cuál es el equivalente de Python del método method_missing
de Ruby? Intenté usar __getattr__
pero este gancho también se aplica a los campos. Solo quiero interceptar las invocaciones del método. ¿Cuál es la forma de Python para hacerlo?equivalente en Python de 'method_missing' de Ruby
Respuesta
No hay diferencia en Python entre propiedades y métodos. Un método es solo una propiedad, cuyo tipo es solo instancemethod
, que resulta ser invocable (admite __call__
).
Si desea implementar esto, su método __getattr__
debe devolver una función (a lambda
o un habitual def
, sean cuales sean sus necesidades en suite) y tal vez comprobar algo después de la llamada.
Python no distingue entre métodos y atributos (a.k.a. "variables de instancia") de la forma en que lo hace Ruby. Los métodos y otros atributos de objeto se buscan exactamente de la misma manera en Python, ni siquiera Python conoce la diferencia en la etapa de búsqueda. Hasta que se encuentre el atributo, es solo una cadena.
Así que si usted está pidiendo una manera de asegurar que __getattr__
es única llamada de métodos, me temo que probablemente no va a encontrar una solución elegante. Pero es bastante fácil simplemente devolver una función (o incluso una nueva marca dynamically bound method) de __getattr__
.
Por la misma razón usarías 'method_missing' en Ruby o' doesNotUnderstand' en Smalltalk. – missingfaktor
Entiendo por qué querrías usar '__getattr__'.Simplemente no entiendo por qué "solo quieres interceptar las invocaciones de métodos". – senderle
Mi diseño no requirió la interceptación del acceso al campo, pero no parece ser un gran obstáculo. Encuentro que la solución provista por @Emil es lo suficientemente buena para mis requisitos. – missingfaktor
Aunque no lo recomiendo !!!!!!!!!!!!!!!!!!!!!
este tipo de método se acerca más a implementar el comportamiento de llamar al método especial para cada nombre que no corresponde a un atributo/método invocable. Por supuesto, todavía no tienen espacios de nombres separados, por lo que puede parecer un poco extraño. Funciona sobrescribiendo __getattribute__
, que funciona en un nivel inferior, luego __getattr__
, intenta recuperar un atributo si falla, devuelve un método especial al curry para llamar con el nombre con el que lo llamó, si lo logra, lo pasa si es invocable, de lo contrario envuelve el resultado con un objeto proxy que actúa casi de la misma manera luego, excepto que implementa la llamada con su método especial.
No le permite acceder al objeto que llama porque no se me ocurrió una buena manera de hacerlo sin una especie de memoria perdida (el objeto que llama) si ya es un atributo no recuperable que almacena (lo único que se me ocurre es comenzar un nuevo hilo que lo borre después de un minuto, para entonces probablemente lo haya llamado a menos que lo esté usando en un cierre que no sería compatible en ese caso).
Editar: Olvidé mi llamamiento puede tener algunos falsos positivos.
depende de la biblioteca http://pypi.python.org/pypi/ProxyTypes
from peak.util.proxies import ObjectWrapper
from functools import partial
def m(name, *args, **kwargs):
print(name,repr(args),repr(kwargs))
class CallProxy(ObjectWrapper):
def __init__(self, obj, m, method_name):
ObjectWrapper.__init__(self, obj)
object.__setattr__(self, "_method_name", method_name)
object.__setattr__(self, "_m", m)
def __call__(self, *args, **kwargs):
return self._m(self._method_name, *args,**kwargs)
class Y(object):
def __init__(self):
self.x = [3]
def __getattribute__(self, name):
try:
val = object.__getattribute__(self, name)
if not callable(val):
return CallProxy(val, m, name)
else:
return val
except AttributeError:
return partial(m, name)
In [2]: y=Y()
In [3]: y.x
Out[3]: [3]
In [4]: y.z
Out[4]: <functools.partial at 0x2667890>
In [5]: y.zz([12])
('zz', '([12],)', '{}')
In [6]: y.x.append(5)
In [7]: y.x
Out[7]: [3, 5]
In [8]: y.x(1,2,3,key="no")
('x', '(2, 3)', "{'key': 'no'}")
Se podría implementar un missing_method como función de la forma a continuación:
https://gist.github.com/gterzian/6400170
import unittest
from functools import partial
class MethodMissing:
def method_missing(self, name, *args, **kwargs):
'''please implement'''
raise NotImplementedError('please implement a "method_missing" method')
def __getattr__(self, name):
return partial(self.method_missing, name)
class Wrapper(object, MethodMissing):
def __init__(self, item):
self.item = item
def method_missing(self, name, *args, **kwargs):
if name in dir(self.item):
method = getattr(self.item, name)
if callable(method):
return method(*args, **kwargs)
else:
raise AttributeError(' %s has not method named "%s" ' % (self.item, name))
class Item(object):
def __init__(self, name):
self.name = name
def test(self, string):
return string + ' was passed on'
class EmptyWrapper(object, MethodMissing):
'''not implementing a missing_method'''
pass
class TestWrapper(unittest.TestCase):
def setUp(self):
self.item = Item('test')
self.wrapper = Wrapper(self.item)
self.empty_wrapper = EmptyWrapper()
def test_proxy_method_call(self):
string = self.wrapper.test('message')
self.assertEqual(string, 'message was passed on')
def test_normal_attribute_not_proxied(self,):
with self.assertRaises(AttributeError):
self.wrapper.name
self.wrapper.name()
def test_empty_wrapper_raises_error(self,):
with self.assertRaises(NotImplementedError):
self.empty_wrapper.test('message')
if __name__ == '__main__':
unittest.main()
- 1. method_missing gotchas en Ruby
- 2. ¿Ruby tiene un method_missing equivalente para variables de instancia indefinidas?
- 3. Equivalente a Ruby method_missing en Objective C/iOS
- 4. Python equivalente de Perl/Ruby || =
- 5. Ruby equivalente de Python setattr()
- 6. Ruby LESS equivalente de gema en Python
- 7. Ruby equivalente al "dir" de Python?
- 8. Ruby equivalente a la ayuda de Python()?
- 9. Python equivalente de continuaciones con Ruby
- 10. Python Equivalente a #each_cons de Ruby?
- 11. Python equivalente a cada_slice de Ruby (conteo)
- 12. ¿Tiene Javascript algo como la función method_missing de Ruby?
- 13. ¿Hay un equivalente en Python del "cualquiera" de Ruby? ¿función?
- 14. ¿Cuál es el equivalente de Python al "inspeccionar" de Ruby?
- 15. Ruby equivalente de NumPy
- 16. ¿Cuál es el equivalente Ruby de os.walk de Python?
- 17. Ruby "es" equivalente
- 18. Python equivalente de Sinatra
- 19. Equivalente de Bash Backticks en Python
- 20. ¿Cuál es el equivalente Ruby de python setup.py develop?
- 21. ¿Hay un Python equivalente a los símbolos de Ruby?
- 22. ¿Cuál es el equivalente Ruby de "pythonic"?
- 23. ¿Hay un equivalente de Rake en Python?
- 24. Equivalente de rubí obj.send en Python
- 25. PHP equivalente al símbolo de Ruby
- 26. Equivalente para inyectar() en Python?
- 27. ¿Qué es el equivalente "sys.stdout.write()" en Ruby?
- 28. Equivalente de cURL para Ruby?
- 29. Carga dinámica de clases: ¿hay un "method_missing" para las clases en Ruby?
- 30. ruby on rails campos de atributos dinámicos de DB utilizando los problemas de method_missing
Gracias. Encontré [esto] (http://venodesigns.net/2010/11/02/emulating-rubys-method_missing-in-python/) en un pequeño google. – missingfaktor
Como referencia, el enlace en cuestión elude la ambigüedad definiendo una lista de nombres de atributos que deben considerarse métodos (lo que suena como que es un poco contrario al propósito, ya que podría simplemente _definir_ cada uno de esos métodos y delegarlos en un stub). –