2008-09-16 112 views
2

问题:我有一个类,它包含一个模板方法execute,它调用另一个方法_execute。子类应该覆盖_execute以实现一些特定的功能。此功能应记录在_execute的文档字符串中。高级用户可以创建自己的子类来扩展库。但是,处理这种子类的另一个用户应该只使用execute,因此如果他使用help(execute),他将看不到正确的文档字符串。从一种方法中使用docstring自动覆盖另一种方法

因此,修改基类应该很好,因为在子类中,execute的文档字符串会自动替换为_execute的文档字符串。任何想法如何做到这一点?

我正在考虑元类来做到这一点,使这对用户完全透明。

+0

是否有任何很好的理由,为什么执行的文档字符串不能只读“不......”然后调用_execute,哪些子类预计会覆盖;查看_execute的文档以获取详细信息“? 如果用户需要提供基类,那么这似乎是最为Pythonic的方法。 – 2008-09-16 14:41:23

+0

它只是觉得有点不对,如果用户输入帮助(o.execute),他会a)不会得到他可能想要的信息,并且b)被告知查看一些可疑的方法_execute,可能他甚至不知道存在。对于图书馆的一个天真的用户来说,这只是太多的实现细节。 – nikow 2008-09-27 17:27:49

回答

4

好吧,如果您不介意复制子类中的原始方法,则可以使用以下技术。

import new 

def copyfunc(func): 
    return new.function(func.func_code, func.func_globals, func.func_name, 
         func.func_defaults, func.func_closure) 

class Metaclass(type): 
    def __new__(meta, name, bases, attrs): 
     for key in attrs.keys(): 
      if key[0] == '_': 
       skey = key[1:] 
       for base in bases: 
        original = getattr(base, skey, None) 
        if original is not None: 
         copy = copyfunc(original) 
         copy.__doc__ = attrs[key].__doc__ 
         attrs[skey] = copy 
         break 
     return type.__new__(meta, name, bases, attrs) 

class Class(object): 
    __metaclass__ = Metaclass 
    def execute(self): 
     '''original doc-string''' 
     return self._execute() 

class Subclass(Class): 
    def _execute(self): 
     '''sub-class doc-string''' 
     pass 
0

那么文档字符串存储在__doc__所以根据事实后的文档字符串_execute重新分配它不会太难。

基本上:

 
class MyClass(object): 
    def execute(self): 
     '''original doc-string''' 
     self._execute() 

class SubClass(MyClass): 
    def _execute(self): 
     '''sub-class doc-string''' 
     pass 

    # re-assign doc-string of execute 
    def execute(self,*args,**kw): 
     return MyClass.execute(*args,**kw) 
    execute.__doc__=_execute.__doc__ 

执行必须被重新声明到doc字符串被附接到执行用于​​而不是为了MyClass(否则会与其他子干扰的版本类)。

这不是一个非常整洁的方式,但是从库的用户的POV它应该给出想要的结果。然后,您可以将它包装在一个元类中,以便让子类更容易分类。

+0

问题是我希望用户编写子类而不用编写用于文档字符串操作的任何样板代码。任何想法如何处理这与metaclasses在一个更好的方式比我上面提到的丑陋的解决方案? – nikow 2008-09-16 13:46:41

2

有没有理由不能直接覆盖基类的execute函数?

class Base(object): 
    def execute(self): 
     ... 

class Derived(Base): 
    def execute(self): 
     """Docstring for derived class""" 
     Base.execute(self) 
     ...stuff specific to Derived... 

如果你不想做以上:

Method对象不支持写入到__doc__属性,所以你必须在实际的函数对象改变__doc__。既然你不希望重写一个在基类中,你必须给每个子类的execute自己的副本:

class Derived(Base): 
    def execute(self): 
     return Base.execute(self) 

    class _execute(self): 
     """Docstring for subclass""" 
     ... 

    execute.__doc__= _execute.__doc__ 

但这是类似于重新定义execute的一种迂回的方式...

+0

动机是用户编写自己的子类。我现在在原始问题中澄清了这一点。 – nikow 2008-09-16 13:51:57

0

我同意处理这个的最简单,最Python的方式是简单地重新定义你的子类执行,并有它调用execute基类的方法:

class Sub(Base): 
    def execute(self): 
     """New docstring goes here""" 
     return Base.execute(self) 

这是非常小代码来完成你想要的东西;唯一的缺点是您必须在扩展Base的每个子类中重复此代码。然而,这是你想要的行为付出的小代价。

如果您希望草率和冗长的方式确保执行的文档字符串是动态生成的,那么您可以使用描述符协议,这比其他方案的代码少得多。这很烦人,因为您不能只在现有函数上设置描述符,这意味着必须使用方法将执行写为单独的类。

下面的代码要做到这一点,但是请记住,我上面的例子更简单,更Python:

class Executor(object): 
    __doc__ = property(lambda self: self.inst._execute.__doc__) 

    def __call__(self): 
     return self.inst._execute() 

class Base(object): 
    execute = Executor() 

class Sub(Base): 
    def __init__(self): 
     self.execute.inst = self 

    def _execute(self): 
     """Actually does something!""" 
     return "Hello World!" 

spam = Sub() 
print spam.execute.__doc__ # prints "Actually does something!" 
help(spam)     # the execute method says "Actually does something!" 
1

看那functools.wraps()装饰;它所有这一切,但我不知道如果你能让它在正确的上下文中运行

相关问题