项目的多重继承与组合的讨论(+其他事情)

发布于 2024-07-14 14:33:21 字数 4575 浏览 4 评论 0原文

我正在编写一个用于模拟分布式传感器群的 python 平台。 这个想法是,最终用户可以编写一个由 SensorNode 行为(通信、日志记录等)组成的自定义节点,并实现许多不同的传感器。

下面的示例简要演示了这个概念。

#prewritten
class Sensor(object):
  def __init__(self):
    print "Hello from Sensor"
  #...

#prewritten
class PositionSensor(Sensor):
  def __init__(self):
    print "Hello from Position"
    Sensor.__init__(self)
  #...

#prewritten
class BearingSensor(Sensor):
  def __init__(self):
    print "Hello from Bearing"
    Sensor.__init__(self)
  #...

#prewritten
class SensorNode(object):
  def __init__(self):
    print "Hello from SensorNode"
  #...

#USER WRITTEN
class MySensorNode(SensorNode,BearingSensor,PositionSensor):
  def CustomMethod(self):
    LogData={'Position':position(), 'Bearing':bearing()} #position() from PositionSensor, bearing() from BearingSensor
    Log(LogData) #Log() from SensorNode

新编辑:

首先概述我想要实现的目标: 我正在编写一个模拟器来模拟群体智能算法,特别关注移动传感器网络。 这些网络由许多小型机器人组成,它们通信各个传感器数据,以构建复杂的环境感知图。

该项目的根本目标是开发一个模拟平台,为传感器提供抽象接口,以便将相同的用户实现的功能直接移植到运行嵌入式 Linux 的机器人群中。 由于机器人实现是目标,我需要进行设计,使软件节点的行为相同,并且只能访问物理节点将拥有的信息。

作为仿真引擎的一部分,我将提供一组对不同类型的传感器和不同类型的传感器节点进行建模的类。 我希望将所有这些复杂性从用户手中抽象出来,以便用户必须做的就是定义节点上存在哪些传感器,以及正在实现什么类型的传感器节点(移动、固定位置)。

我最初的想法是每个传感器都会提供一个 read() 方法,该方法将返回相关值,但是在阅读了对问题的回答后,我发现也许更具描述性的方法名称会更好(.distance(), .position( )、.bearing() 等)。

我最初希望为传感器使用单独的类(具有共同的祖先),以便技术水平更高的用户可以轻松扩展现有类之一,以创建新的传感器(如果他们愿意)。 例如:

Sensor
  |
DistanceSensor(designed for 360 degree scan range)
    |           |           |
IR Sensor   Ultrasonic    SickLaser
(narrow)    (wider)       (very wide)

我最初想到多重继承(尽管它半破坏了继承的 IS-A 关系)的原因是由于模拟系统背后的基本原理。 让我解释一下:

用户实现的 MySensorNode 不应该直接访问其在环境中的位置(类似于机器人,访问是通过传感器接口间接进行的),同样,传感器不应该知道它们在哪里。 然而,缺乏直接知识会带来问题,因为传感器的返回值都取决于它们在环境中的位置和方向(需要进行模拟才能返回正确的值)。

SensorNode 作为模拟库中实现的类,负责在 pygame 环境中绘制 MySensorNode - 因此,它是唯一应该直接访问环境中传感器节点的位置和方向的类。

SensorNode 还负责环境内的平移和旋转,但是这种平移和旋转是电机驱动的副作用。

我的意思是,机器人不能直接改变它们在世界中的位置,它们所能做的就是为电机提供动力,而世界中的运动是电机与环境相互作用的副作用。 我需要在模拟中对此进行准确建模。

因此,为了移动,用户实现的功能可以使用:

motors(50,50)

作为副作用,该调用将改变节点在世界中的位置。

如果 SensorNode 使用组合实现,则 SensorNode.motors(...) 将无法直接更改实例变量(例如位置),MySensorNode.draw() 也不会解析为 SensorNode.draw(),因此 SensorNode 我认为应该使用继承来实现。

就传感器而言,组合对于此类问题的好处是显而易见的,MySensorNode 由多个传感器组成 - 说得够多了。

然而,我认为的问题是传感器需要访问它们在世界中的位置和方向,如果你使用组合,你最终会得到这样的调用:

>>> PosSensor.position((123,456))
(123,456)

然后再一次思考,你可以在初始化时将 self 传递给传感器,例如:

PosSensor = PositionSensor(self)

然后,

PosSensor.position()

但是这个 PosSensor.position() 需要访问实例本地的信息(在 init() 期间作为 self 传递),那么当您可以访问实例时为什么还要调用 PosSensor本地信息? 另外,将你的实例传递给你所组成的对象似乎不太正确,跨越了封装和信息隐藏的界限(尽管Python没有做太多支持信息隐藏的想法)。

如果解决方案是使用多重继承实现的,这些问题就会消失:

class MySensorNode(SensorNode,PositionSensor,BearingSensor):
  def Think():
    while bearing()>0:
      # bearing() is provided by BearingSensor and in the simulator
      # will simply access local variables provided by SensorNode
      # to return the bearing. In robotic implementation, the
      # bearing() method will instead access C routines to read
      # the actual bearing from a compass sensor
      motors(100,-100)
      # spin on the spot, will as a side-effect alter the return
      # value of bearing()

    (Ox,Oy)=position() #provided by PositionSensor
    while True:
      (Cx,Cy)=position()
      if Cx>=Ox+100:
        break
      else:
        motors(100,100)
        #full speed ahead!will alter the return value of position()

希望此编辑已经澄清了一些事情,如果您有任何问题,我非常乐意尝试并澄清它们

旧的事情:

当构造 MySensorNode 类型的对象时,需要调用超类的所有构造函数。 我不想让用户因为必须为 MySensorNode 调用每个超类的构造函数而编写自定义构造函数而变得复杂。 理想情况下,我希望发生的是:

mSN = MySensorNode()
# at this point, the __init__() method is searched for
# and SensorNode.__init__() is called given the order
# of inheritance in MySensorNode.__mro__

# Somehow, I would also like to call all the other constructors
# that were not executed (ie BearingSensor and PositionSensor)

任何见解或一般性评论将不胜感激, 干杯:)

旧编辑: 这样做是

#prewritten
class SensorNode(object):
  def __init__(self):
    print "Hello from SensorNode"
    for clss in type(self).__mro__:
      if clss!=SensorNode and clss!=type(self):
        clss.__init__(self)

可行的,因为 self 是 MySensorNode 的一个实例。 然而这个解决方案很混乱。


I am writing a python platform for the simulation of distributed sensor swarms. The idea being that the end user can write a custom Node consisting of the SensorNode behaviour (communication, logging, etc) as well as implementing a number of different sensors.

The example below briefly demonstrates the concept.

#prewritten
class Sensor(object):
  def __init__(self):
    print "Hello from Sensor"
  #...

#prewritten
class PositionSensor(Sensor):
  def __init__(self):
    print "Hello from Position"
    Sensor.__init__(self)
  #...

#prewritten
class BearingSensor(Sensor):
  def __init__(self):
    print "Hello from Bearing"
    Sensor.__init__(self)
  #...

#prewritten
class SensorNode(object):
  def __init__(self):
    print "Hello from SensorNode"
  #...

#USER WRITTEN
class MySensorNode(SensorNode,BearingSensor,PositionSensor):
  def CustomMethod(self):
    LogData={'Position':position(), 'Bearing':bearing()} #position() from PositionSensor, bearing() from BearingSensor
    Log(LogData) #Log() from SensorNode

NEW EDIT:

Firstly an overview of what I am trying to achieve:
I am writing a simulator to simulate swarm intelligence algorithms with particular focus on mobile sensor networks. These networks consist of many small robots communicating individual sensor data to build a complex sensory map of the environment.

The underlying goal of this project is to develop a simulation platform that provides abstracted interfaces to sensors such that the same user-implemented functionality can be directly ported to a robotic swarm running embedded linux. As robotic implementation is the goal, I need to design such that the software node behaves the same, and only has access to information that an physical node would have.

As part of the simulation engine, I will be providing a set of classes modelling different types of sensors and different types of sensor node. I wish to abstract all this complexity away from the user such that all the user must do is define which sensors are present on the node, and what type of sensor node (mobile, fixed position) is being implemented.

My initial thinking was that every sensor would provide a read() method which would return the relevant values, however having read the responses to the question, I see that perhaps more descriptive method names would be beneficial (.distance(), .position(), .bearing(), etc).

I initially wanted use separate classes for the sensors (with common ancestors) so that a more technical user can easily extend one of the existing classes to create a new sensor if they wish. For example:

Sensor
  |
DistanceSensor(designed for 360 degree scan range)
    |           |           |
IR Sensor   Ultrasonic    SickLaser
(narrow)    (wider)       (very wide)

The reason I was initially thinking of Multiple Inheritance (although it semi-breaks the IS-A relationship of inheritance) was due to the underlying principle behind the simulation system. Let me explain:

The user-implemented MySensorNode should not have direct access to its position within the environment (akin to a robot, the access is indirect through a sensor interface), similarly, the sensors should not know where they are. However, this lack of direct knowledge poses a problem, as the return values of the sensors are all dependent on their position and orientation within the environment (which needs to be simulated to return the correct values).

SensorNode, as a class implemented within the simulation libraries, is responsible for drawing the MySensorNode within the pygame environment - thus, it is the only class that should have direct access to the position and orientation of the sensor node within the environment.

SensorNode is also responsible for translation and rotation within the environment, however this translation and rotation is a side effect of motor actuation.

What I mean by this is that robots cannot directly alter their position within the world, all they can do is provide power to motors, and movement within the world is a side-effect of the motors interaction with the environment. I need to model this accurately within the simulation.

So, to move, the user-implemented functionality may use:

motors(50,50)

This call will, as a side-effect, alter the position of the node within the world.

If SensorNode was implemented using composition, SensorNode.motors(...) would not be able to directly alter instance variables (such as position), nor would MySensorNode.draw() be resolved to SensorNode.draw(), so SensorNode imo should be implemented using inheritance.

In terms of the sensors, the benefit of composition for a problem like this is obvious, MySensorNode is composed of a number of sensors - enough said.

However the problem as I see it is that the Sensors need access to their position and orientation within the world, and if you use composition you will end up with a call like:

>>> PosSensor.position((123,456))
(123,456)

Then again - thinking, you could pass self to the sensor upon initialisation, eg:

PosSensor = PositionSensor(self)

then later

PosSensor.position()

however this PosSensor.position() would then need to access information local to the instance (passed as self during init()), so why call PosSensor at all when you can access the information locally? Also passing your instance to an object you are composed of just seems not quite right, crossing the boundaries of encapsulation and information hiding (even though python doesn't do much to support the idea of information hiding).

If the solution was implemented using multiple inheritance, these problems would disappear:

class MySensorNode(SensorNode,PositionSensor,BearingSensor):
  def Think():
    while bearing()>0:
      # bearing() is provided by BearingSensor and in the simulator
      # will simply access local variables provided by SensorNode
      # to return the bearing. In robotic implementation, the
      # bearing() method will instead access C routines to read
      # the actual bearing from a compass sensor
      motors(100,-100)
      # spin on the spot, will as a side-effect alter the return
      # value of bearing()

    (Ox,Oy)=position() #provided by PositionSensor
    while True:
      (Cx,Cy)=position()
      if Cx>=Ox+100:
        break
      else:
        motors(100,100)
        #full speed ahead!will alter the return value of position()

Hopefully this edit has clarified some things, if you have any questions I'm more than happy to try and clarify them

OLD THINGS:

When an object of type MySensorNode is constructed, all constructors from the superclasses need to be called. I do not want to complicate the user with having to write a custom constructor for MySensorNode which calls the constructor from each superclass. Ideally, what I would like to happen is:

mSN = MySensorNode()
# at this point, the __init__() method is searched for
# and SensorNode.__init__() is called given the order
# of inheritance in MySensorNode.__mro__

# Somehow, I would also like to call all the other constructors
# that were not executed (ie BearingSensor and PositionSensor)

Any insight or general comments would be appreciated,
Cheers :)

OLD EDIT:
Doing something like:

#prewritten
class SensorNode(object):
  def __init__(self):
    print "Hello from SensorNode"
    for clss in type(self).__mro__:
      if clss!=SensorNode and clss!=type(self):
        clss.__init__(self)

This works, as self is an instance of MySensorNode. However this solution is messy.


如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

月亮邮递员 2024-07-21 14:33:21

如果您想坚持原始的数据图设计,可以通过使用组合来解决传感器架构。 您似乎对 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()

这应该让您了解刚性类型系统的替代方案。 请注意,您根本不必依赖类型层次结构——只需实现一个(可能是隐式的)公共接口。

不太旧:

更仔细地阅读问题后,我发现您所拥有的是钻石继承的经典示例< /a>,这是让人逃离单一继承的邪恶。

你可能不希望这样开始,因为类层次结构在 Python 中意味着占位。 您想要做的是创建一个SensorInterface(传感器的最低要求)并拥有一堆“混合”类,这些类具有完全独立的功能,可以通过各种名称的方法调用。 在您的传感器框架中,您不应该说诸如 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

您可以 使用另一个函数查找包内的模块

The sensor architecture can be solved by using composition if you want to stick to your original map-of-data design. You seem to be new to Python so I'll try to keep idioms to a minimum.

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

The architectural problem you're describing with the actuators is solved by using mixins and proxying (via __getattr__) rather than inheritance. (Proxying can be a nice alternative to inheritance because objects to proxy to can be bound/unbound at runtime. Also, you don't have to worry about handling all initialization in a single constructor using this technique.)

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!'

And finally, you can throw it all together with a simple node declaration:

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()

That should give you an idea of the alternatives to the rigid type system. Note that you don't have to rely on the type hierarchy at all -- just implement to a (potentially implicit) common interface.

LESS OLD:

After reading the question more carefully, I see that what you have is a classic example of diamond inheritance, which is the evil that makes people flee towards single inheritance.

You probably don't want this to begin with, since class hierarchy means squat in Python. What you want to do is make a SensorInterface (minimum requirements for a sensor) and have a bunch of "mixin" classes that have totally independent functionality that can be invoked through methods of various names. In your sensor framework you shouldn't say things like isinstance(sensor, PositionSensor) -- you should say things like "can this sensor geo-locate?" in the following form:

def get_position(sensor):
    try:
        return sensor.geolocate()
    except AttributeError:
        return None

This is the heart of duck-typing philosophy and EAFP (Easier to Ask for Forgiveness than Permission), both of which the Python language embraces.

You should probably describe what methods these sensors will actually implement so we can describe how you can use mixin classes for your plugin architecture.

OLD:

If they write the code in a module that gets put in a plugin package or what have you, you can magically instrument the classes for them when you import their plugin modules. Something along the lines of this snippet (untested):

 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

You can find the modules within a package with another function.

风向决定发型 2024-07-21 14:33:21

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!
>>> 

编辑:重写答案。 (再次)

super calls the next class in the mro-list. This works even if you leave out the __init__ form some class.

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

Example:

>>> 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!
>>> 

Edit: Rewrote the answer. (again)

别把无礼当个性 2024-07-21 14:33:21

这是部分解决方案:

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)。

编辑:我在看到您的更新之前发布了此内容; 我将重新阅读您的问题,如有必要,请更新此解决方案。

Here's a partial solution:

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

You'll have to move your __init__ code from the Node subclasses into some other method (I used cls_init).

Edit: I posted this before I saw your updates; I'll re-read your question, and if necessary, update this solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文