如何在定义类时自动注册一个类
我希望在定义类时注册一个类实例。理想情况下,下面的代码可以解决问题。
registry = {}
def register( cls ):
registry[cls.__name__] = cls() #problem here
return cls
@register
class MyClass( Base ):
def __init__(self):
super( MyClass, self ).__init__()
不幸的是,此代码生成错误NameError: global name 'MyClass' is not defined
。
发生了什么是在#problem here
线我试图实例化一个MyClass
但装饰者还没有返回,所以它不存在。
是不是在使用元类或类似的东西?
没有找到相关结果
已邀请:
5 个回复
氏脑
方法返回类,所以只需在返回之前注册该类。
上一个示例适用于Python 2.x.在Python 3.x中,
的定义略有不同(而
没有显示,因为它没有变化 - 除非
可以变成
如果你想要的话):
从Python 3.6开始,还有一个新的
方法(参见PEP 487)可以用来代替元类(感谢@matusko的下面的答案):
[编辑:修复缺失
参数为
] [编辑:添加了Python 3.x示例] [编辑:修正了args到super()的顺序,并改进了3.x差异的描述] [编辑:添加Python 3.6
示例]
醒荒捆府绣
钩子,用于初始化给定类的所有子类。 提案包括以下子类注册示例
在这个例子中,
将包含一个简单的列表 整个继承树中的所有子类。应该注意到这一点 这也很适合作为mixin类。
凡夕
方法中的
调用引起的。如果您使用dappawit建议的元类,问题仍然存在;这个答案的例子的原因很简单,就是dappawit通过省略
类并因此省去了
来简化了你的例子。在以下示例中,
和
都不起作用:
在这两种情况下问题都是一样的;在创建类对象之后,但在绑定到名称之前,调用
函数(由元类或直接作为装饰器)。这就是
变得粗糙的地方(在Python 2.x中),因为它要求你在
调用中引用类,你只能通过使用全局名称并相信它将被绑定到该名称来合理地做到这一点。到调用
调用时。在这种情况下,这种信任是错误的。 我认为元类是错误的解决方案。元类用于创建具有一些共同的自定义行为的类族,正如类用于创建具有一些共同的自定义行为的实例族。你所做的只是在一个类上调用一个函数。您不会定义一个类来调用字符串上的函数,也不应该定义一个元类来调用类上的函数。 因此,问题是:(1)在类创建过程中使用钩子来创建类的实例,以及(2)使用
之间的基本不兼容性。 解决这个问题的一种方法是不使用
。
解决了一个难题,但它引入了其他人(这是其中之一)。如果你使用复杂的多重继承方案,
的问题比不使用
的问题要好,如果你继承的是使用
的第三方类,那么你必须使用
。如果这两个条件都不成立,那么用直接基类调用替换你的
调用实际上可能是一个合理的解决方案。 另一种方法是不要将
挂钩到课堂创作中。在每个类定义之后添加
非常相当于在它们之前添加
或者将
(或者你称之为元类的任何内容)添加到它们中。尽管如此,底部的一行不如自我记录的那么好,所以这感觉不太好,但实际上它可能是一个合理的解决方案。 最后,你可以转向令人不愉快的黑客,但可能会奏效。问题是在模块绑定到模块的全局范围之前正在查找名称。所以你可以作弊,如下:
这是如何工作的: 我们首先检查
是否在
(而不是它是否具有
属性,这将始终为真)。如果它从另一个类继承了一个
方法,我们可能会很好(因为超类已经以通常的方式绑定到它的名字),而我们即将做的魔法不适用于
所以我们想要如果班级使用默认值
,请避免尝试。 我们查找
方法并抓住它的
字典,这是全局查找(例如查找
调用中提到的类)的地方。这通常是最初定义
方法的模块的全局字典。这样的字典即将在
返回时插入
,所以我们只是提前插入它。 我们最终创建一个实例并将其插入到注册表中。这是在try / finally块中,以确保我们删除我们创建的绑定,无论创建实例是否抛出异常;这是不太可能的必要(因为99.999%的时间名称即将反弹),但最好保持像这样的奇怪魔法尽可能绝缘,以尽量减少有一天其他一些奇怪的魔法与之交互不良的可能性它。 这个版本的
无论是作为装饰器调用还是由元类调用(我仍然认为它不能很好地利用元类)。有一些不起眼的情况会失败但是: 我可以想象一个奇怪的类没有
方法但是继承了一个叫
的方法,并且
在被定义的类中被覆盖并且进行了
调用。可能不太可能。
方法可能最初在另一个模块中定义,然后通过在类块中执行
在类中使用。但是,另一个模块的
属性,这意味着我们的临时绑定会破坏该模块中该类名称的任何定义(oops)。再一次,不太可能 可能是其他我没有想到的奇怪案例。 在这些情况下,您可以尝试添加更多黑客以使其更加强大,但Python的本质是这些黑客都是可能的,并且不可能使它们绝对是防弹。
绵扇寸访
盟犯涩沟都
不起作用。 这是我的代码在定义时注册类的所有子类: