Python:相互依赖的类

时间:2020-07-01 20:33:27

标签: python python-2.7 inheritance

我正在尝试创建一组类,其中每个类都有相应的类的“数组”版本。但是,我需要两个类都相互了解。这是一个工作示例,以演示我正在尝试做的事情。但这需要在每个类中复制一个“ to_array”。在我的实际示例中,即使唯一的区别是“ BaseArray”,“ PointArray”或“ LineArray”,也需要重复其他更复杂的方法。类似地,BaseArray类将具有仅“ BaseObj”,“ PointObj”或“ LineObj”不同的方法。

# ------------------
# Base object types
# ------------------
class BaseObj(object):
    def __init__(self, obj):
        self.obj = obj
    def to_array(self):
        return BaseArray([self])

class Point(BaseObj):
    def to_array(self):
        return PointArray([self])

class Line(BaseObj):
    def to_array(self):
        return LineArray([self])

# ------------------
# Array object types
# ------------------
class BaseArray(object):
    def __init__(self, items):
        self.items = [BaseObj(i) for i in items]

class PointArray(BaseArray):
    def __init__(self, items):
        self.items = [Point(i) for i in items]

class LineArray(BaseArray):
    def __init__(self, items):
        self.items = [Line(i) for i in items]

# ------------------
# Testing....
# ------------------

p = Point([1])
print(p)
pa = p.to_array()
print(pa)
print(pa.items)

这是我的尝试,可以理解的是会引起一个错误。我知道为什么会收到NameError,因此我知道为什么这不起作用。我正在显示这是为了弄清楚我想做什么。

# ------------------
# Base object types
# ------------------
class BaseObj(object):
    ArrayClass = BaseArray
    def __init__(self, obj):
        self.obj = obj
    def to_array(self):
        # By using the "ArrayClass" class attribute here, I can have a single
        # "to_array" function on this base class without needing to
        # re-implement this function on each subclass
        return self.ArrayClass([self])
    # In the actual application, there would be other BaseObj methods that
    # would use self.ArrayClass to avoid code duplication

class Point(BaseObj):
    ArrayClass = PointArray

class Line(BaseObj):
    ArrayClass = LineArray

# ------------------
# Array object types
# ------------------
class BaseArray(object):
    BaseType = BaseObj
    def __init__(self, items):
        self.items = [self.BaseType(i) for i in items]
    # In the actual application, there would be other BaseArray methods that
    # would use self.BaseType to avoid code duplication

class PointArray(BaseArray):
    BaseType = Point

class LineArray(BaseArray):
    BaseType = Line

# ------------------
# Testing....
# ------------------

p = Point([1])
print(p)
pa = p.to_array()
print(pa)
print(pa.items)

一种可能的解决方案是仅对所有类将“ ArrayClass”定义为“无”,然后在定义“数组”版本之后,您可以像这样对原始类进行猴子修补:

BaseObj.ArrayClass = BaseArray
Point.ArrayClass = PointArray
Line.ArrayClass = LineArray

这可行,但是感觉有点不自然,我怀疑有更好的方法来实现。万一重要,我的用例最终将是(仍然)仍然使用Python 2.7的程序的插件,因此我需要一个使用Python 2.7的解决方案。理想情况下,相同的解决方案可以在2.7和3+中运行。

1 个答案:

答案 0 :(得分:0)

这里是使用装饰器的解决方案。我更喜欢使用类属性分配(如我所说的“ monkey patch”),因为它可以使事情保持一致和清晰。我对此很满意,但仍然对其他想法感兴趣...

# ------------------
# Base object types
# ------------------
class BaseObj(object):
    ArrayClass = None
    def __init__(self, obj):
        self.obj = obj
    def to_array(self):
        # By using the "ArrayClass" class attribute here, I can have a single
        # "to_array" function on this base class without needing to
        # re-implement this function on each subclass
        return self.ArrayClass([self])
    # In the actual application, there would be other BaseObj methods that
    # would use self.ArrayClass to avoid code duplication

    @classmethod
    def register_array(cls):
        def decorator(subclass):
          cls.ArrayClass = subclass
          subclass.BaseType = cls
          return subclass
        return decorator

class Point(BaseObj):
    pass

class Line(BaseObj):
    pass

# ------------------
# Array object types
# ------------------
class BaseArray(object):
    BaseType = None
    def __init__(self, items):
        self.items = [self.BaseType(i) for i in items]
    # In the actual application, there would be other BaseArray methods that
    # would use self.BaseType to avoid code duplication

@Point.register_array()
class PointArray(BaseArray):
    pass

@Line.register_array()
class LineArray(BaseArray):
    pass

# ------------------
# Testing....
# ------------------

p = Point([1])
print(p)
pa = p.to_array()
print(pa)
print(pa.items)