Python中的类、方法和多态性
我做了一个模块原型,目的是在Python中创建复杂的定时器计划。这个类的原型模拟了定时器对象,每个定时器都有自己的等待时间,还有重复对象,用来把定时器和其他重复对象组合在一起,最后还有一个计划类,专门用来保存所有的定时器和重复实例。这个结构可以根据需要变得非常复杂,而且需要灵活。
这三个类都有一个 .run()
方法,可以用来执行整个计划。无论是哪种类,.run()
方法要么运行一个定时器,要么运行一个重复组,执行一定次数,要么运行一个计划。
这种面向多态的方式是合理的还是傻的?还有什么其他合适的方法可以考虑,用来构建这样一个多功能的工具,让所有的构建块可以以简单的方式组合得非常复杂?
谢谢!
以下是模块代码:
#####################
## Importing modules
from time import time, sleep
#####################
## Class definitions
class Timer:
"""
Timer object with duration.
"""
def __init__(self, duration):
self.duration = duration
def run(self):
print "Waiting for %i seconds" % self.duration
wait(self.duration)
chime()
class Repeat:
"""
Repeat grouped objects for a certain number of repetitions.
"""
def __init__(self, objects=[], rep=1):
self.rep = rep
self.objects = objects
def run(self):
print "Repeating group for %i times" % self.rep
for i in xrange(self.rep):
for group in self.objects:
group.run()
class Schedule:
"""
Groups of timers and repetitions. Maybe redundant with class Repeat.
"""
def __init__(self, schedule=[]):
self.schedule = schedule
def run(self):
for group in self.schedule:
group.run()
########################
## Function definitions
def wait(duration):
"""
Wait a certain number of seconds.
"""
time_end = time() + float(duration) #uncoment for minutes# * 60
time_diff = time_end - time()
while time_diff > 0:
sleep(1)
time_diff = time_end - time()
def chime():
print "Ding!"
3 个回答
这确实是经常使用的,完全没问题。如果你想更小心一点,可以用 hasattr
来检查一下你期待的对象是否真的有一个 run
方法。这可以帮助你确保错误尽可能早地被发现。
不过,除了这个,使用起来是没问题的,大家也经常这么做。
基于鸭子类型的方法是可以的。如果你想检查某个类是否适合在你的框架中运行,可以使用抽象基类(需要Python 2.6)。PEP 3119提到:
[...] 有很多种方法可以测试一个对象是否符合特定的协议。例如,如果问“这个对象是可变序列容器吗?”,可以查看它是否是“list”的子类,或者看看它是否有一个叫getitem的方法。但要注意,虽然这些测试看起来很明显,但它们都不完全正确,因为一个会产生假阴性,另一个会产生假阳性。[...] 这个PEP提出了一种组织这些测试的特定策略,称为抽象基类,或者ABC。ABC就是一些Python类,它们被添加到对象的继承树中,以便向外部检查者表明该对象的某些特性。测试是通过使用isinstance()来完成的,某个特定的ABC存在就意味着测试通过了。
你可以实现一个ABC,并使用isinstance
或issubclass
来测试类或实例是否是为你的框架编写的:
from abc import ABCMeta, abstractmethod
class Runnable(object):
__metaclass__ = ABCMeta
@abstractmethod
def run(self):
raise NotImplementedError
class Schedule(Runnable):
...
重要的一点是,你也可以注册其他类(你可能无法控制这些类,因为你并没有编写它们)作为可运行的类,而isinstance
和issubclass
方法会反映这一点:
>>> issubclass(SomeOtherClass, Runnable)
False
>>> Runnable.register(SomeOtherClass)
>>> issubclass(SomeOtherClass, Runnable)
True
这被称为鸭子类型,在Python中经常用到。