Python中类似于Ruby的method_missing
方法的等效方法是什么?我尝试使用__getattr__
,但此钩子也适用于字段。我只想拦截方法调用。Python的解决方案是什么?
Python中类似于Ruby的method_missing
方法的等效方法是什么?我尝试使用__getattr__
,但此钩子也适用于字段。我只想拦截方法调用。Python的解决方案是什么?
在Python中,属性和方法之间没有区别。 方法只是一个属性,其类型仅为 instancemethod
,恰好可以调用(支持 __call__
)。
如果您想实现此操作,您的 __getattr__
方法应该返回一个函数(一个lambda
或一个常规的def
,无论哪种都可以满足您的需求),并在调用后可能会检查一些内容。
Python不像Ruby一样区分方法和属性(也称为“实例变量”)。在Python中,方法和其他对象属性的查找方式完全相同 - 即使是Python在查找阶段也无法区分它们。在找到属性之前,它只是一个字符串。
因此,如果您要求一种方法来确保仅对方法调用__getattr__
,恐怕您可能找不到一个优雅的解决方案。但是从__getattr__
返回一个函数(甚至是全新的动态绑定方法)非常容易。
method_missing
或者在Smalltalk中使用doesNotUnderstand
。 - missingfaktor__getattr__
。我只是不明白为什么你“只想拦截方法调用”。 - senderle__getattr__
介于 method_missing
和覆盖 Hash#[]
以为缺失的键执行特殊操作之间。 - Mark Reedimport 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()
这个解决方案创建了一个 Dummy
对象,其中:
None
(即使您传递参数)methodname: defaultvalue
,用于应返回特定默认值的方法class Dummy:
def __init__(self, methods):
self.methods = methods
def __getattr__(self, attr):
defaultvalue = self.methods[attr] if attr in self.methods else None
return lambda *args, **kwargs: defaultvalue
def baz(self):
return 'custom'
d = Dummy({'foo': 1234})
print(d.foo()) # 1234
print(d.bar(1, 2, x=123, y=456)) # None
print(d.kjfdhgjf()) # None
print(d.baz()) # 'custom'
defaultvalue = self.methods.get(attr)
- Kelly Bundy