Python 可以访问类及其祖先的绑定方法上的装饰器

Python 可以访问类及其祖先的绑定方法上的装饰器,python,class,reflection,decorator,python-decorators,Python,Class,Reflection,Decorator,Python Decorators,当我在Python类中修饰绑定方法时,我需要从外部类中获取这个修饰器中的一些信息。可能吗 例如: def modifier(func): import sys cls_namespace = sys._getframe(1).f_locals cls_namespace['data'] # dictonary has no key 'data' ... return func class Parent: data = "Hi!" class

当我在Python类中修饰绑定方法时,我需要从外部类中获取这个修饰器中的一些信息。可能吗

例如:

def modifier(func):
    import sys
    cls_namespace = sys._getframe(1).f_locals
    cls_namespace['data']  # dictonary has no key 'data'
    ...
    return func

class Parent:
    data = "Hi!"

class Child(Parent):

    @modifier
    def method(self):
        pass
def modifier(cls):
    # cls is the newly created class object, including class attributes
    cls.data
    return cls

@modifier
class Child(Parent):
    def method(self):
        pass
def decorator(func):
    @wraps(func)
    def inner(self, *args, **kwargs):
        cls = self.__class__  # bound and straight-forward
        ...

    def extra(*args, **kwargs):
        cls = func.im_class  # Not bound
        ...

    inner.extra = extra

    return inner
cls\u名称空间
只是当前类的不完整名称空间,没有我需要获取的
数据
字段


有没有办法在decorator中获得它?

函数修饰在执行类主体时发生,此时对类本身或其基类一无所知。这意味着
modifier
装饰未绑定的函数对象,并且只有在实例上实际调用
func
时才会绑定该对象

您可以返回一个包装函数来替换修饰后的函数,它将被绑定,您可以访问
self

from functools import wraps

def modifier(func):
    @wraps(func)
    def wrapper(self, *args, **kwargs):
        # self is an instance of the class
        self.data
        return func(self, *args, **kwargs)
    return wrapper
然后,每次对实例调用
方法
时,都会调用包装器

如果必须在类创建时访问基类,则必须等待
类子语句
完成执行。在Python3.6之前,这只能通过类装饰器或元类实现;在创建类主体之后,将调用每个类,并且您将有权(至少)访问基类

使用类装饰器,例如:

def modifier(func):
    import sys
    cls_namespace = sys._getframe(1).f_locals
    cls_namespace['data']  # dictonary has no key 'data'
    ...
    return func

class Parent:
    data = "Hi!"

class Child(Parent):

    @modifier
    def method(self):
        pass
def modifier(cls):
    # cls is the newly created class object, including class attributes
    cls.data
    return cls

@modifier
class Child(Parent):
    def method(self):
        pass
def decorator(func):
    @wraps(func)
    def inner(self, *args, **kwargs):
        cls = self.__class__  # bound and straight-forward
        ...

    def extra(*args, **kwargs):
        cls = func.im_class  # Not bound
        ...

    inner.extra = extra

    return inner
现在请注意装饰器的位置

Python3.6添加了一个也可以为您提供这种访问的接口;每次为当前类创建子类时,都会调用(类)方法:

class Parent:
    def __init_subclass__(cls, **kwargs):
        # cls is a subclass of Parent
        super().__init_subclass__(**kwargs)
        cls.data

    data = "Hi!"

class Child(Parent):
    def method(self):
        pass

并不是说传递给装饰器包装器的第一个参数就是对象实例(
self
)。由于它,您可以访问w=您需要的所有内容

见拉斐尔的答复:


self是第一个参数

这是一个特别均衡的解决方案:

def wrap_class(cls):
    """Wrap a class to allow binding all decorated methods."""
    for func in cls.__dict__.values():
        if hasattr(func, '__wrapped__'):
            func.__wrapped__.im_class = cls

    return cls
要求您使用
@functools.wrapps(func)
,然后使用
@wrapps\u class
装饰类

装饰器示例:

def modifier(func):
    import sys
    cls_namespace = sys._getframe(1).f_locals
    cls_namespace['data']  # dictonary has no key 'data'
    ...
    return func

class Parent:
    data = "Hi!"

class Child(Parent):

    @modifier
    def method(self):
        pass
def modifier(cls):
    # cls is the newly created class object, including class attributes
    cls.data
    return cls

@modifier
class Child(Parent):
    def method(self):
        pass
def decorator(func):
    @wraps(func)
    def inner(self, *args, **kwargs):
        cls = self.__class__  # bound and straight-forward
        ...

    def extra(*args, **kwargs):
        cls = func.im_class  # Not bound
        ...

    inner.extra = extra

    return inner
用法示例:

@wrap_class
class Badger:
    @decorator
    def stoat(self, mushroom, snake):
        pass

Badger().stoat()
Badger.stoat.extra()