答案 0 :(得分:11)
如果您想坚持原始的数据地图设计,可以使用合成来解决传感器架构。你似乎是Python的新手,所以我会尝试将习语保持在最低限度。
class IRSensor:
def read(self): return {'ir_amplitude': 12}
class UltrasonicSensor:
def read(self): return {'ultrasonic_amplitude': 63}
class SickLaserSensor:
def read(self): return {'laser_amplitude': 55}
class CompositeSensor:
"""Wrap multiple component sensors, coalesce the results, and return
the composite readout.
"""
component_sensors = []
def __init__(self, component_sensors=None):
component_sensors = component_sensors or self.component_sensors
self.sensors = [cls() for cls in component_sensors]
def read(self):
measurements = {}
for sensor in self.sensors:
measurements.update(sensor.read())
return measurements
class MyCompositeSensor(CompositeSensor):
component_sensors = [UltrasonicSensor, IRSensor]
composite_sensor = MyCompositeSensor()
measurement_map = composite_sensor.read()
assert measurement_map['ultrasonic_amplitude'] == 63
assert measurement_map['ir_amplitude'] == 12
使用mixins和代理(通过__getattr__
)而不是继承来解决您使用执行器描述的架构问题。 (代理可以是继承的一个很好的替代方法,因为代理的对象可以在运行时绑定/解除绑定。此外,您不必担心使用此技术处理单个构造函数中的所有初始化。)
class MovementActuator:
def __init__(self, x=0, y=0):
self.x, self.y = (x, y)
def move(self, x, y):
print 'Moving to', x, y
self.x, self.y = (x, y)
def get_position(self):
return (self.x, self.y)
class CommunicationActuator:
def communicate(self):
return 'Hey you out there!'
class CompositeActuator:
component_actuators = []
def __init__(self, component_actuators=None):
component_actuators = component_actuators \
or self.component_actuators
self.actuators = [cls() for cls in component_actuators]
def __getattr__(self, attr_name):
"""Look for value in component sensors."""
for actuator in self.actuators:
if hasattr(actuator, attr_name):
return getattr(actuator, attr_name)
raise AttributeError(attr_name)
class MyCompositeActuator(CompositeActuator):
component_actuators = [MovementActuator, CommunicationActuator]
composite_actuator = MyCompositeActuator()
assert composite_actuator.get_position() == (0, 0)
assert composite_actuator.communicate() == 'Hey you out there!'
最后,您可以将所有内容与简单的节点声明一起抛出:
from sensors import *
from actuators import *
class AbstractNode:
sensors = [] # Set of classes.
actuators = [] # Set of classes.
def __init__(self):
self.composite_sensor = CompositeSensor(self.sensors)
self.composite_actuator = CompositeActuator(self.actuators)
class MyNode(AbstractNode):
sensors = [UltrasonicSensor, SickLaserSensor]
actuators = [MovementActuator, CommunicationActuator]
def think(self):
measurement_map = self.composite_sensor.read()
while self.composite_actuator.get_position()[1] >= 0:
self.composite_actuator.move(100, -100)
my_node = MyNode()
my_node.think()
这应该让您了解刚性类型系统的替代方案。请注意,您根本不必依赖于类型层次结构 - 只需实现(可能是隐式的)公共接口。
在仔细阅读问题后,我发现你所拥有的是diamond inheritance的典型例子,它是单{{}}的evil that makes people flee。
你可能不希望这开始,因为类层次结构意味着在Python中蹲下。你想要做的是做一个SensorInterface
(传感器的最低要求),并有一堆“mixin”类,它们具有完全独立的功能,可以通过各种名称的方法调用。在您的传感器框架中,您不应该说isinstance(sensor, PositionSensor)
之类的内容 - 您应该说“这个传感器可以进行地理定位吗?”采用以下形式:
def get_position(sensor):
try:
return sensor.geolocate()
except AttributeError:
return None
这是鸭子类型哲学的核心,EAFP(比宽容更容易要求宽恕),这两者都是Python语言所包含的。
您应该描述这些传感器实际实现的方法,以便我们可以描述如何将mixin类用于插件架构。
如果他们将代码写入一个放在插件包中的模块或者你有什么,你可以在导入他们的插件模块时神奇地为它们设置类。这段代码的一些内容(未经测试):
import inspect
import types
from sensors import Sensor
def is_class(obj):
return type(obj) in (types.ClassType, types.TypeType)
def instrumented_init(self, *args, **kwargs):
Sensor.__init__(self, *args, **kwargs)
for module in plugin_modules: # Get this from somewhere...
classes = inspect.getmembers(module, predicate=is_class)
for name, cls in classes:
if hasattr(cls, '__init__'):
# User specified own init, may be deriving from something else.
continue
if cls.__bases__ != tuple([Sensor]):
continue # Class doesn't singly inherit from sensor.
cls.__init__ = instrumented_init
您可以find the modules within a package使用其他功能。
答案 1 :(得分:1)
super
调用mro-list中的下一个类。即使你遗漏了__init__
形式的某个类,这也行得正常。
class A(object):
def __init__(self):
super(A,self).__init__()
print "Hello from A!"
class B(A):
def __init__(self):
super(B,self).__init__()
print "Hello from B!"
class C(A):
def __init__(self):
super(C,self).__init__()
print "Hello from C!"
class D(B,C):
def __init__(self):
super(D,self).__init__()
print "Hello from D!"
class E(B,C):
pass
示例:
>>> x = D()
Hello from A!
Hello from C!
Hello from B!
Hello from D!
>>> y = E()
Hello from A!
Hello from C!
Hello from B!
>>>
编辑:重写了答案。 (再次)
答案 2 :(得分:1)
这是部分解决方案:
class NodeMeta(type):
def __init__(cls, name, bases, d):
setattr(cls, '__inherits__', bases)
class Node(object):
__metaclass__ = NodeMeta
def __init__(self):
for cls in self.__inherits__:
cls.cls_init(self)
class Sensor(Node):
def cls_init(self):
print "Sensor initialized"
class PositionSensor(Sensor):
def cls_init(self):
print "PositionSensor initialized"
self._bearing = 0
def bearing(self):
# calculate bearing:
return self._bearing
class BearingSensor(Sensor):
def cls_init(self):
print "BearingSensor initialized"
self._position = (0, 0)
def position(self):
# calculate position:
return self._position
# -------- custom sensors --------
class CustomSensor(PositionSensor, BearingSensor):
def think(self):
print "Current position:", self.position()
print "Current bearing:", self.bearing()
class CustomSensor2(PositionSensor, BearingSensor, Sensor):
pass
>>> s = CustomSensor()
PositionSensor initialized
BearingSensor initialized
>>> s.think()
Current position: (0, 9)
Current bearing: 0
您必须将__init__
代码从Node子类移动到其他方法(我使用cls_init
)。
修改:在我看到您的更新之前,我发布了这个内容;我会重新阅读您的问题,如有必要,请更新此解决方案。