使用元类继承类字典

时间:2017-04-28 16:01:11

标签: python python-3.x inheritance metaclass

我正在使用元类设置类属性fields

class MyMeta(type):
    def __new__(mcs, name, bases, clsdict):

        clsdict['fields'] = {k: v
                             for k, v in clsdict.items()
                             if <my_condition>}
        return super(MyMeta, mcs).__new__(mcs, name, bases, clsdict)

class MyBaseClass(metaclass=MyMeta):
    fields = {}

以下实例化会产生预期结果:

class SubClass(MyBaseClass):
    param1 = 1 # meets <my_condition>

>>> SubClass.fields
{param1: 1}

但如果我现在继承SubClassfields为空:

class SubSubClass(SubClass):
   pass

>>> SubSubClass.fields 
{}

如何更新继承层次结构中所有类的classdict,以便从基类更新fields变量?

2 个答案:

答案 0 :(得分:4)

你需要以某种方式保留超类的public Flowable<List<Book>> getItems(String query) {} textChangeSubscriber .debounce(300, TimeUnit.MILLISECONDS) .observeOn(Schedulers.computation()) .switchMap(s -> getItems(s).toObservable()) .flatMapIterable(items -> items) .map(Book::convert) .toList() .observeOn(AndroidSchedulers.mainThread()) .subscribe(books -> { Log.i("test", "" + books.toString()); }, error -> { Log.i("test", "" + error); }); getItems(query).flatMapIterable(items -> items) .map(Book::convert) .toList() .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(books -> { Log.i("test", "" + "" + books.toString()); }, error -> { Log.i("test", "" + error); }); ,例如通过迭代“基础”并使用他们的fields作为起点:

fields

适用于class MyMeta(type): def __new__(mcs, name, bases, clsdict): if 'fields' not in clsdict: clsdict['fields'] = {} # Initialize "fields" from base classes for base in bases: try: clsdict['fields'].update(base.fields) except AttributeError: pass # Fill in new fields (I included a "trivial" condition here, just use yours instead.) clsdict['fields'].update({k: v for k, v in clsdict.items() if k.startswith('param')}) return super(MyMeta, mcs).__new__(mcs, name, bases, clsdict) SubClass

SubSubClass

答案 1 :(得分:1)

我建议将fields转换为属性描述符,该描述符从父类中获取_fields的所有内容。这样,您还可以更轻松地自定义名称冲突等时发生的情况。

class MyMeta(type):
    def __new__(mcs, name, bases, clsdict):
        # change fields to _fields
        clsdict['_fields'] = {k: v
                             for k, v in clsdict.items()
                             if <my_condition>}
        return super(MyMeta, mcs).__new__(mcs, name, bases, clsdict)
    @property
    def fields(cls):
        # reversed makes most recent key value override parent values
        return {k:v 
                for c in reversed(cls.__mro__) 
                for k,v in getattr(c, '_fields', {}).items() }

用法:

class MyBaseClass(metaclass=MyMeta):
    fields = {}

class SubClass(MyBaseClass):
    param1 = 1

>>> SubClass.fields
{param1: 1}

class SubSubClass(SubClass):
   pass

>>> SubSubClass.fields 
{param1: 1} # success

现在,SomeChildClass.fields的使用总是引用元类属性。 getattr的第三个参数允许没有_fields属性的类(例如object)以静默方式失败。

使用描述符还具有防止子类意外覆盖fields属性的优点:

>>> SubSubClass.fields = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

如果需要,您还可以创建一个setter,并在__init__方法中使用它(即,返回使用fields而不是_fields),以便完整的其余部分该类是实现不可知的:

    @fields.setter
    def fields(cls, mapping):
        try:
            cls._fields.update(**mapping)
        except AttributeError:
            cls._fields = dict(**mapping)