0

我正在寻找从注册为 ABC 的子类的类的实例中调用抽象基类方法的正确方法。这是一些非常基本的测试代码,首先要弄清楚如何使其工作。这是我目前所在的位置:

from abc import ABCMeta

# Dog class
class Dog(object):
    def speak(self):
        pass
    def move(self):
        pass

# Barking behaviors
class Bark(object):
    __metaclass__ = ABCMeta
    def speak(self):
        print "bark bark bark"

class Howl(object):
    __metaclass__ = ABCMeta
    def speak(self):
        print "ahwoooooo"

# Movement behaviors
class Run(object):
    __metaclass__ = ABCMeta
    def move(self):
        print "I'm running"

class Walk(object):
    __metaclass__ = ABCMeta
    def move(self):
        print "I'm walking"


# Dog implementations
class Beagle(Dog):
    pass
Howl.register(Beagle)
Run.register(Beagle)

nora = Beagle()
nora.speak() # THIS IS THE ISSUE: Calls speak() from original Dog class
nora.move()  # Need to call move() from registered ABC

# Test to be sure .register() was used properly
assert isinstance(nora, Howl)

虽然这种方法似乎过于复杂地改变了两个 Dog 方法,但我希望能够灵活地将行为分配给未知数量的实例。我希望能够在实例不知道实际行为的情况下调用 speak() 和 move()。我也喜欢这种方法,因为我也能够轻松删除或更改注册类的行为,而无需更改任何现有代码。

当前代码读取的方式 nora.speak() 和 nora.move() 调用从 Dog 到 Beagle 的继承方法,其中只包含 pass。

如果有人对我需要做什么以使注册行为的方法可调用有任何见解,或者我的方法是否完全有缺陷,我将不胜感激。

4

1 回答 1

0

这是我的尝试(可能不是最pythonic的方式,但与您的帖子很接近):

class Animals(object):
    def speak(self):
        return self.speak_action

    def swim(self):
        return self.swim_action

    def move(self):
        return self.move_action


class Dog(Animals):
    @property
    def speak_action(self):
        return "bark bark bark"

    @property
    def move_action(self):
        return "I'm Running"


class Beagle(Dog):
    @property
    def speak_action(self):
        return "ahwoooooo"


class Duck(Animals):
    @property
    def swim_action(self):
        return "Im floating"

    @property
    def speak_action(self):
        return "Quack!!"

    @property
    def move_action(self):
        return "I Fly!"

class Mallard(Duck):
    @property
    def speak_action(self):
        return "I'm Flying higher"

(让异常冒泡是个好习惯)

In [825]: d = Dog()

In [826]: d.speak()
Out[826]: 'bark bark bark'

In [827]: d.move()
Out[827]: "I'm Running"

In [828]: d.swim()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-828-c6d2ef2b464d> in <module>()
----> 1 d.swim()

.stuff/python/git_py/help_so.py in swim(self)
      4
      5     def swim(self):
----> 6         return self.swim_action
      7
      8     def move(self):

AttributeError: 'Dog' object has no attribute 'swim_action'

您可以选择要委托的内容:

In [830]: b = Beagle()

In [831]: b.speak()
Out[831]: 'ahwoooooo'

In [832]: b.move()
Out[832]: "I'm Running"

In [833]: b.swim()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-833-9c7b1a0c0dca> in <module>()
----> 1 b.swim()

/stuff/python/git_py/help_so.py in swim(self)
      4
      5     def swim(self):
----> 6         return self.swim_action
      7
      8     def move(self):

AttributeError: 'Beagle' object has no attribute 'swim_action'

并创造其他具有更多技能的动物:

In [849]: dd = Duck()

In [850]: dd.speak()
Out[850]: 'Quack!!'

In [851]: dd.move()
Out[851]: 'I Fly!'

In [852]: dd.swim()
Out[852]: 'Im floating'

您可以将某些内容指定给单个类,甚至可以将默认值指定给主类,并且可以根据需要/需要进行扩展。

于 2015-04-10T04:44:27.047 回答