TL; DR Python 2.7.5,当使用描述符作为装饰器时,是否有任何方法可以传入参数(到__init__
方法)? 或 如何使用带参数的方法装饰器(as here)访问类实例的属性? - 我认为这是不可能的,不过,因此低于重点描述符...带参数的Python描述符?
龙版
我有一个类的对象,不同的“类型”属性。基于一个实例的“类型”,我想要一个方法可用或不可用。我知道一种方法是创建多个类,但是我试图在创建这些对象时没有一堆if/else语句。例如,我有两个对象A和B几乎相同,除了对象B我不想让get_start_date()
方法可用。所以基本上,我想要的是A和B都是类MyObjects的实例,但具有不同的“type”属性。
type(A) == type(B)
A.genus_type != B.genus_type
我会使用.genus_type
属性来区分哪些方法是允许的,哪些不是......
我想我可以用装饰用白名单,如:
def valid_for(whitelist):
def wrap(f):
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
return wrapper
return wrap
class A(object):
@valid_for(['typeB'])
def do_something_cool(self):
print 'blah'
但问题是我没有访问装饰器中的实际类实例,我可以在其中测试实例类型属性。根据this SO question,我想,“我可以使用描述符!”。
于是,我又试图:
class valid_for(object):
""" descriptor to check the type of an item, to see
if the method is valid for that type"""
def __init__(self, func):
self.f = func
def __get__(self, instance, owner):
def wrapper(*args):
return self.f(instance, *args)
return wrapper
但我无法弄清楚如何获得['typeB']
参数传递到默认的描述......,巨蟒通过在调用的方法作为参数__init__
。我可以为每种类型创建硬编码的描述符并嵌套它们,但是我不知道是否会碰到this problem。假设我可以克服嵌套问题,似乎也不太干净做这样的事情:
class A(object):
@valid_for_type_b
@valid_for_type_f
@valid_for_type_g
def do_something_cool(self):
print 'blah'
做这样的事情只是让我func
等于列表['typeB']
...
class valid_for(object):
""" descriptor to check the type of an item, to see
if the method is valid for that type"""
def __init__(self, func, *args):
self.f = func
def __get__(self, instance, owner):
def wrapper(*args):
return self.f(instance, *args)
return wrapper
class A(object):
@valid_for(['typeB'])
def do_something_cool(self):
print 'blah'
和我func
不在*args
列表中,所以我不能只做一个简单的参数交换(*args
为空)。
我一直在寻找提示here和here,但还没有找到任何看起来像干净或有效的解决方法。有没有一种干净的方式来做到这一点,还是我必须使用多个类,并混合各种方法?或者,现在我倾向于认为检查一个实例方法,但似乎不干净的,可重复使用...
class A(object):
def _valid_for(self, whitelist):
if self.genus_type not in whitelist:
raise Exception
def do_something_cool(self):
self._valid_for(['foo'])
print 'blah'
我使用Python 2.7.5。
更新1
每在评论一个建议,我想:
def valid_for2(whitelist):
def wrap(f):
def wrapper(*args, **kwargs):
import pdb
pdb.set_trace()
print args[0].genus_type
return f(*args, **kwargs)
return wrapper
return wrap
但在这一点上,ARGS [0]。只是返回参数:
(Pdb) args[0]
args = (<FormRecord object at 0x112f824d0>,)
kwargs = {}
(Pdb) args[0].genus_type
args = (<FormRecord object at 0x112f824d0>,)
kwargs = {}
但是,使用functools
建议的工作 - 所以我会奖励答案。在functools
似乎有一些黑魔法让参数在?
更新2
所以调查jonrsharpe的建议多,他的方法也似乎工作,但我要明确地使用self
代替args[0]
。不知道为什么行为是不同的...
def valid_for2(whitelist):
def wrap(f):
def wrapper(self, *args, **kwargs):
print self.genus_type
return f(*args, **kwargs)
return wrapper
return wrap
产生相同的输出与functools
。 谢谢!
呀,我试图与装饰 - 但一个装饰,我相信我能不能访问这个类实例的属性... – user
当然最大的问题是,当你装修方法,您无法访问方法所在的类?你可以在'wrapper'(它现在是'args [0]'''''''中测试'self'(因此测试'isinstance(self,...)'或'type(self)'),但是你可以明确地),但不能包含当前在“白名单”中定义的类。你将如何解决'typeB''到实际的课堂? – jonrsharpe
所以我的术语可能会令人困惑。当我使用'typeB'作为上面的例子时,它被定义为类实例的一个属性 - 比如B.genus_type ='typeB'。我希望一切都可以是一个类,所以键入(A)==类型(B),但是A.genus_type!= B.genus_type。 – user