【问题标题】:Dynamically inserting a function into a Python class将函数动态插入 Python 类
【发布时间】:2020-05-22 13:53:18
【问题描述】:

我正在编写一个元类,除其他外,它还想为它创建的类添加一个方法。让我们暂时忘掉元类,看看简单的方法添加。

为了动态添加实例方法我可以这样做:

class Foo:
    def bar(self, x):
        print(f"In bar() with {x} and {self}")

def func(self, x):
    print(f"In func() with {x} and {self}")

Foo.func = func

之后我可以做:

>>> f = Foo()                                                                                                                                              
>>> f.bar(7)                                                                                                                                               
In bar() with 7 and <__main__.Foo object at 0x7f912a7e57f0>                                                                                                
>>> f.func(7)                                                                                                                                              
In func() with 7 and <__main__.Foo object at 0x7f912a7e57f0>

所以barfunc 方法似乎功能相同,但有一些明显的区别,例如:

>>> f.bar.__qualname__                                                                                                                                     
'Foo.bar'                                                                                                                                                  
>>> f.func.__qualname__                                                                                                                                 
'func'

f.func.__module__ 也可能与 f.bar.__module__ 不同,具体取决于所有内容的定义位置。

我必须在构造 2(如下)中进行哪些更改才能使两个构造的行为完全相同(没有使用 Foo 类的代码可以根据使用的构造改变其行为)?

# Construction 1
class Foo:
    def func(self):
        pass

# Construction 2
class Foo:
    pass
def func(self):
    pass
Foo.func = func

我已经创建了一个装饰器,希望能实现一个合理的Construction 2版本,但是我仍然会因为这样的猴子补丁而丢失/破坏什么?

class instance_method_of:

    def __init__(self, cls, name=None):
        self.cls = cls
        self.name = name

    def __call__(self, func):
        if self.name is not None:
            func.__name__ = self.name
        func.__qualname__ = f'{self.cls.__qualname__}.{func.__name__}'
        func.__module__ = self.cls.__module__
        setattr(self.cls, func.__name__, func)
        return func

class Foo:
    pass

@instance_method_of(Foo)
def func(self):
    pass

【问题讨论】:

    标签: python python-3.x class methods monkeypatching


    【解决方案1】:

    它似乎涵盖了一切!虽然我会使用像这样的函数装饰器:

    from pathlib import Path
    
    def patch(f):
        cls = next(iter(f.__annotations__.values()))
        name = f.__defaults__[0]
        f.__qualname__ = f"{cls.__name__}.{f.__name__}"
        f.__module__ = cls.__module__
        if name is None:
            setattr(cls,f.__name__,f)
        else:
            f.__qualname__ = f"{cls.__name__}.{name}"
            setattr(cls,name,f)
        return f
    
    @patch
    def new(self:Path, name:str=None):
        "new"
        return list(self.iterdir())
    
    path = Path()
    path.new()
    

    大部分改编自fastai版本

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-24
      • 2016-06-15
      • 2019-10-27
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      相关资源
      最近更新 更多