我有许多Python类,例如,库/包中的Class1
、Class2
、Class3
等。我想用一些常见的功能来扩展所有的类。如果我单独扩展每个类,我们会引入大量冗余,并打破";不要重复自己"缩略语因此,我的想法是拥有一个Base
类,并使用它来扩展其他类。例如:
class Base:
def __init__(self):
# I want self.base_attr_1, self.base_attr_2 and so on...
def base_method_1(self, *args, **kwargs):
pass
def base_method_2(self, *args, **kwargs):
pass
# and so on...
因此,我们可以使用多重继承来扩展Class1
、Class2
等。比如
class Class1(Class1, Base):
pass
class Class2(Class2, Base):
pass
# and so on...
这样,当我创建一个Class1
、Class2
等对象时,我就可以使用Base
类的属性和方法了。喜欢
class_1 = Class1(*args, **kwargs)
print(class_1.base_attr_1)
print(class_1.base_attr_2)
class_1.base_method_1(*args, **kwargs)
class_2.base_method_2(*args, **kwargs)
# and so on..
请解释如何实现Class1
、Class2
等,以扩展Base
类。
非常感谢您的帮助。非常感谢。
根据您的描述,您将有两种可能性来处理您的问题:
- 元类
- 装饰工
如果我是你,我会尝试这样的东西(装饰器解决方案(:
from functools import wraps
def deco(cls):
def test(x):
return x**2
d = {k:v for k,v in locals().items() if k != "cls"}
@wraps(cls)
def wrapper(*args, **kwargs):
o = cls(*args, **kwargs)
#o.test = test # setattr(o,"test", test) will be better solution,
# if you have more elements, which you'd like to add
# generalized :
# ============
for k,v in d.items(): setattr(o,k,v)
return o
#Fast replacement of @wraps, but not exhaustive !
#wrapper.__doc__ = cls.__doc__
#wrapper.__name__ = cls.__name__
return wrapper
@deco
class A(object):
pass
a = A()
print(a.__dict__)
print(a.test(10))
结果:
{'test': <function test at 0x02843C70>}
100
如前所述,我的元类解决方案:
class MyMeta(type):
def __new__(cls, clsname, bases, clsdict):
def test1(self, x):
return x ** 2
def test2(self, x):
return x * 10
# filter the elements which aren't in the __new__ signature
tmp = {k: v for k, v in locals().items() if k not in ("cls", "clsname", "bases", "clsdict")}
for k, v in tmp.items(): clsdict[k] = v
return type.__new__(cls, clsname, bases, clsdict)
class A(object):
__metaclass__ = MyMeta
pass
a = A()
print(a.__dict__)
print(A.__dict__)
print(a.test1(10))
print(a.test2("ok_?"))
结果:
{}
{'test1': <function test1 at 0x029F73F0>, '__module__': '__main__', 'test2': <function test2 at 0x02A14BB0>, '__metaclass__': <class '__main__.MyMeta'>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
100
ok_?ok_?ok_?ok_?ok_?ok_?ok_?ok_?ok_?ok_?
这里的区别在于test1和test2不在实例中,而是在类本身中,这意味着如果您对这些类进行子类化,它们也将在新类的结构中。
哪个将是更好的解决方案取决于您的情况:(
当您有这样的继承设置时:
class MyClass1(Base, ExternalClass1):
调用super().__init__()
将调用Base.__init__()
(可能是第一个继承类(,因此仅初始化Base
中的属性。您可以显式地调用同一继承上所有祖先的init函数;电平";像这样:
class MyClass1(Base, ExternalClass1):
def __init__(self) -> None:
Base.__init__(self)
ExternalClass1.__init__(self)
这将初始化来自Base
和ExternalClass1
的属性。
示例:
class ExternalClass1():
def __init__(self) -> None:
self.external_attr_1 = "external attr"
def external_func1(self):
print("external_func1")
class Base():
def __init__(self) -> None:
self.base_attr_1 = "base attr"
def base_method_1(self):
print("base_method_1")
class MyClass1(Base, ExternalClass1):
def __init__(self) -> None:
Base.__init__(self)
ExternalClass1.__init__(self)
self.my_attr_1 = "my class attr"
self.external_func1()
self.base_method_1()
self.my_class_1_func()
print(self.external_attr_1)
print(self.base_attr_1)
print(self.my_attr_1)
def my_class_1_func(self):
print("my_class_1_func")
cl1 = MyClass1()
输出:
external_func1
base_method_1
my_class_1_func
external attr
base attr
my class attr
但是请注意,self
现在在所有3个类之间共享,这可能会导致冲突。另一种模式当然是使用composition,并将外部类作为MyClass1
的属性。这样既安全又减少了耦合。
编辑:如果需要相同的类名,那么可以用模块名引用它,但我认为这不是一个很好的做法。
import external
...
class MyClass1(Base, external.MyClass1):
def __init__(self) -> None:
Base.__init__(self)
external.MyClass1.__init__(self)