28

Python 的 Rubymethod_missing方法等价物是什么?我尝试使用__getattr__,但这个钩子也适用于字段。我只想拦截方法调用。Python的方法是什么?

4

3 回答 3

29

在 Python 中,属性和方法没有区别。方法只是一个属性,它的类型是 just instancemethod,恰好是可调用的(支持__call__)。

如果您想实现这一点,您的__getattr__方法应该返回一个函数(alambda或常规def,无论您需要什么套件),并可能在调用后检查一些内容。

于 2011-07-15T08:22:26.540 回答
5

Python 不像 Ruby 那样区分方法和属性(也称为“实例变量”)。在 Python 中查找方法和其他对象属性的方式完全相同——甚至 Python 也不知道查找阶段的区别。在找到属性之前,它只是一个字符串。

因此,如果您要寻求一种方法来确保__getattr__仅调用方法,恐怕您可能找不到优雅的解决方案。但是. ___getattr__

于 2011-07-15T08:18:43.647 回答
3

您可以通过以下方式实现类似 missing_method 的功能:

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()
于 2013-08-31T19:36:31.933 回答