繁体   English   中英

Python mixin扩展了类属性

[英]Python mixin to extend class property

试图找出如何为Django管理命令编写一些mixins,它将包装BaseCommand.option_list而不会丢失当前类或任何继承的类/ mixins的值。 目标是避免在我的命令中执行BaseCommand.option_list + MyCommonOptionMixin.option_list + MyOtherCommonOptionMixin.option_list + ( local command options )

例:

class BaseCommmand(object):
    option_list = (
        # Default options here.
    )

    # Rest of BaseCommand code. 

我用一些常见的选项定义了一个mixin:

class MyCommonOptionMixin(object):
    option_list = (
        # Some common option/options I wish to have available in many commands
    )

    def __getattribute__(self, name):
        values = super(MyCommonOptionMixin, self).__getattribute__(name)
        if name == 'option_list':
            for option in self.option_list:
                if option not in values:
                    values += option,
        return values

也许我还有一个,只是为了涵盖我有多个的情况。 mixin都覆盖了__getattribute__

class MyOtherCommonOptionMixin(object):
    option_list = (
        # Maybe I have another mixin I want to define separately
    )

    # Tried this, does not work with more than one mixin. 
    def __getattribute__(self, name):
        values = super(MyOtherCommonOptionMixin, self).__getattribute__(name)
        if name == 'option_list':
            for option in self.option_list:
                if option not in values:
                    values += option,
        return values

    # Works if the mixin defines the option_list under a different name, e.g. "_mymixin_options"
    # Then access at self._mymixin_options instead of self.option_list


class MyCommand(MyCommonOptionMixin, MyOtherCommonOptionMixin, BaseCommand):
    option_list = BaseCommand.option_list + (
        # Local defined options.
    )

如果mixins对option_list属性使用相同的名称,我会遇到冲突。 是否有更简洁的方法来实现这一目标,而不是在mixins中唯一地命名option_list并覆盖__getattribute__

文档中的建议是明确地连接各种选项列表。 也就是说,如果你想走这条路线,我认为自定义元类是正确的方法。 就像是:

class CommandMetaclass(type):
    def __new__(mcl, name, bases, dct):
        # start with the option_list in the class we're creating
        # use set() to avoid duplicates
        option_list = set(dct.get('option_list', tuple()))

        # add the options from each base class
        for base in bases:
            option_list.update(base.__dict__.get('option_list', tuple()))

        # replace the original option_list with our combined version
        dct['option_list'] = tuple(option_list)

        return type.__new__(mcl, name, bases, dct)

class MyCommand(MyCommonOptionMixin, MyOtherCommonOptionMixin, BaseCommand):
    __metaclass__ = CommandMetaclass

    option_list = ( 
        # Local defined options.
    )

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM