【问题标题】:Reverse mapping class attributes to classes in Python将类属性反向映射到 Python 中的类
【发布时间】:2010-11-18 19:22:31
【问题描述】:

我有一些 Python 代码,其中有一堆类,每个类都有一个属性 _internal_attribute。我希望能够生成这些属性到原始类的映射。基本上我希望能够做到这一点:

class A(object):
    _internal_attribute = 'A attribute'
class B(object):
    _internal_attribute = 'B attribute'

a_instance = magic_reverse_mapping['A attribute']()
b_instance = magic_reverse_mapping['B attribute']()

我在这里缺少的是如何生成magic_reverse_mapping dict。我有一种直觉,让元类生成 A 和 B 是解决此问题的正确方法;看起来对吗?

【问题讨论】:

    标签: python metaclass


    【解决方案1】:

    您首先需要一些数据结构来存储适用类的列表,但您不必首先生成它。您可以改为从全局变量中读取类。这自然假设您的类扩展了object,就像您在第一篇文章中所做的那样。

    def magic_reverse_mapping(attribute_name, attribute_value):
        classobjects = [val for val in globals().values() if isinstance(val, object)]
        attrobjects = [cls for cls in classobjects if hasattr(cls, attribute_name)]
        resultobjects = [cls for cls in attrobjects if object.__getattribute__(cls, attribute_name) == attribute_value]
        return resultobjects
    
    magic_reverse_mapping('_internal_attribute', 'A attribute')
    #output:   [<class '__main__.A'>]
    

    请注意,这会返回具有该属性值的类的列表,因为可能不止一个。如果你想实例化第一个:

    magic_reverse_mapping('_internal_attribute', 'A attribute')[0]()
    #output:   <__main__.A object at 0xb7ce486c>
    

    与某事的答案不同,您不必为您的课程添加装饰器(不过,这是一个很好的解决方案)。但是,无法排除全局命名空间中的任何类。

    【讨论】:

    • “类列表”正是我想要避免的,这意味着每当我添加一个新的子类时,我必须记住将它添加到两个地方。
    • 嗯,我现在更喜欢这个后期编辑...不过,我确实认为我会使用装饰器解决方案。它更明确,感觉不那么神奇。
    • @wxs:谢谢。你措辞的方式听起来很正确......sth的解决方案更Pythonic。
    【解决方案2】:

    可以使用元类在magic_reverse_mapping 中自动注册您的类:

    magic_reverse_mapping = {}
    
    class MagicRegister(type):
       def __new__(meta, name, bases, dict):
          cls = type.__new__(meta, name, bases, dict)
          magic_reverse_mapping[dict['_internal_attribute']] = cls
          return cls
    
    class A(object):
        __metaclass__ = MagicRegister
        _internal_attribute = 'A attribute'
    
    afoo = magic_reverse_mapping['A attribute']()
    

    或者,您可以在您的类上使用装饰器来注册它们。我认为这更具可读性和更容易理解:

    magic_reverse_mapping = {}
    
    def magic_register(cls):
       magic_reverse_mapping[cls._internal_attribute] = cls
       return cls
    
    @magic_register
    class A(object):
        _internal_attribute = 'A attribute'
    
    afoo = magic_reverse_mapping['A attribute']()
    

    或者您甚至可以手动完成。如果不使用任何魔法,这并没有那么多工作:

    reverse_mapping = {}
    
    class A(object):
        _internal_attribute = 'A attribute'
    
    reverse_mapping[A._internal_attribute] = A
    

    查看不同的变体,我认为装饰器版本使用起来最愉快。

    【讨论】:

    • 请注意,类装饰器需要 Python >= 2.6。
    • 装饰器解决方案似乎很完美,出于某种原因,我认为类装饰器只是 Py3k。我责怪 PEP-3129 说它们包含在 3k 中,而没有提到它们也在 2.6 中。
    猜你喜欢
    • 2012-09-23
    • 2020-09-14
    • 1970-01-01
    • 1970-01-01
    • 2015-10-02
    • 1970-01-01
    • 2021-04-30
    • 2018-04-21
    • 2017-03-16
    相关资源
    最近更新 更多