Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Pythonic在游戏实体类中实现代码重用的方法_Python_Oop_Mixins - Fatal编程技术网

Pythonic在游戏实体类中实现代码重用的方法

Pythonic在游戏实体类中实现代码重用的方法,python,oop,mixins,Python,Oop,Mixins,我开始为我正在编写的游戏定义我的实体类。但是,我需要大量代码重用。我想为不同的功能定义类,然后让类“拥有”这些类中的一些功能 例如: class Collidable: def handle_collision(other, incident_vector): pass def __init__(self, shape): self.shape = shape class Movable: def update_position(sel

我开始为我正在编写的游戏定义我的实体类。但是,我需要大量代码重用。我想为不同的功能定义类,然后让类“拥有”这些类中的一些功能

例如:

class Collidable:
    def handle_collision(other, incident_vector):
        pass

    def __init__(self, shape):
        self.shape = shape

class Movable:
    def update_position(self):
        self.velocity += self.acceleration
        self.position += self.velocity

    def __init__(self, velocity, acceleration):
        self.velocity, self.acceleration = velocity, acceleration

class Drawable:
    def draw(self):
        pass

    def __init__(self, image):
        self.image = image

class Controllable:
    def key_down(self, key):
        pass

    def __init__(self):
        pass
class Collidable(object):
    def handle_collision(other, incident_vector):
        pass

    def __init__(self, shape, **kwargs):
        self.shape = shape
        super(Collidable, self).__init__(**kwargs)

class Movable(object):
    def update_position(self):
        self.velocity += self.acceleration
        self.position += self.velocity

    def __init__(self, velocity, acceleration, **kwargs):
        self.velocity, self.acceleration = velocity, acceleration
        super(Movable, self).__init__(**kwargs)

class Drawable(object):
    def draw(self):
        pass

    def __init__(self, image, **kwargs):
        self.image = image
        super(Drawable, self).__init__(**kwargs)

class Controllable(object):
    def key_down(self, key):
        pass

    def __init__(self, **kwargs):
        super(Controllable, self).__init__(**kwargs)
class Player(Collidable, Movable, Drawable, Controllable):
    def __init__(name, **kwargs):
        self.name = name
        super(Player, self).__init__(**kwargs)
然后有一个
Player
类,它是可碰撞的、可移动的、可绘制的、可控制的,一个
看不见的屏障
它是唯一可碰撞的,一个
背景
它是唯一可绘制的,等等。我听说过许多连接多个类的不同方式,(比如通过组合、(多重)继承、接口等),但我不知道在这种情况下,哪一种方法最合适和/或最适合

Mix-ins(多重继承的特例)看起来就是我想要的(因为玩家应该是可碰撞的、可移动的、可绘制的和可控制的),但是在尝试这一点时,我发现使用
super
将正确的参数传递给正确的init函数很困难

编辑:


我使用的是python 3.2。

混合是一种方法,但您不想对它们调用
\uuuu init\uuuu

class CollidableMixin(object):
    #...
    def init_collidable(self, shape):
        self.shape = shape

class MovableMixin(object):
    #...
    def init_movable(self, velocity, acceleration):
        self.velocity, self.acceleration = velocity, acceleration

class DrawableMixin(object):
    #...
    def init_drawable(self, image):
        self.image = image
在我看来,
controlable
不需要单独的类,因为它只定义了继承类应该具有的接口。虽然在Java等静态类型语言中经常这样做,但在Python中不需要这样做。相反,您只需定义一个
key\u down
方法并使用它即可。这就是所谓的duck类型

在示例实现中,这将如下所示:

class Player(CollidableMixin, DrawableMixin, MovableMixin):
    def __init__(self):
        self.init_collidable(...)
        self.init_drawable(...)
        self.init_movable(...)

    def key_down(self, key):
        # ...

objects = []
objects.append(Player())
# ... add some more objects. Later we iterate through that collection,
# not knowing which of them is a player:
for o in objects:
    try:
        o.key_down(...)
    except AttributeError:
        pass
>>> p = Player(shape='circle', velocity=0.0, acceleration=1.0, image='player.png')
>>> p.shape
'circle'
>>> p.velocity
0.0
>>> p.acceleration
1.0

混音是一种方式,但您不想对其调用
\uuuu init\uuuu

class CollidableMixin(object):
    #...
    def init_collidable(self, shape):
        self.shape = shape

class MovableMixin(object):
    #...
    def init_movable(self, velocity, acceleration):
        self.velocity, self.acceleration = velocity, acceleration

class DrawableMixin(object):
    #...
    def init_drawable(self, image):
        self.image = image
在我看来,
controlable
不需要单独的类,因为它只定义了继承类应该具有的接口。虽然在Java等静态类型语言中经常这样做,但在Python中不需要这样做。相反,您只需定义一个
key\u down
方法并使用它即可。这就是所谓的duck类型

在示例实现中,这将如下所示:

class Player(CollidableMixin, DrawableMixin, MovableMixin):
    def __init__(self):
        self.init_collidable(...)
        self.init_drawable(...)
        self.init_movable(...)

    def key_down(self, key):
        # ...

objects = []
objects.append(Player())
# ... add some more objects. Later we iterate through that collection,
# not knowing which of them is a player:
for o in objects:
    try:
        o.key_down(...)
    except AttributeError:
        pass
>>> p = Player(shape='circle', velocity=0.0, acceleration=1.0, image='player.png')
>>> p.shape
'circle'
>>> p.velocity
0.0
>>> p.acceleration
1.0

下面是使用
super()
实现继承的简单方法。为此,您将始终需要使用关键字参数创建
Player
(以及从***类继承的其他类)的实例。每个基类将从
kwargs
中删除它正在使用的任何关键字参数,并将其余的参数传递到mro中的下一个
\uuuuuu init\uuuuu()
,例如:

class Collidable:
    def handle_collision(other, incident_vector):
        pass

    def __init__(self, shape):
        self.shape = shape

class Movable:
    def update_position(self):
        self.velocity += self.acceleration
        self.position += self.velocity

    def __init__(self, velocity, acceleration):
        self.velocity, self.acceleration = velocity, acceleration

class Drawable:
    def draw(self):
        pass

    def __init__(self, image):
        self.image = image

class Controllable:
    def key_down(self, key):
        pass

    def __init__(self):
        pass
class Collidable(object):
    def handle_collision(other, incident_vector):
        pass

    def __init__(self, shape, **kwargs):
        self.shape = shape
        super(Collidable, self).__init__(**kwargs)

class Movable(object):
    def update_position(self):
        self.velocity += self.acceleration
        self.position += self.velocity

    def __init__(self, velocity, acceleration, **kwargs):
        self.velocity, self.acceleration = velocity, acceleration
        super(Movable, self).__init__(**kwargs)

class Drawable(object):
    def draw(self):
        pass

    def __init__(self, image, **kwargs):
        self.image = image
        super(Drawable, self).__init__(**kwargs)

class Controllable(object):
    def key_down(self, key):
        pass

    def __init__(self, **kwargs):
        super(Controllable, self).__init__(**kwargs)
class Player(Collidable, Movable, Drawable, Controllable):
    def __init__(name, **kwargs):
        self.name = name
        super(Player, self).__init__(**kwargs)
然后您可以定义您的
Player
类:

class Player(Collidable, Movable, Drawable, Controllable):
    pass
然后像这样使用它:

class Player(CollidableMixin, DrawableMixin, MovableMixin):
    def __init__(self):
        self.init_collidable(...)
        self.init_drawable(...)
        self.init_movable(...)

    def key_down(self, key):
        # ...

objects = []
objects.append(Player())
# ... add some more objects. Later we iterate through that collection,
# not knowing which of them is a player:
for o in objects:
    try:
        o.key_down(...)
    except AttributeError:
        pass
>>> p = Player(shape='circle', velocity=0.0, acceleration=1.0, image='player.png')
>>> p.shape
'circle'
>>> p.velocity
0.0
>>> p.acceleration
1.0
如果您需要
Player
类的其他实例变量,您可以定义一个类似于其他类的
\uuu init\uuuu()
,例如:

class Collidable:
    def handle_collision(other, incident_vector):
        pass

    def __init__(self, shape):
        self.shape = shape

class Movable:
    def update_position(self):
        self.velocity += self.acceleration
        self.position += self.velocity

    def __init__(self, velocity, acceleration):
        self.velocity, self.acceleration = velocity, acceleration

class Drawable:
    def draw(self):
        pass

    def __init__(self, image):
        self.image = image

class Controllable:
    def key_down(self, key):
        pass

    def __init__(self):
        pass
class Collidable(object):
    def handle_collision(other, incident_vector):
        pass

    def __init__(self, shape, **kwargs):
        self.shape = shape
        super(Collidable, self).__init__(**kwargs)

class Movable(object):
    def update_position(self):
        self.velocity += self.acceleration
        self.position += self.velocity

    def __init__(self, velocity, acceleration, **kwargs):
        self.velocity, self.acceleration = velocity, acceleration
        super(Movable, self).__init__(**kwargs)

class Drawable(object):
    def draw(self):
        pass

    def __init__(self, image, **kwargs):
        self.image = image
        super(Drawable, self).__init__(**kwargs)

class Controllable(object):
    def key_down(self, key):
        pass

    def __init__(self, **kwargs):
        super(Controllable, self).__init__(**kwargs)
class Player(Collidable, Movable, Drawable, Controllable):
    def __init__(name, **kwargs):
        self.name = name
        super(Player, self).__init__(**kwargs)

下面是使用
super()
实现继承的简单方法。为此,您将始终需要使用关键字参数创建
Player
(以及从***类继承的其他类)的实例。每个基类将从
kwargs
中删除它正在使用的任何关键字参数,并将其余的参数传递到mro中的下一个
\uuuuuu init\uuuuu()
,例如:

class Collidable:
    def handle_collision(other, incident_vector):
        pass

    def __init__(self, shape):
        self.shape = shape

class Movable:
    def update_position(self):
        self.velocity += self.acceleration
        self.position += self.velocity

    def __init__(self, velocity, acceleration):
        self.velocity, self.acceleration = velocity, acceleration

class Drawable:
    def draw(self):
        pass

    def __init__(self, image):
        self.image = image

class Controllable:
    def key_down(self, key):
        pass

    def __init__(self):
        pass
class Collidable(object):
    def handle_collision(other, incident_vector):
        pass

    def __init__(self, shape, **kwargs):
        self.shape = shape
        super(Collidable, self).__init__(**kwargs)

class Movable(object):
    def update_position(self):
        self.velocity += self.acceleration
        self.position += self.velocity

    def __init__(self, velocity, acceleration, **kwargs):
        self.velocity, self.acceleration = velocity, acceleration
        super(Movable, self).__init__(**kwargs)

class Drawable(object):
    def draw(self):
        pass

    def __init__(self, image, **kwargs):
        self.image = image
        super(Drawable, self).__init__(**kwargs)

class Controllable(object):
    def key_down(self, key):
        pass

    def __init__(self, **kwargs):
        super(Controllable, self).__init__(**kwargs)
class Player(Collidable, Movable, Drawable, Controllable):
    def __init__(name, **kwargs):
        self.name = name
        super(Player, self).__init__(**kwargs)
然后您可以定义您的
Player
类:

class Player(Collidable, Movable, Drawable, Controllable):
    pass
然后像这样使用它:

class Player(CollidableMixin, DrawableMixin, MovableMixin):
    def __init__(self):
        self.init_collidable(...)
        self.init_drawable(...)
        self.init_movable(...)

    def key_down(self, key):
        # ...

objects = []
objects.append(Player())
# ... add some more objects. Later we iterate through that collection,
# not knowing which of them is a player:
for o in objects:
    try:
        o.key_down(...)
    except AttributeError:
        pass
>>> p = Player(shape='circle', velocity=0.0, acceleration=1.0, image='player.png')
>>> p.shape
'circle'
>>> p.velocity
0.0
>>> p.acceleration
1.0
如果您需要
Player
类的其他实例变量,您可以定义一个类似于其他类的
\uuu init\uuuu()
,例如:

class Collidable:
    def handle_collision(other, incident_vector):
        pass

    def __init__(self, shape):
        self.shape = shape

class Movable:
    def update_position(self):
        self.velocity += self.acceleration
        self.position += self.velocity

    def __init__(self, velocity, acceleration):
        self.velocity, self.acceleration = velocity, acceleration

class Drawable:
    def draw(self):
        pass

    def __init__(self, image):
        self.image = image

class Controllable:
    def key_down(self, key):
        pass

    def __init__(self):
        pass
class Collidable(object):
    def handle_collision(other, incident_vector):
        pass

    def __init__(self, shape, **kwargs):
        self.shape = shape
        super(Collidable, self).__init__(**kwargs)

class Movable(object):
    def update_position(self):
        self.velocity += self.acceleration
        self.position += self.velocity

    def __init__(self, velocity, acceleration, **kwargs):
        self.velocity, self.acceleration = velocity, acceleration
        super(Movable, self).__init__(**kwargs)

class Drawable(object):
    def draw(self):
        pass

    def __init__(self, image, **kwargs):
        self.image = image
        super(Drawable, self).__init__(**kwargs)

class Controllable(object):
    def key_down(self, key):
        pass

    def __init__(self, **kwargs):
        super(Controllable, self).__init__(**kwargs)
class Player(Collidable, Movable, Drawable, Controllable):
    def __init__(name, **kwargs):
        self.name = name
        super(Player, self).__init__(**kwargs)

哇,我非常喜欢。也解决了我的游戏中的一些问题:)不过,我想知道这种方法有多标准。定义“init的私有版本”是否被认为是一种良好的实践?在我看来,代码仍然可以使用标准的init方法。而不是
self.init\u可碰撞(…)
,您得到的是
可碰撞的。是不是更清晰,使用更标准的方法?干杯我为什么不给他们打电话?这是为了回答为正确的类提供正确的参数的问题吗?我可以通过使用**kwargs参数来解决这个问题吗?@Darthfett:对于新样式的类
super(…)。\uuu init\uuu(…)
只有在所有方法都具有相同的签名时才有效。不能指定调用方法的顺序。你当然可以使用另一个答案中的方法,但这样做会失去一些安全性(通常不值得!)@Morlock:我认为这是老式类必须采用的方法,但对于新式类则不鼓励(尽管我不能告诉你为什么,抱歉)。哇,我非常喜欢。也解决了我的游戏中的一些问题:)不过,我想知道这种方法有多标准。定义“init的私有版本”是否被认为是一种良好的实践?在我看来,代码仍然可以使用标准的init方法。而不是
self.init\u可碰撞(…)
,您得到的是
可碰撞的。是不是更清晰,使用更标准的方法?干杯我为什么不给他们打电话?这是为了回答为正确的类提供正确的参数的问题吗?我可以通过使用**kwargs参数来解决这个问题吗?@Darthfett:对于新样式的类
super(…)。\uuu init\uuu(…)
只有在所有方法都具有相同的签名时才有效。不能指定调用方法的顺序。您当然可以使用另一个答案中的方法,但这样做会失去一些安全性(通常不值得!)@Morlock:我认为旧样式的类必须这样做,但新样式的类不鼓励这样做(尽管我无法告诉您原因,抱歉)。我同意这是Python中最自然的实现方式—OOP系统的预期使用方式。只要
Player
实例必须将自己的参数传递给父构造函数,这将变得很棘手。然后我们需要
kwargs.update({…})
。如果几个参数的名称相同,它会变得更加丑陋…@NiklasB。是的