我有一个基类Base
和两个子类Foo
和Bar
。在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
是一个抽象基类,在某些情况下它不是,所以我正在寻找一种支持这两者的解决方案。
答案 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方法