Как динамически добавить метод в класс с помощью `functools.partial ()` - PullRequest
1 голос
/ 25 мая 2020

У меня возникли проблемы с правильным заклинанием для добавления метода Dynami c к классу с использованием functools.partial в следующей ситуации. Ниже приведен класс Creator, к которому я хочу добавить метод create_someclass, который частично параметризован состоянием класса creator.

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'

Ответы [ 2 ]

1 голос
/ 25 мая 2020

Это проблема при создании 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!
0 голосов
/ 25 мая 2020

Я думаю, проблема в том, что create является функцией-членом Stitch (несмотря на ваш плохой отступ: create обращается к переменной-члену params из Stitch), поэтому вам понадобится объект типа 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)
...