简体   繁体   English

Python:__subclasses__ order

[英]Python: __subclasses__ order

I have some code that creates a list of (instances of) subclasses by calling the __subclasses__() function on a base class. 我有一些代码通过在基类上调用__subclasses__()函数来创建子类的(实例)列表。

subclasses = [subclass() for subsclass in BaseClass.__subclasses__()]

In Python 2.7 the order of the subclasses in this list is always equal to the order of the import statements in my code (each subclass is defined in it's own Python file). 在Python 2.7中,此列表中子类的顺序始终等于我的代码中的import语句的顺序(每个子类在其自己的Python文件中定义)。 But in Python 3.5 the order of subclasses in this list seems random. 但是在Python 3.5中,此列表中的子类顺序似乎是随机的。 Can I use some kind of workaround to get the same behavior in Python 3.5? 我可以使用某种解决方法在Python 3.5中获得相同的行为吗?

See the class.__subclasses__ documentation . 请参阅class.__subclasses__文档

In Python 3.5, there is not, not by any trivial means. 在Python 3.5中,没有任何琐碎的手段。 As of Python 3.4 the tp_subclasses data structure tracks subclasses via a dictionary (mapping the id() value of the subclass to a weak reference, see Python issue #17936 for why). 从Python 3.4开始tp_subclasses数据结构通过字典跟踪子类(将子类的id()值映射到弱引用,请参阅Python问题#17936,了解原因)。 Dictionaries are unordered. 字典是无序的。

In Python 3.6, the internal implementation of dictionaries was changed, and they now track insertion order. 在Python 3.6中,字典的内部实现已更改,现在它们跟踪插入顺序。 When you upgrade to Python 3.6, you'd get your subclasses in insertion order (order in which they are first seen by Python) again. 当您升级到Python 3.6时,您将再次以插入顺序(Python首次看到它们的顺序)获取子类。

However, the fact that subclasses are tracked in a dictionary is an implementation detail and should not really be relied upon. 但是,在字典中跟踪子类的事实是一个实现细节,不应该真正依赖它。

You could track the order by some other means. 您可以通过其他方式跟踪订单。 You could give your base class a metaclass that records subclasses in order, for example: 您可以为基类提供按顺序记录子类的元类,例如:

from itertools import count
from weakref import WeakKeyDictionary

class SubclassesInOrderMeta(type):
    _subclass_order = WeakKeyDictionary()
    _counter = count()

    def __ordered_subclasses__(cls):
        # sort subclasses by their 'seen' order; the sort key
        # puts classes that are missing from the _subclass_order
        # mapping at the end, defensively.
        order_get = type(cls)._subclass_order.get
        sort_key = lambda c: order_get(c, float('inf'))
        return sorted(cls.__subclasses__(), key=sort_key)

    def __new__(mcls, *args, **kwargs):
        cls = super(SubclassesInOrderMeta, mcls).__new__(mcls, *args, **kwargs)
        mcls._subclass_order[cls] = next(mcls._counter)
        return cls

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

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