请考虑以下代码:
class MyCustomDescriptor:
def __init__(self,foo):
self._foo = foo
def __call__(self,decorated_method):
# Here's my question... Is there any way to get a reference to the
# type (ClassA or ClassB) here?
return self
def __get__(self,instance,type):
# Clearly at this point I can get the type of the class.
# But it's too late, I would have liked
# to get it back in __call__.
return 10
class ClassA:
@MyCustomDescriptor(foo=1)
def some_value(self): pass
class ClassB:
@MyCustomDescriptor(foo=1)
def some_value(self): pass
我想要获得对类的引用的原因是我想使用修饰函数/方法向类中添加一些静态数据。我意识到这有些不典型,但对于我正在做的事情,它会有所帮助。
答案 - 无法完成。基于下面的响应之一,我从调用内部检查了堆栈,并且能够获得使用描述符的完全限定类(在我的示例中为ClassA或ClassB)。但是你不能将它变成一个类型/类,因为类型/类仍然被解析(或者在python中正确的术语)。换句话说,python遇到了ClassA并开始解析它。在解析它时,它会遇到描述符并调用init并调用描述符。 ClassA仍然没有完成解析。因此,无论您是否可以从调用中获取完全限定的模块/类名,您都无法将其转换为类型。
答案 0 :(得分:4)
在应用装饰器时,some_value
只是一个函数,而不是一个方法。所以,不,该函数无法知道它与特定类相关联。
有两种选择:
MyCustomDescriptor
(以及foo
)或some_value
。类装饰器看起来像这样:
def register(method_name,foo):
def class_decorator(cls):
method=getattr(cls,method_name)
class MyCustomDescriptor(object):
def __get__(self,instance,type):
result=method(instance)
return '{c}: {r}'.format(c=cls.__name__,r=result)
setattr(cls,method_name,MyCustomDescriptor())
return cls
return class_decorator
@register('some_value',foo=1)
class ClassA:
def some_value(self):
return 10
例如,运行
a=ClassA()
print(a.some_value)
产量
ClassA: 10
答案 1 :(得分:1)
嗯......有一种我能想到的方法,但它有资格作为我喜欢称之为“Python voodoo”的东西,这意味着它正在访问不应该用于普通编程的Python特性。所以在你这样做之前仔细考虑。它也是依赖于实现的,所以如果你希望你的代码可以移植到其他Python解释器(CPython除外),请不要依赖它。话虽如此:
当调用描述符的__call__
方法时,您可以使用inspect.stack()
访问解释器堆栈。返回列表中的第二个堆栈帧表示调用__call__
的上下文。该堆栈框架中包含的部分信息是上下文名称,通常是函数名称,但在这种情况下,__call__
未从函数内部调用,它是从类内部调用的,因此上下文name将是该类的名称。
import inspect
class MyCustomDescriptor:
def __call__(self,decorated_method):
self.caller_name = inspect.stack()[1][3]
return self
...