4

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

因此,最好修改基类,使子类中的文档字符串execute自动替换为_execute. 任何想法如何做到这一点?

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

4

5 回答 5

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
于 2008-09-16T14:02:38.390 回答
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...

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

方法对象不支持写入__doc__属性,因此您必须更改__doc__实际的函数对象。由于您不想覆盖基类中的那个,因此您必须为每个子类提供其自己的副本execute

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

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

    execute.__doc__= _execute.__doc__

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

于 2008-09-16T13:31:44.953 回答
1

查看 functools.wraps() 装饰器;它完成了所有这些,但我不知道你是否可以让它在正确的上下文中运行

于 2008-09-16T15:19:05.897 回答
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__

Execute 必须重新声明为文档字符串附加到执行的版本SubClass而不是 for MyClass(否则会干扰其他子类)。

这不是一种非常整洁的方式,但从图书馆用户的 POV 来看,它应该会给出预期的结果。然后,您可以将其包装在一个元类中,以使子类化的人更容易。

于 2008-09-16T13:25:12.177 回答
0

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

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

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

如果您想要一种草率且冗长的方式来确保动态生成执行的文档字符串,您可以使用描述符协议,这将比这里的其他建议少得多的代码。这很烦人,因为您不能只在现有函数上设置描述符,这意味着 execute 必须编写为带有__call__方法的单独类。

这是执行此操作的代码,但请记住,我上面的示例更简单,更 Pythonic:

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!"
于 2008-09-16T14:17:43.780 回答