【问题标题】:Method Added in PythonPython中添加的方法
【发布时间】:2018-02-23 22:19:12
【问题描述】:

在 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

Python 有没有类似的回调?

【问题讨论】:

  • 不适用于在类创建期间添加的方法。之后它就像任何其他属性一样只是__setattr__
  • 您可以使用元类来做到这一点。
  • 这个功能有什么好的用例?我认为如果你也提供一些动力会很酷。

标签: python python-3.x class methods


【解决方案1】:

在 Python 中,方法只是 属性,碰巧是可调用的*。您必须连接到设置的属性才能看到添加到类的新方法。

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

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

然后看起来像这样:

>>> class Demo(metaclass=NewMethodAlerter):
...     def existing_method(self):
...         pass
...
>>> def new_method(self): pass
>>> Demo.new_method = new_method
New method new_method added!

如果您想了解 initial 属性集,即执行 class 主体的结果,那么您有两个选择:使用元类,或者在 Python 3.6 及更高版本中, __init_subclass__ method。任何一个都被调用来创建新类,并可用于检查属性:

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

__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

你可能想在What is a metaclass in Python?阅读元类


*其实属性就是函数。函数是descriptor objects,这会导致它们在通过实例访问时被绑定。该绑定过程会生成一个方法对象,该对象在被调用时会获取原始函数并传入它所绑定的实例。

【讨论】:

  • 那么就没有办法拦截类定义中定义的方法了吗?
  • @faraz:你想在这里实现什么?我可能误会了。元类在创建类时告知类的所有初始属性。
  • 我希望 New method existing_method added! 在类定义之后出现。
  • @faraz:你的问题让我很困惑,因为术语“添加”。我已经更新了这个问题,但它现在越来越多地与What is a metaclass in Python? 重复。
  • @faraz 一个小的说明可以帮助您理解为什么您没有看到有关现有方法的消息:当执行类主体并且所有初始类都没有调用 __setattr__ 方法成员被创建。为类 creation 调用了一组单独的机制。
猜你喜欢
  • 2016-05-01
  • 1970-01-01
  • 2014-05-18
  • 2013-05-27
  • 2011-04-28
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 1970-01-01
相关资源
最近更新 更多