在Python3.1的类构造过程中,如何找到绑定方法的类?
我想编写一个装饰器,使类的方法对其他方可见;然而,我所描述的问题与细节无关。代码大致如下所示:在Python3.1的类构造过程中,如何找到绑定方法的类?,python,python-3.x,Python,Python 3.x,我想编写一个装饰器,使类的方法对其他方可见;然而,我所描述的问题与细节无关。代码大致如下所示: def CLASS_WHERE_METHOD_IS_DEFINED( method ): ??? def foobar( method ): print( CLASS_WHERE_METHOD_IS_DEFINED( method ) ) class X: @foobar def f( self, x ): return x ** 2 我这里的问题是,当装饰程序foob
def CLASS_WHERE_METHOD_IS_DEFINED( method ):
???
def foobar( method ):
print( CLASS_WHERE_METHOD_IS_DEFINED( method ) )
class X:
@foobar
def f( self, x ):
return x ** 2
我这里的问题是,当装饰程序foobar()
看到该方法时,它还不可调用;相反,它会看到它的一个未绑定版本。也许这可以通过在类上使用另一个decorator来解决,这个decorator将负责对绑定方法所做的任何事情。下一步我将尝试做的是,在装饰方法通过装饰器时,简单地用属性标记装饰方法,然后使用类装饰器或元类来进行后处理。如果我能做到这一点,那么我就不必解开这个谜语,这个谜语仍然困扰着我:
在上面的代码中,任何人都可以在
CLASS\u下填写有意义的行,其中定义了\u方法\u
,这样装饰师就可以在定义f
的那一刻打印出定义了f
的类了吗?或者这种可能性在python 3中被排除了?当调用装饰器时,它是以一个函数作为参数而不是一个方法来调用的——因此,装饰器尽可能多地检查和反省它的方法将毫无用处,因为它只是一个函数,并且不携带任何关于封闭类的信息。我希望这能解决你的“谜语”,尽管是消极的
可能会尝试其他方法,例如对嵌套堆栈框架进行深度内省,但它们是粗糙的、脆弱的,肯定不会延续到其他Python 3实现中,例如pynie;因此,我衷心建议您避免使用它们,而使用您已经在考虑的类装饰器解决方案,它更干净、更可靠。这是一篇非常古老的文章,但内省并不是解决这个问题的方法,因为使用一点巧妙的类构造逻辑可以更轻松地解决这个问题 实现这一点的关键是元类——它搜索在它创建的类上定义的属性,以找到
foobar
描述符。一旦这样做了,它就会通过描述符的init_self
和init_cls
方法向他们传递有关他们所涉及的类的信息
init_self
仅对定义了描述符的类调用。这是应该对foobar
进行修改的地方,因为该方法只调用一次。而init_cls
是为所有有权访问修饰方法的类调用的。在这里可以引用对类foobar
的修改
import inspect
class MetaX(type):
def __init__(cls, name, bases, classdict):
# The classdict contains all the attributes
# defined on **this** class - no attribute in
# the classdict is inherited from a parent.
for k, v in classdict.items():
if isinstance(v, foobar):
v.init_self(k, cls)
# getmembers retrieves all attributes
# including those inherited from parents
for k, v in inspect.getmembers(cls):
if isinstance(v, foobar):
v.init_cls(cls)
例子
#兼容性
进口六
类X(六个,带有_元类(MetaX,object)):
定义初始化(自):
self.value=1
@福巴
def f(自身,x):
返回self.value+x**2
Y(X)级:及格
#印刷品:
#我的名字叫“f”,属于
#我存在于实例的mro中
#我存在于实例的mro中
打印('CLASS-CONSTRUCTION OVER\n')
打印(Y().f(3))
#印刷品:
# 10
正如我在一些文章中提到的,由于Python 3.6,这个问题的解决方案非常简单,因为它可以通过定义的类对象调用
我们可以使用它定义一个装饰器,该装饰器可以通过以下方式访问该类:
class\u装饰器:
定义初始化(self,fn):
self.fn=fn
定义设置名称(自身、所有者、名称):
#与“所有者”(即类)一起做某事
打印(f“装饰{self.fn}并使用{owner}”)
#然后用原来的方法代替我们自己
setattr(所有者、名称、self.fn)
然后可以用作普通装饰器:
>>A类:
... @高级装饰师
... def hello(self,x=42):
... 返回x
...
装饰与使用
>>>你好
如果我想把一些参数传递给装饰师怎么办?至少有两种方法可以做到:1。对参数使用\uuuu init\uuuu
,并定义一个\uuu调用(self,fn)
方法,该方法设置self.fn=fn
并返回self
。2.将整个class\u decorator
定义包装到另一个函数中,该函数接受您的参数并返回class\u decorator
。
import inspect
class MetaX(type):
def __init__(cls, name, bases, classdict):
# The classdict contains all the attributes
# defined on **this** class - no attribute in
# the classdict is inherited from a parent.
for k, v in classdict.items():
if isinstance(v, foobar):
v.init_self(k, cls)
# getmembers retrieves all attributes
# including those inherited from parents
for k, v in inspect.getmembers(cls):
if isinstance(v, foobar):
v.init_cls(cls)
# for compatibility
import six
class X(six.with_metaclass(MetaX, object)):
def __init__(self):
self.value = 1
@foobar
def f(self, x):
return self.value + x**2
class Y(X): pass
# PRINTS:
# I am named 'f' and owned by <class '__main__.X'>
# I exist in the mro of <class '__main__.X'> instances
# I exist in the mro of <class '__main__.Y'> instances
print('CLASS CONSTRUCTION OVER\n')
print(Y().f(3))
# PRINTS:
# 10