如何使用 `functools.partial()` 将方法动态添加到 class

How to dynamically add method to class with `functools.partial()`

在以下情况下,我无法正确使用 functools.partial 将动态方法添加到 class。下面有一个Creator class,我想在其中添加一个create_someclass方法,它被creator class状态部分参数化。

import functools

class Creator:
    def __init__(self, params):
        self.params = params

class Stitch:
    __tablename__ = 'stitch'
    def __init__(self, params, name):
        self.name = name
        self.params = params

def create(self, clz, *args, **kwargs):
    return clz(self.params, *args, **kwargs)

for clazz in [Stitch]:
    setattr(Creator, 'create_%s' % clazz.__tablename__, functools.partial(create, clz=clazz))

creator = Creator('params')

# Neither of these work, but I'd like either one -- preferably the first one.

stitch = creator.create_stitch('myname')
# AttributeError: 'str' object has no attribute 'params'

stitch = creator.create_stitch(name='myname')  
# TypeError: create() missing 1 required positional argument: 'self'

这是为 class 方法制作 partial 的问题,因此在 Python 3.4 中我们引入了 partialmethod 作为替代方法。工作方式如下:

import functools

class Creator:
    def __init__(self, params):
        self.params = params

class Stitch:
    __tablename__ = 'stitch'
    def __init__(self, params, name):
        self.name = name
        self.params = params

def create(self, clz, *args, **kwargs):
    return clz(self.params, *args, **kwargs)

for clazz in [Stitch]:
    setattr(Creator, 'create_%s' % clazz.__tablename__, functools.partialmethod(create, clz=clazz))
    # use partialmethod instead here

creator = Creator('params')

stitch = creator.create_stitch(name='myname')  
# works!

我认为问题在于 create 是 Stitch 的成员函数(尽管你的缩进错误:create 访问了 Stitch 的成员变量 params),所以你需要一个 Stitch 类型的对象来与 create 一起使用,然后它也将作为第一个参数传递给 create。它会像这样工作:

import functools


class Creator:
    def __init__(self, params):
        self.params = params

class Stitch:
    __tablename__ = 'stitch'
    def __init__(self, params, name):
        self.name = name
        self.params = params

    def create(self, clz, *args, **kwargs):
        return clz(self.params, *args, **kwargs)


creator = Creator('params')
stitch1 = Stitch('pp', 'my_name')
print("stitch1= ", stitch1)

for clazz in [Stitch]:
    setattr(Creator, 'create_%s' % clazz.__tablename__, functools.partial(stitch1.create, clazz))

stitch = creator.create_stitch('myname')
print("stitch= ", stitch)