来自重写方法的默认参数值(防止样板)

时间:2013-05-31 08:19:40

标签: python default-value boilerplate

我有一个基类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))

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

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

2 个答案:

答案 0 :(得分: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))

答案 1 :(得分: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方法