我在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是正确的方法来解决这个问题;那似乎没错?
答案 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>
与某人的回答不同,您不必在类中添加装饰器(尽管是简洁的解决方案)。但是,没有办法排除全局命名空间中的任何类。