我已经想了好几个小时了。我有一个类,它最终需要(但不会初始化(一些关键属性。此类的子类需要不同的属性。
如果有帮助的话,这是半边数据结构中的顶点、边和面的基本MeshElement类。
通常,我需要创建一个与另一个实例相似但不相同的istance,所以我有下面的borrow_b
这样的方法,可以将属性从一个实例复制到另一个。
我无法想出一个borrow_b
构造函数,它a(保留/复制了来自init的类型提示,b(可以由具有不同必需属性的子类继承。
这是我有过的最理智的想法,但它打破了"修改对象的方法返回None"的规则
class AB:
def __init__(self, a: Optional[int] = None, b: Optional[int] = None):
if a is not None:
self.a = a
if b is not None:
self.b = b
def borrow_b(self, other):
self.b = other.b # already type hinted when other was initialized
return self
# >>> one_two = AB(1, 2)
# >>> six_two = AB(6).borrow_b(one_two)
我当然意识到这可以分为两条线:
six_two = AB(6)
six_two.borrow_b(one_two)
并允许borrow_b
返回None,但我喜欢第一个看起来更像构造函数,而且我不相信第一个不是"Python">
当然,有更好的解决方案。
FWIW,
six_two = AB(6, six_two.b)
不是一个"可行"的解决方案,因为不是所有我想复制的属性都是"必需的"。我通常想复制一些必需的参数加上通常但不一定附加到网格元素(颜色、紫外线、硬度等(的杂项标记。
使用类方法来实现备用构造函数。对象的目的是跨多个方法调用或函数边界保持状态;创建一个只在一个范围内使用并立即丢弃的对象表明,您首先只需要一个具有适当参数的函数。
class AB:
def __init__(self, a: Optional[int] = None, b: Optional[int] = None):
if a is not None:
self.a = a
if b is not None:
self.b = b
@classmethod
def borrow_b(cls, o1: AB, o2: AB):
return cls(o1.a, o2.b)
one_two = AB(1, 2)
six = AB(6)
six_two = AB.borrow_b(one_two, six)
是的,创建six
似乎只是为了初始化six_two
,但可能由于其他原因它已经存在了。否则,您可以定义一个类方法,该方法专门接受一个对象和任意一组其他参数来覆盖"原型"。类似的东西
@classmethod
def make_from_prototype(cls, prototype, **kwargs):
new_obj = cls(prototype.a, prototype.b)
for attr, value in kwargs:
setattr(new_obj, attr, value)
return new_obj
...
one_two = AB(1,2)
six_two = AB.make_from_prototype(one_two, b=6)
一个缺点是make_from_prototype
绕过了类型提示,因为**kwargs
可以采用任意一组关键字参数。最好用作专用类方法,仅用作borrow_b
:等专用类方法的基本实现
@classmethod
def _make_from_prototype(cls, prototype: AB, **kwargs):
# Same definition as above
@classmethod
def borrow_b(cls, o1: AB, o2:AB):
return cls._make_from_prototype(o1, b=o2.b)