代码之家  ›  专栏  ›  技术社区  ›  nikow

使用一个方法中的docstring自动覆盖另一个方法中的docstring

  •  2
  • nikow  · 技术社区  · 16 年前

    问题是:我有一个包含模板方法的类 execute 它调用另一个方法 _execute . 子类应该覆盖 执行死刑 实现一些特定的功能。此功能应记录在 执行死刑 . 高级用户可以创建自己的子类来扩展库。但是,处理此类子类的另一个用户应该只使用 执行 ,所以如果他使用 help(execute) .

    因此,最好以这样的方式修改基类:在子类中 执行 自动替换为 执行死刑 . 你知道怎么做吗?

    我在考虑使用元类来实现这一点,使之对用户完全透明。

    5 回复  |  直到 13 年前
        1
  •  4
  •   Sylvain Defresne    16 年前

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

    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
    
        2
  •  2
  •   dF.    16 年前

    是否有原因不能重写基类的 execute 直接作用?

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

    如果您不想执行上述操作:

    方法对象不支持写入 __doc__ 属性,因此必须更改 第二讲 在实际函数对象中。由于您不想重写基类中的一个子类,因此必须为每个子类提供自己的 执行 :

    class Derived(Base):
        def execute(self):
            return Base.execute(self)
    
        class _execute(self):
            """Docstring for subclass"""
            ...
    
        execute.__doc__= _execute.__doc__
    

    但这类似于一种迂回的重新定义方法 执行

        3
  •  1
  •   _Mark_    16 年前

    看看functools.wrapps()修饰器;它可以完成所有这些工作,但是如果您能让它在正确的上下文中运行,我现在还不知道。

        4
  •  0
  •   John Montgomery    16 年前

    文档字符串存储在 __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__
    
    

    必须重新声明execute以使doc字符串附加到execute的版本。 SubClass 而不是为了 MyClass (否则会干扰其他子类)。

    这不是一种非常整洁的方法,但从库用户的POV来看,它应该给出所需的结果。然后你可以用一个元类来包装这一点,以使子类的人更容易理解。

        5
  •  0
  •   Eli Courtwright    16 年前

    我同意最简单、最简单的方法是在子类中重新定义execute,并让它调用基类的execute方法:

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

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

    如果您希望使用一种草率而冗长的方式来确保动态生成用于执行的docstring,那么您可以使用描述符协议,该协议的代码比这里的其他建议要少得多。这很烦人,因为您不能只在现有函数上设置描述符,这意味着必须使用 __call__ 方法。

    下面是实现这一点的代码,但请记住,我上面的示例非常简单,而且更像是蟒蛇:

    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!"