python - 通常此类方法的第一个参数名为“mcs”
问题描述
我在以下元类中收到了令人惊讶的 PyCharm 警告
通常此类方法的第一个参数名为“mcs”
这是我不知道的一些约定,比如命名第一个参数self
还是cls
?我尝试搜索 SO 但没有找到任何命中。代码取自这篇文章。
class Meta(type):
def __prepare__(metaclass, cls, bases):
return dict()
def __new__(metacls, cls, bases, clsdict):
return super().__new__(metacls, cls, bases, clsdict)
解决方案
对于元类,通常是“类方法”的方法 - 就像__prepare__
并将__new__
在第一个参数上接收元类本身。
关于该参数的命名没有约定。通常人们不知道或根本不担心元类真正发生的全部情况,只会简单地命名它们cls
,就好像它是一个正常的类,然后生活就会随之而来。我相信大多数 IDE 不会识别其他任何东西,如果突出显示的“正确”使用“cls”和“self”作为方法的第一个参数,它们甚至可能会将其他任何东西标记为“错误”。必须始终牢记,这些只是惯例 - 短绒和语法荧光笔远不如人类思维灵活(至少目前如此),不应将它们视为法律。
也就是说,与名称“cls”和“self”不同,当第一个参数是元类本身时,没有严格的约定——我通常将它命名为mcls
,但mcs
会很好,虽然metaclass
有点危险,因为它是保留的类定义本身中的关键字(使用class
语句时)。
但是,参数中使用的类恰好metaclass
是传递给元类方法的第一个参数的类,因此,是的,如果元类中的第一个参数名为__new__
,它可能会“修复不一致” 。(我从来没想过那个)。__new__
metaclass
换句话说,当用 定义一个类时class MyClass(ClassA, ClassB, metaclass=MyMeta):
, 的MyMeta
第一个参数传递的是MyMeta.__new__
,如果它是 命名metaclass
的,就好像Python 将它作为“命名参数”传递一样。即使在class
语句方面,metaclass
名称在语言定义中是硬编码的,并且在def __new__
另一方面,将使用第一个参数上的任何名称。
In [98]: class M(type):
...: def __new__(metaclass, name, bases, namespace, **kwargs):
...: return super().__new__(metaclass, name, bases, namespace, **kwargs)
...:
In [99]: class A(metaclass=M):
...: pass
无论如何,正如我所说,我通常对mcls
.
相反,同样重要的是:元类上的任何其他方法,普通类上的任何其他方法都self
将作为参数接收class
使用元类创建的 - 所以通常命名它们cls
而不是self
,因为更容易记住元类的实例代表什么。
因此,在方法的元类中,以及任何有用的方法,第一个参数都有意义,__init__
而不是。__getattr__
__call__
cls
self
回到你的片段之一:
class Meta(type):
def __prepare__(metaclass, cls, bases):
return dict()
def __new__(metacls, cls, bases, clsdict):
return super().__new__(metacls, cls, bases, clsdict)
正如我评论的那样,您可以调用第一个参数,metacls
但第二个参数应该不是。同样:Python 将这些作为有序参数传递,因此如果您将其命名为它会起作用,但它的内容是作为字符串声明的类名,尽管如此。一方面,名称通常表示类本身,在调用这些方法时它甚至不存在——它只会从您在 元类方法内部调用的那一点开始存在。__new__
__prepare__
name
cls
cls
cls
super().__new__
__new__
至于第四个参数,你调用clsdict
,我知道没有严格的约定 -clsdict
足够清楚,就像那样namespace
- 但多年来,我一直在使用 simple dct
,并且ns
有时也使用过。
最后,如上所述,我不希望 PyCharm 或任何其他风格的荧光笔(或“校正器”)比我更好地理解我对元类的意图:我会忽略它们。
推荐阅读
- javascript - 如何找到点数组的中点并继续递归调用直到多次?
- excel - 如何在 VBA 中使用 for 循环进行多种条件格式设置
- c# - 如何使用懒惰
(功能 valueFactory) 以一种方式,如果 init 失败它不应该使用缓存异常并且不应该为 init 运行多个线程 - python - 在 python 中使用生成器函数访问输出的问题
- r - 根据 R 中日期时间的条件连接多列
- apache-camel - 如何使用聚合器选项,例如完成大小、完成超时和拆分聚合
- html - 无法打开索引页面
- laravel - 在 laravel 中创建控制器时有没有办法调用模型?
- css - 仅使用 CSS 背景设计列
- python-3.x - 在 python 3 中使用 subprocess.check_call 运行 Oracle DBCA