获取由 class 的装饰器标记的所有函数
get all functions marked by decorator of a class
我正在尝试存储在 class 中定义的特定 actions
。
为了减少代码重复,我想使用 mixin
class 来存储基于装饰器的所有操作。
这个想法是,其他人应该可以直接使用新操作来扩展 classes。我特别想避免在源代码中明确列出这些操作(这应该由装饰器处理)。
这是我想到的。不幸的是,在所有 .actions
列表中,列出了来自所有 class 的所有操作。
但是,我想要一个解决方案,只列出特定 class 的操作。
class ActionMixin:
actions = []
@staticmethod
def action(fun):
ActionMixin.actions.append(fun)
return fun
class Human(ActionMixin):
@ActionMixin.action
def talk(self):
pass
class Dog(ActionMixin):
@ActionMixin.action
def wuff(self):
pass
class Cat(ActionMixin):
@ActionMixin.action
def miau(self):
pass
if __name__ == "__main__":
party = [Human(), Dog()]
possible_actions = [action for memer in party for action in member.actions]
# I would like that possible_actions is now only Human.talk() and Dog.wuff()
# instead it is 2 times all actions
print(len(possible_actions)) # == 6
我会在这里写我自己的描述符。所以:
class Registry:
def __init__(self):
self._registered = []
def __call__(self, func):
self._registered.append(func)
return func
def __get__(self, obj, objtype=None):
return self._registered
class Human:
actions = Registry()
@actions
def talk(self):
pass
class Dog:
actions = Registry()
@actions
def wuff(self):
pass
class Cat:
actions = Registry()
@actions
def miau(self):
pass
因此,不是从混合宏继承,而是初始化描述符对象。然后该对象本身可以用作装饰器(__call__
方法!)。
请注意,装饰器可以是您为其指定的任何名称,它可以是存储操作的属性的名称。
在 REPL 中:
In [11]: party = [Human(), Dog()]
In [12]: [action for member in party for action in member.actions]
Out[12]: [<function __main__.Human.talk(self)>, <function __main__.Dog.wuff(self)>]
编辑:
如果您希望它存在于基础中,则必须更改实现 class。基本上,使用 dict
来跟踪注册表,不幸的是,我们必须依靠脆弱的 __qualname__
来获取 __call__
中的 class:
class ActionsRegistry:
def __init__(self):
self._registry = {}
def __call__(self, func):
klass_name, func_name = func.__qualname__.rsplit('.', 1)
if klass_name not in self._registry:
self._registry[klass_name] = []
self._registry[klass_name].append(func)
return func
def __get__(self, obj, objtype=None):
if obj is None:
return self
return self._registry[objtype.__qualname__]
class Base:
actions = ActionsRegistry()
class Human(Base):
@Base.actions
def talk(self):
pass
class Dog(Base):
@Base.actions
def wuff(self):
pass
class Cat(Base):
@Base.actions
def miau(self):
pass
我正在尝试存储在 class 中定义的特定 actions
。
为了减少代码重复,我想使用 mixin
class 来存储基于装饰器的所有操作。
这个想法是,其他人应该可以直接使用新操作来扩展 classes。我特别想避免在源代码中明确列出这些操作(这应该由装饰器处理)。
这是我想到的。不幸的是,在所有 .actions
列表中,列出了来自所有 class 的所有操作。
但是,我想要一个解决方案,只列出特定 class 的操作。
class ActionMixin:
actions = []
@staticmethod
def action(fun):
ActionMixin.actions.append(fun)
return fun
class Human(ActionMixin):
@ActionMixin.action
def talk(self):
pass
class Dog(ActionMixin):
@ActionMixin.action
def wuff(self):
pass
class Cat(ActionMixin):
@ActionMixin.action
def miau(self):
pass
if __name__ == "__main__":
party = [Human(), Dog()]
possible_actions = [action for memer in party for action in member.actions]
# I would like that possible_actions is now only Human.talk() and Dog.wuff()
# instead it is 2 times all actions
print(len(possible_actions)) # == 6
我会在这里写我自己的描述符。所以:
class Registry:
def __init__(self):
self._registered = []
def __call__(self, func):
self._registered.append(func)
return func
def __get__(self, obj, objtype=None):
return self._registered
class Human:
actions = Registry()
@actions
def talk(self):
pass
class Dog:
actions = Registry()
@actions
def wuff(self):
pass
class Cat:
actions = Registry()
@actions
def miau(self):
pass
因此,不是从混合宏继承,而是初始化描述符对象。然后该对象本身可以用作装饰器(__call__
方法!)。
请注意,装饰器可以是您为其指定的任何名称,它可以是存储操作的属性的名称。
在 REPL 中:
In [11]: party = [Human(), Dog()]
In [12]: [action for member in party for action in member.actions]
Out[12]: [<function __main__.Human.talk(self)>, <function __main__.Dog.wuff(self)>]
编辑:
如果您希望它存在于基础中,则必须更改实现 class。基本上,使用 dict
来跟踪注册表,不幸的是,我们必须依靠脆弱的 __qualname__
来获取 __call__
中的 class:
class ActionsRegistry:
def __init__(self):
self._registry = {}
def __call__(self, func):
klass_name, func_name = func.__qualname__.rsplit('.', 1)
if klass_name not in self._registry:
self._registry[klass_name] = []
self._registry[klass_name].append(func)
return func
def __get__(self, obj, objtype=None):
if obj is None:
return self
return self._registry[objtype.__qualname__]
class Base:
actions = ActionsRegistry()
class Human(Base):
@Base.actions
def talk(self):
pass
class Dog(Base):
@Base.actions
def wuff(self):
pass
class Cat(Base):
@Base.actions
def miau(self):
pass