将类属性反向映射到Python中的类

时间:2009-08-11 23:11:59

标签: python metaclass

我在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字典。我有一种直觉,有一个元类产生A和B是正确的方法来解决这个问题;那似乎没错?

2 个答案:

答案 0 :(得分:5)

可以使用元类在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

观察不同的变体,我认为装饰器版本将是最令人愉快的。

答案 1 :(得分:3)

首先需要一些数据结构来存储适用类的列表,但您不必首先生成它。您可以从全局变量中读取类。这自然会假设您的课程延伸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>

与某人的回答不同,您不必在类中添加装饰器(尽管是简洁的解决方案)。但是,没有办法排除全局命名空间中的任何类。

相关问题