问题描述
我有一个基类 Base
和两个子类 Foo
和 Bar
。在 Base
中,我定义了一个带有可选参数的函数。在运行时(而不是在定义时)给定或获取此参数。总是以相同的确切方式获取参数,这导致子类具有样板代码行(确保只有一行,但这只是示例)。通常,它看起来像这样:
I have a base class Base
and two sub classes Foo
and Bar
. In Base
I define a function with an optional argument. This argument is either given or fetched at runtime (not at definition time). The argument is always fetched in the same exact way, which leads to subclasses having a boilerplate line of code (sure it's one line, but it's just an example). Normally this would look like this:
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 __
中切换,因此调用/重写该方法会感觉正常:
Now I came up with a hack that solves this problem, but I don't find this to be a solid solution. The solution involves defining a private method that wraps the overridden method and supplies it with the correct value. Both methods are switched in the __init__
so calling/overriding the method feels 'normal':
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))
我想出的解决方案带来的问题是,不清楚该名称是否是可选的,因为它看起来好像没有
The 'solution' I came up with poses the problem that it's not clear that name is optional since it looks like it doesn't have a default value.
在某些情况下, Base
是抽象基类,在某些情况下不是,所以我正在寻找一种同时支持两者的解决方案。
In some cases Base
is an abstract base class and in some cases it's not, so I'm looking for a solution that supports both.
推荐答案
您可以使用元类
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
In this case any class derived from Base
will be modified so that method greet will be renamed to _greet and greet method will be created which will run _greet
这篇关于覆盖方法的默认参数值(防止样板)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!