Python类方法在调用另一个方法时运行

2024-10-01 17:22:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我上的课如下:

class MyClass(object):
    def __init__(self):
        self.foo = "foo"
        self.bar = "bar"
        self.methodCalls = 0  #tracks number of times any function in the instance is run

    def get_foo(self):
        addMethodCall()
        return self.foo

    def get_bar(self):
        addMethodCall()
        return self.bar

    def addMethodCall(self):
        self.methodCalls += 1

是否有一个内置函数可以在调用方法时调用,而不是一直运行addMethodCall()?在


Tags: ofselfnumbergetreturnobjectfooinit
1条回答
网友
1楼 · 发布于 2024-10-01 17:22:46

不,类上没有钩子来完成这项工作。方法也是属性也是,尽管有点特殊,因为它们是在访问实例上的function对象时生成的;函数是descriptors。在

对method对象的调用是生成method对象的一个独立步骤:

>>> class Foo(object):
...     def bar(self):
...         return 'bar method on Foo'
...
>>> f = Foo()
>>> f.bar
<bound method Foo.bar of <__main__.Foo object at 0x100777bd0>>
>>> f.bar is f.bar
False
>>> stored = f.bar
>>> stored()
'bar method on Foo'

调用描述符协议是^{} method的任务,因此您可以挂接该协议以查看何时生成方法,但仍需要包装生成方法对象的以检测调用。例如,您可以返回一个带有^{} method的对象,它代表实际的方法。在

但是,用每次调用一个计数器递增的decorator来装饰每个方法会更容易。考虑到decorator在函数被绑定之前应用于,因此您必须传递self

^{2}$

您仍然需要将此应用于类中的所有函数。您可以手动将此应用于要计数的所有方法:

class MyClass(object):
    def __init__(self):
        self.foo = "foo"
        self.bar = "bar"
        self.methodCalls = 0  #tracks number of times any function method is run

    @method_counter
    def get_foo(self):
        return self.foo

    @method_counter
    def get_bar(self):
        return self.bar

或者可以使用元类:

import types

class MethodCounterMeta(type):
    def __new__(mcls, name, bases, body):
        # create new class object
        for name, obj in body.items():
            if name[:2] == name[-2:] == '__':
                # skip special method names like __init__
                continue
            if isinstance(obj, types.FunctionType):
                # decorate all functions
                body[name] = method_counter(obj)
        return super(MethodCounterMeta, mcls).__new__(mcls, name, bases, body)

    def __call__(cls, *args, **kwargs):
        # create a new instance for this class
        # add in `methodCalls` attribute
        instance = super(MethodCounterMeta, cls).__call__(*args, **kwargs)
        instance.methodCalls = 0
        return instance

这将处理decorator所需的一切,为您设置一个methodCalls属性,因此您的类不必:

class MyClass(object):
    __metaclass__ = MethodCounterMeta
    def __init__(self):
        self.foo = "foo"
        self.bar = "bar"

    def get_foo(self):
        return self.foo

    def get_bar(self):
        return self.bar

后一种方法的演示:

>>> class MyClass(object):
...     __metaclass__ = MethodCounterMeta
...     def __init__(self):
...         self.foo = "foo"
...         self.bar = "bar"
...     def get_foo(self):
...         return self.foo
...     def get_bar(self):
...         return self.bar
...
>>> instance = MyClass()
>>> instance.get_foo()
'foo'
>>> instance.get_bar()
'bar'
>>> instance.methodCalls
2

上面的元类只考虑类主体中的函数对象(因此def语句和lambda表达式的结果)部分进行装饰。它忽略任何其他可调用对象(还有更多的类型具有__call__方法,例如functools.partial对象),以及稍后添加到类的函数。在

相关问题 更多 >

    热门问题