说明和我尝试过的操作:
我已经在stackoverflow中看到很多关于将方法绑定到类实例的文章(我知道已经有很多重复的东西)。
但是,我还没有找到有关将方法绑定到类本身的讨论。我能想到解决方法,但我很好奇是否有一种简单的方法可以实现以下目标:
import types
def quacks(some_class):
def quack(self, number_of_quacks):
self.number_of_quacks = number_of_quacks
setattr(some_class, "quack", types.MethodType(quack, some_class))
return some_class
@quacks
class Duck:
pass
但以上操作无效:
d1 = Duck()
d2 = Duck()
d1.quack(1)
d2.quack(2)
print(d2.number_of_quacks)
# 2
print(d1.number_of_quacks)
# 2
因为quack实际上是在修改类本身而不是实例。
我可以想到两种解决方法。如下所示:
class Duck:
def __init__(self):
setattr(self, "quack", types.MethodType(quack, self))
或类似的
class Quacks:
def quack(self, number_of_quacks):
self.number_of_quacks = number_of_quacks
class Duck(Quacks):
pass
问题:
所以我的问题是,有没有一种简单的方法来实现上面描述的简单的@quacks
类装饰器?
为什么要问: 我打算创建一组函数,以模块化方式添加用于类的常用方法。如果我不退出该项目,该列表可能会随着时间的推移而增长,我希望代码定义看起来不错。而且从口味上来说,我认为下面的选项1比选项2更好:
# option 1
@quacks
@walks
@has_wings
@is_white
@stuff
class Duck:
pass
# option 2
class Duck(
Quacks,
Walks,
HasWings,
IsWhite,
Stuff):
pass
答案 0 :(得分:1)
如果您不介意完全更改所需的语法以获取所需的功能,则可以使用type
动态构造类(请参见第二个签名)。
第一个参数是类的名称,第二个参数是超类的元组,第三个参数是要添加的属性的字典。
Duck = type("Duck", (), {
"quack", quack_function,
"walk", walk_function,
...
})
因此,您可以在创建时直接添加功能,而不是在创建后注入适当功能的装饰器。这种方法的优点在于,您可以以编程方式构建属性字典,而使用装饰器则不能。
答案 1 :(得分:0)
找到了另一个解决方法,我想下面会为我做。
def quacks(some_class):
def quack(self, number_of_quacks):
self.number_of_quacks = number_of_quacks
old__init__ = some_class.__init__
def new__init__(self, *args, **kwargs):
setattr(self, "quack", types.MethodType(quack, self))
old__init__(self, *args, **kwargs)
setattr(some_class, "__init__", new__init__)
return some_class
随时添加任何其他替代方法,或者如果您发现此方法有任何缺点。
编辑:一种受@SethMMorton回答启发的不那么骇人听闻的方式:
def quack(self, number_of_quacks):
self.number_of_quacks = number_of_quacks
def add_mixin(some_class, some_fn):
new_class = type(some_class.__name__, (some_class,), {
some_fn.__name__: some_fn
})
return new_class
def quacks(some_class):
return add_mixin(some_class, quack)
@quacks
class Duck:
pass
d1 = Duck()
d2 = Duck()
d1.quack(1)
d2.quack(2)
print(d1.number_of_quacks)
print(d2.number_of_quacks)