运行一组特定的子类方法而不显式调用它们

时间:2014-08-07 08:50:38

标签: python class-design

我在Python中实现以下内容:(下面的代码框架)

    class Base(object):

        def __init__(self, run_ext):
        def common_method1(self, run_ext):
        def common_method2(self, run_ext):


        def run_all(self):
             """Run all the methods beginning with run*"""  

    class Ext1(Base):

        def run11(self):
        def run12(self):

        def notrelated11(self):


    class Ext2(Base):

        def run21(self):
        def run22(self):

        def notrelated21(self):


Ext1.run_all()  # should run all the *'run*'* methods in Ext1 and 
Ext2.run_all()  # should run all the *'run*'* methods in Ext2.

目标: 在基类中实现run_all(),该类在调用时将从子类运行一组特定的方法。

思想:   - 实现它的方法是通过显式调用子类中的方法并将父类中的run_all定义为抽象方法。   - 有点hacky方式是设置属性(或标识由其名称运行的方法)。

我正在寻找更好的替代解决方案..

  • 还想知道这个问题是否适合任何现有的设计模式?

注意:子类可能包含其他方法,而不仅仅是run1,run2 ..上面提到的not_related方法。

更新:正如@mkriheli指出的那样,基类不会/不应该知道从它继承的子类。

感谢。

2 个答案:

答案 0 :(得分:2)

如何使用装饰器:

import inspect

def runnable(f):
  setattr(f, '__can_run__', True)
  return f

class Base:
  def run_all(self):
    for runner_name in inspect.getmembers(self, predicate=inspect.ismethod):
      func = getattr(self, runner_name[0])
      if hasattr(func, '__can_run__'):
        if getattr(func, '__can_run__'):
          func()

class Child(Base):
  def __init__(self):
    self.incremental = 0

  @runnable
  def run1(self):
    self.incremental += 1
    print "running", self.incremental

  @runnable
  def run2(self):
    self.incremental += 1    
    print "running", self.incremental


c = Child()
c.run_all()

输出:

running 1
running 2

请注意,我不建议使用inspect,并且您可能会以更好的方式尝试。 inspect是一个CPython实现功能,并不保证在其他Python实现中存在。不要Wrong Thing To Do

答案 1 :(得分:0)

遵循@Nandeep的想法,免费检查

class runnable(object):
  run_list = []
  @staticmethod
  def add(f):
    runnable.run_list.append(f)

class Base:
  def run_all(self):
    for runner_name in runnable.run_list:
      # Now you have all the functions


class Child(Base):
  def __init__(self):
    self.incremental = 0

  @runnable.add
  def run1(self):
    self.incremental += 1
    print "running", self.incremental