Python中的类、方法和多态性

3 投票
3 回答
5287 浏览
提问于 2025-04-15 18:25

我做了一个模块原型,目的是在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 个回答

2

这确实是经常使用的,完全没问题。如果你想更小心一点,可以用 hasattr 来检查一下你期待的对象是否真的有一个 run 方法。这可以帮助你确保错误尽可能早地被发现。

不过,除了这个,使用起来是没问题的,大家也经常这么做。

6

基于鸭子类型的方法是可以的。如果你想检查某个类是否适合在你的框架中运行,可以使用抽象基类(需要Python 2.6)。PEP 3119提到:

[...] 有很多种方法可以测试一个对象是否符合特定的协议。例如,如果问“这个对象是可变序列容器吗?”,可以查看它是否是“list”的子类,或者看看它是否有一个叫getitem的方法。但要注意,虽然这些测试看起来很明显,但它们都不完全正确,因为一个会产生假阴性,另一个会产生假阳性。[...] 这个PEP提出了一种组织这些测试的特定策略,称为抽象基类,或者ABC。ABC就是一些Python类,它们被添加到对象的继承树中,以便向外部检查者表明该对象的某些特性。测试是通过使用isinstance()来完成的,某个特定的ABC存在就意味着测试通过了。

你可以实现一个ABC,并使用isinstanceissubclass来测试类或实例是否是为你的框架编写的:

from abc import ABCMeta, abstractmethod

class Runnable(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def run(self):
        raise NotImplementedError

 class Schedule(Runnable):
     ...

重要的一点是,你也可以注册其他类(你可能无法控制这些类,因为你并没有编写它们)作为可运行的类,而isinstanceissubclass方法会反映这一点:

  >>> issubclass(SomeOtherClass, Runnable)
  False
  >>> Runnable.register(SomeOtherClass)
  >>> issubclass(SomeOtherClass, Runnable)
  True
3

这被称为鸭子类型,在Python中经常用到。

撰写回答