覆盖方法的默认参数值(防止样板) [英] Default argument value from overridden method (preventing boilerplate)

查看:138
本文介绍了覆盖方法的默认参数值(防止样板)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

这篇关于覆盖方法的默认参数值(防止样板)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆