Python中等价于Ruby的'method_missing'是什么?

32 投票
4 回答
9129 浏览
提问于 2025-04-16 21:35

Python中有没有类似于Ruby的method_missing方法的东西?我试过用__getattr__,但这个方法也会影响到属性。我只想拦截方法的调用。那在Python中应该怎么做呢?

4 个回答

3

你可以通过下面的方式来实现一个类似于缺失方法的功能:

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()
5

在Python中,方法和属性(也叫“实例变量”)的区别不像在Ruby中那么明显。Python查找方法和其他对象属性的方式是完全一样的——在查找的过程中,连Python自己都不知道它们之间的区别。在找到属性之前,它们都只是字符串。

所以,如果你在寻找一种方法来确保__getattr__只在调用方法时被触发,我恐怕你找不到一个优雅的解决方案。不过,从__getattr__返回一个函数(甚至是一个全新的动态绑定的方法)其实是很简单的。

31

在Python中,属性和方法没有区别。方法其实就是一种属性,它的类型是instancemethod,而且是可以被调用的(支持__call__)。

如果你想实现这个功能,你的__getattr__方法应该返回一个函数(可以是lambda表达式或者普通的def,根据你的需要来选择),并且可以在调用后检查一些东西。

撰写回答