最佳实践:更新/扩展子类类属性

时间:2015-07-16 22:17:44

标签: python oop

这只是一点点好奇心。我经常发现自己更新了一个继承在子类中的类属性,我想知道其他人如何处理它。我知道我无法在__init__中更新它们:因为它是一个类属性,我也会将它更新为超类实例。所以我通常做这样的事情:

class A(object):
    attribute = {
        1: 'a',
        ...,
        5: 'e',
    }

class B(A):
    attribute = {
        1: 'a',
        ...,
        5: 'e',
        6: 'f',
    }

但是,因为我喜欢尽可能地遵循DRY原则,并且我想知道是否有人使用更优雅的方式来完成此操作而无需完全复制和粘贴属性。

如所述,这是Django表格的具体示例:

class LoginForm(AuthenticationForm):

    username = forms.EmailField(label=_('Email'))

    error_messages = {
        'inactive': _('This account is inactive.'),
        'invalid_login': _('Please enter a correct username and password. '
                           'Note that both fields may be case-sensitive.'),
        'unconfirmed': _('Your account is not confirmed yet. Please '
                         'check your email and follow the instructions '
                         'in order to activate it.'),
    }

    def confirm_login_allowed(self, user):
        super(LoginForm, self).confirm_login_allowed(user)
        if not user.confirmed:
            raise forms.ValidationError(
                self.error_messages['unconfirmed'],
                code='unconfirmed')

error_messages 属性继承自django.contrib.auth.forms.AuthenticationForm,但我想添加“未确认”密钥,因此我必须复制并粘贴'inactive'和'invalid_login'钥匙也是。

2 个答案:

答案 0 :(得分:3)

如果你把它放在__init__中,那么每个子类的实例(在这种情况下为B)都会看到更新。如果您直接指定类,则唯一不会出现的情况是:

B.attribute[6]
# KeyError

不使用__init__的一种方法是:

class B(A):
    attribute = A.attribute.copy()
    attribute.update({
          6: 'f',
          7: 'g',
          })

print(B().attribute) # --> {1:'a', ..., 5:'e', 6:'f', 7:'g'}
print(A().attribute) # --> {1:'a', ..., 5:'e'}

需要记住的是,类的代码在创建时执行,因此您可以使用普通的Python进行调整。

答案 1 :(得分:1)

这似乎有效:

class A(object):
    attribute = {
        1: 'a',
        5: 'e',
    }

class B(A):
    attribute = A.attribute.copy()
    attribute[6] = 'f'

print(A.attribute)  # -> {1: 'a', 5: 'e'}
print(B.attribute)  # -> {1: 'a', 5: 'e', 6: 'f'}