Python: Что-то не так с динамическим назначением методов экземпляра в качестве атрибутов экземпляра - PullRequest
9 голосов
/ 18 августа 2011

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

from functools import wraps

def logging_decorator(tricky_instance):
    def wrapper(fn):
        @wraps(fn)
        def wrapped(*a, **kw):
            if tricky_instance.log:
                print("Calling %s.." % fn.__name__)
            return fn(*a, **kw)
        return wrapped
    return wrapper     

class Tricky(object):
    def __init__(self, log):
        self.log = log
        self.say_hi = logging_decorator(self)(self.say_hi)

    def say_hi(self):
       print("Hello, world!")


i1 = Tricky(log=True)
i2 = Tricky(log=False)

i1.say_hi()
i2.say_hi()

Это, кажется, работает отлично, но я боюсь, что я мог пропустить некоторые непреднамеренные побочные эффекты этого трюка. Я собираюсь выстрелить себе в ногу, или это безопасно?

Обратите внимание, что я на самом деле не хочу использовать это для регистрации, это просто кратчайший значимый пример, который я могу придумать.

Ответы [ 2 ]

4 голосов
/ 18 августа 2011

Мне не совсем понятно, почему вы бы хотели это сделать. Если вы хотите назначить новый тип метода динамически, используйте types:

import types

class Tricky(object):
    def __init__(self):
        def method(self):
            print('Hello')
        self.method = types.MethodType(method, self)

Если вы хотите что-то сделать с экземпляром, сделайте это методом __init__. Если вы просто хотите получить доступ к экземпляру метода внутри декоратора, вы можете использовать атрибут im_self:

def decorator(tricky_instance):
    def wrapper(meth):
        print(meth.im_self == tricky_instance)
        return meth
    return wrapper

Лично я думаю, что это поворот в землю «Может быть, я не должен использовать».

2 голосов
/ 18 августа 2011

Я думаю, что пытался быть излишне умным. Похоже, что решение смущает проще:

from functools import wraps

def logging_decorator(fn):
    @wraps(fn)
    def wrapped(self, *a, **kw):
        if self.log:
            print("Calling %s.." % fn.__name__)
        return fn(self, *a, **kw)
    return wrapped

class Tricky(object):
    def __init__(self, log):
        self.log = log

    @logging_decorator
    def say_hi(self):
       print("Hello, world!")

i1 = Tricky(log=True)
i2 = Tricky(log=False)

i1.say_hi()
i2.say_hi()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...