I am searching for the proper way to call an abstract base class' method from an instance of a class that is registered as a subclass of the ABC. This is some very basic test code to first figure out how to make this work. This is where I am currently at:
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)
While this approach may seem overly involved to alter the two Dog methods, I am looking to have the flexibility of being able to assign the behaviors to an unknown amount of instances. I'd like to be able to call speak() and move() without the instance knowing the actual behavior. I also like this approach because I am able to easily remove or change the behavior that a class is registered too, without altering any existing code.
The way the code reads currently nora.speak() and nora.move() call the inherited methods from Dog to Beagle, which just contain pass.
I'd appreciate if anyone has any insight on what I need to do from this point to make the registered behavior's methods callable, or if my approach is flawed entirely.
Here is my attempt (probably not the most pythonic way, but something close to your post):
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"
(It is good practice to let exceptions to bubble up)
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'
You can chose what you want to delegate:
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'
And create other animals that with more skills:
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'
You can specific things to individual classes, and even defaults, to the main class, and you can extended as you want/need.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.