如何在
时创建有效的可重用模块在类和子类的上下文中,我的目标是:
各个类都有自己的逻辑,倾向于在模块中交互并创建彼此的实例 - 一切都很好。但是当我需要向类添加更多特定的子类方法时,这些方法不可用于模块中创建的实例。
以下是我遇到的一个例子:
==firstclass.py===
"""This is a reusable class within a module. It creates an instance of
another class in another module."""
from secondclass import Shape
class DataObject(object):
"""Create a class that holds data objects."""
def __init__(self, x, y):
self.m_x = x
self.m_y = y
self.m_shape_list = []
def createShape(self, type):
# here we create an instance of the second class
new_shape = Shape(type)
self.m_shape_list.append(new_shape)
def printCoords(self):
print "Coordinates:", (x,y)
===secondclass.py===
"""This is another reusable class. An instance of this gets created within
an another class and it is also subclassed by the main program."""
class Shape(object):
"""Create a class that holds shape info."""
def __init__(self,type):
self.m_type = type
print "Shape:",type
def printShape(self):
print "Shape:",self.m_type
===main.py===
"""This is my main program and where all the classes get subclassed to add
specific implementation details."""
from firstclass import DataObject
from secondclass import Shape
class GraphicObject(DataObject):
"""Create a subclass of DataObject that holds graphic specific info."""
def __init__(self, x, y, color):
print "Init MySubClass"
super(GraphicObject,self).__init__(x, y)
def createSomeShapes(self):
self.createShape('circle')
self.createShape('square')
self.createShape('octogon')
def renderAll(self):
for shape in self.m_shape_list:
shape.render()
class MyShape(Shape):
"""Create a subclass of Shape that holds graphic specific info."""
def __init__(self, type):
if type == circle:
type = 'round thing'
super(MyShape,self).__init__(type)
def render(self):
print "We got a",shape
# Create an instance of the first class
obj = GraphicObject(10, 10, 'yeller')
# Create a few instances of the second class through the interface
# provided by the first class
obj.createSomeShapes()
# Now attempts to call a method of the subclassed second class
obj.renderAll()
当我跑步时,我得到:
$ python main.py
Init MySubClass
Shape: circle
Shape: square
Shape: octogon
Traceback (most recent call last):
File "main.py", line 35, in <module>
obj.renderAll()
File "main.py", line 21, in renderAll
shape.render()
AttributeError: 'Shape' object has no attribute 'render'
我知道为什么正在发生,但我不知道一种优雅的方法来避免它。
这里的最佳做法是什么?如何在访问子类方法时保持模块代码可重用?
答案 0 :(得分:3)
这不是关于模块的问题。即使所有类都在同一个文件中,您也会遇到同样的问题。问题是您的DataObject类是硬编码的,以创建Shape
的实例,并且不知道您有子类Shape
并且想要使用该子类。有两种方法:
createShape
,则必须覆盖Shape
的文档。这很简单有效。一个缺点是,如果它很长并且需要更改的是Shape类的名称,则覆盖整个方法可能很麻烦。另一方面,如果createShape
也做了其他通常需要在子类中被覆盖的工作,那么必须覆盖它不是一个大问题。shapeClass
类属性来参数化DataObject / Shape关系,并使用它来实例化形状而不是直接引用Shape
。那是:
class DataObject(object):
# other stuff...
shapeClass = Shape
def createShape(self, type):
# here we create an instance of the second class
new_shape = self.shapeClass(type)
self.m_shape_list.append(new_shape)
然后你可以在子类中更简洁地覆盖它:
class GraphicObject(DataObject):
# other stuff...
shapeClass = MyShape
通过将Shape
拉出方法代码并使其成为单独的属性,您允许子类仅覆盖该行为的那一部分。现在,调用someGraphicObject.createShape()
会自动创建MyShape
。
哪种方法更好取决于您的整体类设计,但上面提到的因素(关于使用参数化类的方法是否可能需要在子类中被覆盖)可能是相关的。