Как добавить метод с использованием метакласса - PullRequest
8 голосов
/ 15 сентября 2008

Как добавить метод экземпляра в класс с помощью метакласса (да, мне нужно использовать метакласс)? Работает следующий вид, но func_name все равно будет "foo":

def bar(self):
    print "bar"

class MetaFoo(type):
    def __new__(cls, name, bases, dict):
        dict["foobar"] = bar
        return type(name, bases, dict)

class Foo(object):
    __metaclass__ = MetaFoo

>>> f = Foo()
>>> f.foobar()
bar
>>> f.foobar.func_name
'bar'

Моя проблема в том, что некоторый библиотечный код фактически использует func_name и позже не может найти метод 'bar' экземпляра Foo. Я мог бы сделать:

dict["foobar"] = types.FunctionType(bar.func_code, {}, "foobar")

Существует также types.MethodType, но мне нужен экземпляр, который еще не существует, чтобы использовать его. Я что-то здесь пропускаю?

Ответы [ 2 ]

15 голосов
/ 15 сентября 2008

Попробуйте динамически расширить базы таким образом, чтобы вы могли воспользоваться преимуществами mro, и методы являются реальными методами:

class Parent(object):
    def bar(self):
        print "bar"

class MetaFoo(type):
    def __new__(cls, name, bases, dict):
        return type(name, (Parent,) + bases, dict)

class Foo(object):
    __metaclass__ = MetaFoo

if __name__ == "__main__":
    f = Foo()
    f.bar()
    print f.bar.func_name
2 голосов
/ 15 сентября 2008

Я думаю, что вы хотите сделать это:

>>> class Foo():
...   def __init__(self, x):
...     self.x = x
... 
>>> def bar(self):
...   print 'bar:', self.x
... 
>>> bar.func_name = 'foobar'
>>> Foo.foobar = bar
>>> f = Foo(12)
>>> f.foobar()
bar: 12
>>> f.foobar.func_name
'foobar'

Теперь вы можете свободно передавать Foo s в библиотеку, которая ожидает, что Foo экземпляров будет иметь метод с именем foobar.

К сожалению, (1) я не знаю, как использовать метаклассы и (2) я не уверен, что правильно прочитал ваш вопрос, но надеюсь, что это поможет.

Обратите внимание, что func_name назначается только в Python 2.4 и выше.

...