【问题标题】:Python method that returns instance of class or subclass while keeping subclass attributes返回类或子类实例同时保留子类属性的Python方法
【发布时间】:2022-12-10 16:26:43
【问题描述】:

我正在编写一个 Python 类 A,方法 square() 返回该类的一个新实例,其第一个属性为平方。例如:

class A:
    def __init__(self, x):
        self.x = x

    def square(self):
        return self.__class__(self.x**2)

我想在子类 B 中使用此方法,以便它返回 B 的实例,其中 x 是平方的,但 B 的所有附加属性不变(即从实例中获取)。我可以通过像这样覆盖square()来让它工作:

class B(A):
    def __init__(self, x, y):
        super(B, self).__init__(x)
        self.y = y

    def square(self):
        return self.__class__(self.x**2, self.y)

如果我不覆盖 square() 方法,这个小代码示例将失败,因为我需要在 B 的构造函数中为 y 传递一个值:

#test.py

class A:
    def __init__(self, x):
        self.x = x 

    def square(self):
        return self.__class__(self.x**2)

class B(A):
    def __init__(self, x, y):
        super(B, self).__init__(x)
        self.y = y 

    #def square(self):
    #    return self.__class__(self.x**2, self.y)

a = A(3)
a2 = a.square()
print(a2.x)
b = B(4, 5)
b2 = b.square()
print(b2.x, b2.y)
$ python test.py
9
Traceback (most recent call last):
  File "test.py", line 20, in <module>
    b2 = b.square()
  File "test.py", line 6, in square
    return self.__class__(self.x**2)
TypeError: __init__() takes exactly 3 arguments (2 given)

覆盖该方法一次不是问题。但是 A 可能有多个类似于 square() 的方法,并且可能有更多的子(子)类。如果可能的话,我想避免覆盖所有这些子类中的所有这些方法。

所以我的问题是: 我能否以某种方式在A 中实现方法square(),以便它返回当前子类的新实例,其中包含x 平方以及从self 获取的构造函数所需的所有其他属性(保持不变)?还是我必须继续为每个子类覆盖square()

提前致谢!

【问题讨论】:

  • 简而言之:如果您需要构造一个新实例,那么您需要向该新实例传递它需要实例化的所有参数,如果您实例化的那个类有所不同,那么是的,每个子类都必须重写根据需要自定义它的方法。没有真正的捷径,除非您的类非常可预测并遵循某些模式,因此可以自动读取现有属性并将它们作为 kwargs 传递给构造函数。

标签: python inheritance overwrite


【解决方案1】:

我建议为这两个类实施.__copy__()(也可能是.__deepcopy__)方法。

然后你的squared可以是简单的方法:

def squared(self):
    newObj = copy(self)
    newObj.x = self.x **2
    return newObj

假设所有子类都正确实现了 __copy__ 方法,它将与继承一起工作。

编辑:通过调用 copy() 修复了拼写错误

完整的工作示例:

#test.py

from copy import copy


class A:
    def __init__(self, x):
        self.x = x 

    def square(self):
        newObj = copy(self)
        newObj.x = self.x **2
        return newObj

    def __copy__(self):
        return A(self.x)

class B(A):
    def __init__(self, x, y):
        super(B, self).__init__(x)
        self.y = y 

    def __copy__(self):
        return B(self.x, self.y)

a = A(3)
a2 = a.square()
print(a2.x)
b = B(4, 5)
b2 = b.square()
print(b2.x, b2.y)

【讨论】:

  • 这是一个非常方便的解决方案,它非常适合我正在做的事情!如果我有更多的声誉,我会投票支持它。非常感谢!
【解决方案2】:

检查对象是否包含 y 然后返回正确的类实例:

class A:
    x: int
    def __init__(self, x):
        self.x = x

    def square(self):
        if hasattr(self, 'y'):
            return self.__class__(self.x ** 2, self.y)
        
        return self.__class__(self.x**2)


class B(A):
    y: int
    def __init__(self, x, y):
        super(B, self).__init__(x)
        self.y = y

    # def square(self):
    #     return self.__class__(self.x**2, self.y)

【讨论】:

  • 您要检查子类可能具有的所有其他可能属性吗?
猜你喜欢
  • 2015-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多