Python中添加的方法

fny*_*fny 1 python methods class python-3.x

在Ruby中,可以为在对象上定义方法时创建回调:

module Chatty
  def self.method_added(method_name)
    puts "Adding #{method_name.inspect}"
  end
  def self.some_class_method() end
  def some_instance_method() end
end
# => Adding :some_instance_method
Run Code Online (Sandbox Code Playgroud)

Python有没有类似的回调?

Mar*_*ers 7

在Python中,方法只是恰好可调用的属性*.您必须挂钩设置的属性才能看到要添加到类中的新方法.

您必须使用元类来拦截添加到类中的新属性:

import types

class NewMethodAlerter(type):
    def __setattr__(self, name, obj):
        if isinstance(obj, types.FunctionType):
            print(f'New method {name} added!')
        super().__setattr__(name, obj)


class Demo(metaclass=NewMethodAlerter):
    def existing_method(self):
        pass

def new_method(self): pass
Demo.new_method = new_method
Run Code Online (Sandbox Code Playgroud)

然后看起来像这样:

>>> class Demo(metaclass=NewMethodAlerter):
...     def existing_method(self):
...         pass
...
>>> def new_method(self): pass
>>> Demo.new_method = new_method
New method new_method added!
Run Code Online (Sandbox Code Playgroud)

如果你想知道初始属性集,执行class正文的结果,那么你有两个选择:使用元类,或者在Python 3.6及更高版本中使用__init_subclass__方法.调用其中一个来创建新类,并可用于检查属性:

class InitialMethodAlerter(type):
    def __new__(typ, name, bases, attrs):
        for name, obj in attrs.items():
            if isinstance(obj, types.FunctionType):
                print(f'Method {name} defined!')
        return super().__new__(typ, name, bases, attrs)

class Demo(metaclass=InitialMethodAlerter):
    def existing_method(self):
        pass
Run Code Online (Sandbox Code Playgroud)

__init_subclass__方法:

class InitialMethodAlerter:
    @classmethod
    def __init_subclass__(cls, **kwargs):
        for name, obj in vars(cls).items():
            if isinstance(obj, types.FunctionType):
                print(f'Method {name} defined!')

class Demo(InitialMethodAlerter):
    def existing_method(self):
        pass
Run Code Online (Sandbox Code Playgroud)

您可能想要阅读Python中元类的什么是元类?


*嗯,属性实际上是函数.函数是描述符对象,它们在通过实例访问时会绑定它们.该绑定过程产生一个方法对象,当被调用时,它接受原始函数并传入它所绑定的实例.