在Python中将类属性反向映射到类
我有一些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 个回答
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>
和某些人的回答不同,你不需要给你的类添加装饰器(虽然这是个不错的解决方案)。不过,无法排除任何在全局命名空间中的类。
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
看了不同的方式,我觉得使用装饰器的方式会是最舒服的选择。