2011-08-18 30 views
9

我使用需要实例本身作为一个参数一个装饰想出了下面的代码来装饰实例方法:的Python:任何不妥动态分配的实例方法的实例属性

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() 

这似乎工作的伟大,但我担心我可能忽略了这个技巧的一些无意的副作用。我是要在脚下自杀吗?还是安全?

请注意,我实际上并不想将其用于日志记录,这只是我能想到的最短有意义的示例。

+0

看起来合法。恕我直言。 – Evpok

回答

2

我认为我试图变得不必要的聪明。似乎有一个令人尴尬的更简单的解决方案:

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() 
4

我不清楚为什么你会想要这样做。如果要设定新的方法类型动态地使用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 

就个人而言,我认为这是于水火到也许-I-Shouldn't-USE-装饰的土地。

+0

我想自动调用(临时)网络问题的实例方法,由异常表示。哪些异常是临时的,哪些是永久的取决于实际的实例(实例表示其一致性保证取决于存储位置的Amazon S3对象)。 – Nikratio

+0

我不明白你的代码的功能。你能详细说明一下吗? – Nikratio

+1

我的代码在'__init__'中创建了一个新的实例方法。我想你正在尝试编写一个装饰器,并且你希望装饰器能够访问正在装饰的方法的实例,以概括装饰器? – zeekay