从不同的类扩展Python类的功能



我有许多Python类,例如,库/包中的Class1Class2Class3等。我想用一些常见的功能来扩展所有的类。如果我单独扩展每个类,我们会引入大量冗余,并打破";不要重复自己"缩略语因此,我的想法是拥有一个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...

因此,我们可以使用多重继承来扩展Class1Class2等。比如

class Class1(Class1, Base):
pass
class Class2(Class2, Base):
pass
# and so on...

这样,当我创建一个Class1Class2等对象时,我就可以使用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..

请解释如何实现Class1Class2等,以扩展Base类。

非常感谢您的帮助。非常感谢。

根据您的描述,您将有两种可能性来处理您的问题:

  1. 元类
  2. 装饰工

如果我是你,我会尝试这样的东西(装饰器解决方案(:

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_?

这里的区别在于test1test2不在实例中,而是在类本身中,这意味着如果您对这些类进行子类化,它们也将在新类的结构中。

哪个将是更好的解决方案取决于您的情况:(

当您有这样的继承设置时:

class MyClass1(Base, ExternalClass1):

调用super().__init__()将调用Base.__init__()(可能是第一个继承类(,因此仅初始化Base中的属性。您可以显式地调用同一继承上所有祖先的init函数;电平";像这样:

class MyClass1(Base, ExternalClass1):
def __init__(self) -> None:
Base.__init__(self)
ExternalClass1.__init__(self)

这将初始化来自BaseExternalClass1的属性。

示例:

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)

最新更新