Python-эквивалент Ruby 'method_missing'

Что является эквивалентом Python метода Ruby method_missing ? Я пробовал использовать __ getattr __ , но эта ловушка применима и к полям. Я хочу только перехватить вызовы метода. Как это сделать в Python?

24
задан dreftymac 5 April 2017 в 21:00
поделиться

1 ответ

Хотя я не рекомендую это !!!!!!!!!!!!!!!!!!!!!

это своего рода приближается к реализации поведения вызова специального метода для каждого имени, которое не соответствует вызываемому атрибуту / методу. Конечно, они все еще не имеют отдельных пространств имен, так что это может показаться немного странным. Он работает путем переопределения __getattribute__, который работает на более низком уровне, чем __getattr__, он пытается извлечь атрибут, если не удается, возвращает специальный метод с каррией для вызова с именем, с которым вы его вызвали, если он успешно выполняется, он передает его, если в противном случае он вызывает результат с помощью прокси-объекта, который впоследствии действует почти таким же образом, за исключением того, что он реализует вызов с помощью вашего специального метода.

Он не позволяет вам получить доступ к вызывающему объекту, потому что я не мог придумать хороший способ сделать это без какой-либо утечки памяти (вызывающего объекта), если это уже неотзываемый атрибут, который вы сохраняете ( Единственное, о чем я могу думать, - это запустить новый поток, который удаляет его через минуту, к тому времени вы, вероятно, уже назвали его, если не используете его в закрытии, которое в этом случае не будет поддерживаться).

Редактировать: я забыл, что вызываемый может иметь некоторые ложные срабатывания.

зависит от библиотеки 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'}")
1
ответ дан 28 November 2019 в 23:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: