我可以从 python 中的方法装饰器编辑 class 变量吗?
Can I edit a class variable from a method decorator in python?
我有一个class如下:
class Hamburger():
topping_methods = {}
@prepare_topping("burger", "onion_ring")
def cook(self, stuff, temp):
print("cooking")
h = Hamburger()
我希望 prepare_topping 装饰器在 Hamburger.topping_methods
中添加条目,使其看起来像:
{"burger":< cook method reference >, "onion_ring": < cook method reference >}
关键是我需要在 之前 class 的初始值设定项是 运行(真正的用例是 dict用于在初始化程序中注册事件回调。)但是因为我想访问 class 变量,所以它需要在定义 class 之后。
这是我对装饰器逻辑的了解:
def prepare_topping(*args):
def deco(func):
# This is when I want to add to class dict, but cannot access method arguments yet
print(eval(func.__qualname__.split(".")[0]).topping_methods) # Gets class that method belongs to in a hacky way, but the class is not yet defined
def wrapper(self, *args):
print(self.topping_methods) # Only run if the method is called, which is after __init__
return func(self, *args)
return wrapper
return deco
我意识到我永远无法访问方法 self
参数来实现此目的,因为无论该方法是否实际被调用,我都想做一些事情。有没有一种方法可以让装饰器 运行 只有在 class 被定义之后?在仍然使用装饰器的同时,还有其他方法可以实现这一点吗?
您可以使用超类和 __init_subclass__
钩子来连接:
class CookeryClass:
topping_methods: dict
def __init_subclass__(cls, **kwargs):
cls.topping_methods = {}
for obj in vars(cls).values():
if hasattr(obj, "topping_keys"):
for key in obj.topping_keys:
cls.topping_methods[key] = obj
def prepare_topping(*keys):
def decorator(func):
func.topping_keys = keys
return func
return decorator
class Hamburger(CookeryClass):
@prepare_topping("burger", "onion_ring")
def cook(self, stuff, temp):
print("cooking")
@prepare_topping("mayonnaise", "pineapples")
def not_on_a_pizza_surely(self, stuff, temp):
print("cooking")
print(Hamburger.topping_methods)
这会打印出来
{
'burger': <function Hamburger.cook at 0x000001EA49D293A0>,
'onion_ring': <function Hamburger.cook at 0x000001EA49D293A0>,
'mayonnaise': <function Hamburger.not_on_a_pizza_surely at 0x000001EA49D29430>,
'pineapples': <function Hamburger.not_on_a_pizza_surely at 0x000001EA49D29430>,
}
我有一个class如下:
class Hamburger():
topping_methods = {}
@prepare_topping("burger", "onion_ring")
def cook(self, stuff, temp):
print("cooking")
h = Hamburger()
我希望 prepare_topping 装饰器在 Hamburger.topping_methods
中添加条目,使其看起来像:
{"burger":< cook method reference >, "onion_ring": < cook method reference >}
关键是我需要在 之前 class 的初始值设定项是 运行(真正的用例是 dict用于在初始化程序中注册事件回调。)但是因为我想访问 class 变量,所以它需要在定义 class 之后。
这是我对装饰器逻辑的了解:
def prepare_topping(*args):
def deco(func):
# This is when I want to add to class dict, but cannot access method arguments yet
print(eval(func.__qualname__.split(".")[0]).topping_methods) # Gets class that method belongs to in a hacky way, but the class is not yet defined
def wrapper(self, *args):
print(self.topping_methods) # Only run if the method is called, which is after __init__
return func(self, *args)
return wrapper
return deco
我意识到我永远无法访问方法 self
参数来实现此目的,因为无论该方法是否实际被调用,我都想做一些事情。有没有一种方法可以让装饰器 运行 只有在 class 被定义之后?在仍然使用装饰器的同时,还有其他方法可以实现这一点吗?
您可以使用超类和 __init_subclass__
钩子来连接:
class CookeryClass:
topping_methods: dict
def __init_subclass__(cls, **kwargs):
cls.topping_methods = {}
for obj in vars(cls).values():
if hasattr(obj, "topping_keys"):
for key in obj.topping_keys:
cls.topping_methods[key] = obj
def prepare_topping(*keys):
def decorator(func):
func.topping_keys = keys
return func
return decorator
class Hamburger(CookeryClass):
@prepare_topping("burger", "onion_ring")
def cook(self, stuff, temp):
print("cooking")
@prepare_topping("mayonnaise", "pineapples")
def not_on_a_pizza_surely(self, stuff, temp):
print("cooking")
print(Hamburger.topping_methods)
这会打印出来
{
'burger': <function Hamburger.cook at 0x000001EA49D293A0>,
'onion_ring': <function Hamburger.cook at 0x000001EA49D293A0>,
'mayonnaise': <function Hamburger.not_on_a_pizza_surely at 0x000001EA49D29430>,
'pineapples': <function Hamburger.not_on_a_pizza_surely at 0x000001EA49D29430>,
}