0

我有一个基类Base和两个子类FooBar. 在Base我定义了一个带有可选参数的函数。此参数在运行时(而不是在定义时)给出或获取。参数总是以完全相同的方式获取,这导致子类具有样板代码行(确保它是一行,但这只是一个示例)。通常这看起来像这样:

class Base(object):
    def greet(self, name=None):
        pass

class Foo(Base):
    def greet(self, name=None):
        name = name or get_name_at_runtime()
        print('Hello {name} this is Foo.'.format(name=name))

class Bar(Base):
    def greet(self, name=None):
        name = name or get_name_at_runtime()
        print('Hello {name} this is Bar.'.format(name=name))

现在我想出了一个解决这个问题的技巧,但我认为这不是一个可靠的解决方案。该解决方案涉及定义一个私有方法,该方法包装被覆盖的方法并为其提供正确的值。两种方法都被切换,__init__因此调用/覆盖该方法感觉“正常”:

class Base(object):
    def __init__(self):
        self.greet, self.__greet = self.__greet, self.greet

    def greet(self, name):
        pass

    def __greet(self, name=None):
        self.__greet(name or get_name_at_runtime())

class Foo(Base):
    def greet(self, name):
        print('Hello {name} this is Foo.'.format(name=name))

class Bar(Base):
    def greet(self, name):
        print('Hello {name} this is Bar.'.format(name=name))

我提出的“解决方案”提出了一个问题,即 name 是否可选,因为它看起来没有默认值。

在某些情况下Base是一个抽象基类,而在某些情况下不是,所以我正在寻找一个支持两者的解决方案。

4

2 回答 2

0

使用装饰器怎么样?这就是他们的本意。就像是:

def get_at_runtime(func):
    def wrapped(*args, **kwargs):
        if kwargs.get('name', None) is None:
            kwargs['name'] = get_name_at_runtime()
        func(*args, **kwargs)

并包装你的方法:

@get_at_runtime
def greet(self, name=None):
    print('Hello {name} this is Foo.'.format(name=name))
于 2013-05-31T08:33:44.670 回答
0

嗨,您可以使用元类

class DefaultNameType(type):
    def __new__(cls, name, bases, attrs):
        if 'greet' in attrs:
            attrs['_greet'] = attrs.pop('greet')
            def greet(self, name=None):
                name = name or self.get_name_at_runtime()
                return self._greet(name)
            attrs['greet'] = greet
        print attrs
        return super(DefaultNameType, cls).__new__(cls, name, bases, attrs)

class Base(object):
    __metaclass__ = DefaultNameType

    def get_name_at_runtime(self):
        return 'foo'

    def greet(self, name):
        pass

class Foo(Base):
    def greet(self, name):
        print('Hello {name} this is Foo.'.format(name=name))

class Bar(Base):
    def greet(self, name):
        print('Hello {name} this is Bar.'.format(name=name))    

    def get_name_at_runtime(self):
        return 'foo1'

在这种情况下,任何派生的类Base都将被修改,以便将方法 greet 重命名为 _greet 并创建将运行 _greet 的 greet 方法

于 2013-05-31T08:57:13.440 回答