LINUX.ORG.RU

[python]динамическое добавление методов

 


0

1

Господа! Имею желание по переданному в конструктор списку параметров (a, b, c) создать в классе члены-функции - геттеры, т.е. класс должен содержать методы geta(), getb(), getc().

class createNewEntryClass:
    def __init__(self, args):

        for arg in args:
            argname = func = 'get' + arg
            def func():
                print arg
                print 'func: ', func, 'arg: ', argname
            print 'func: ', func, 'arg: ', argname
            setattr(self, argname, func)

argslist = ('a', 'b', 'c')
klass = createNewEntryClass(argslist)
print dir(klass)
klass.geta()
klass.getb()
klass.getc()
func:  <function func at 0xb7354764> arg:  geta
func:  <function func at 0xb7354df4> arg:  getb
func:  <function func at 0xb735a5a4> arg:  getc
['__doc__', '__init__', '__module__', 'geta', 'getb', 'getc']
c
func:  <function func at 0xb735a5a4> arg:  getc
c
func:  <function func at 0xb735a5a4> arg:  getc
c
func:  <function func at 0xb735a5a4> arg:  getc

В результате, как видно, вызывается все 3 раза getc()

Как решить правильно? Спасибо!


По-моему, собственно задачу добавления методов ты решил правильно, но нарвался на незаметные грабли - все твои func и должны печатать «getc», потому что к моменту их выполнения argname равно «getc».

У этого есть какой-то простой воркароунд, но я не могу его вспомнить сейчас :)

tailgunner ★★★★★
()

По быстрому не соображу, но ещё есть модуль new, у которого есть instancemethod. Может пригодится.

AlexKiriukha ★★★★
()

На крайний случай генерь текст функций и eval-ом его :). А тут выходит что self.geta, self.getb и self.getc ссылаются в одно место. У меня пока все попытки обхитрить питон(типа copy.deepcopy или del func в цикле чтобы inplace не правил) провалились :)

true_admin ★★★★★
()

Например так:


class getter(object):
    def __init__(self, self2, nm):
        self.nm = nm[:]
        self.slf = self2

    def __call__(self):
        print self.nm
        return getattr(self.slf, self.nm)

class createNewEntryClass(object):
    def __init__(self, args):
        for arg in args:
             argname = 'get' + arg
             setattr(self, argname, getter(self, argname))

argslist = ('a', 'b', 'c')
klass = createNewEntryClass(argslist)
print dir(klass)
klass.geta()
klass.getb()
klass.getc()

rymis ★★
()
Ответ на: комментарий от rymis

то есть:


class getter(object):
    def __init__(self, self2, nm):
        self.nm = nm[:]
        self.slf = self2

    def __call__(self):
        print getattr(self.slf, self.nm)
        return getattr(self.slf, self.nm)

class createNewEntryClass(object):
    def __init__(self, args):
        for arg in args:
             argname = 'get' + arg
             setattr(self, arg, argname)
             setattr(self, argname, getter(self, arg))

argslist = ('a', 'b', 'c')
klass = createNewEntryClass(argslist)
print dir(klass)
klass.geta()
klass.getb()
klass.getc()

['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'c', 'geta', 'getb', 'getc']
geta
getb
getc
rymis ★★
()
Ответ на: комментарий от Zubchick

Вообще все это от лукавого. Без понтов можно было сделать get(atr), вместо getatr(), геттер то все-равно один на всех.

Zubchick
()
Ответ на: комментарий от Zubchick

На самом деле - это упрощенный вариант, геттеры естественно разные будут...

najar
() автор топика
Ответ на: комментарий от najar

Точнее бкдет так:

Как уже сказали, не совсем хороший вариант. Лучше явно замкнуть нужные аргументы:

class Foo(object):
    def __init__(self, *args):
        def make_getter(arg):
            def func():
                print 'func: ', func, 'arg: ', arg

            return func

        for arg in args:
            setattr(self, 'get' + arg, make_getter(arg))


foo = Foo('a', 'b', 'c')

foo.geta()
foo.getb()
foo.getc()
baverman ★★★
()
Ответ на: комментарий от tailgunner

корявое, но универсальное, тем более в Питоне замыкания так и реализованы.

rymis ★★
()
Ответ на: комментарий от true_admin

Неявная передача аргумента через значение по-умолчанию. Возможность вызвать klass.geta('b'). Такой геттер нельзя обернуть в проперти. Значение аргумента это статическая информация, а в привиденном примере он передается каждый раз при вызове геттера, что намекает на кривизну.

baverman ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.