PEP 3130 – 访问当前模块/类/函数
- 作者:
- Jim J. Jewett <jimjjewett at gmail.com>
- 状态:
- 已拒绝
- 类型:
- 标准跟踪
- 创建:
- 2007年4月22日
- Python 版本:
- 3.0
- 历史记录:
- 2007年4月22日
拒绝通知
此 PEP 已被拒绝。目前尚不清楚如何实现它,或者在边缘情况下精确的语义应该是什么,并且没有给出足够重要的用例。回应充其量是冷淡的。
摘要
通常需要对当前模块、类或函数的引用,但目前没有完全正确的方法来做到这一点。此 PEP 提出添加关键字 __module__
、__class__
和 __function__
。
__module__
的理由
许多模块导出各种函数、类和其他对象,但在作为脚本运行时会执行其他活动(例如运行单元测试)。目前的习惯用法是测试模块的名称是否已设置为魔术值。
if __name__ == "__main__": ...
更复杂的内省需要模块(尝试)导入自身。如果导入预期名称实际上产生了不同的模块,则没有好的解决方法。
# __import__ lets you use a variable, but... it gets more
# complicated if the module is in a package.
__import__(__name__)
# So just go to sys modules... and hope that the module wasn't
# hidden/removed (perhaps for security), that __name__ wasn't
# changed, and definitely hope that no other module with the
# same name is now available.
class X(object):
pass
import sys
mod = sys.modules[__name__]
mod = sys.modules[X.__class__.__module__]
提案:添加一个 __module__
关键字,它引用当前正在定义(执行)的模块。(但请参阅未解决的问题。)
# XXX sys.main is still changing as draft progresses. May
# really need sys.modules[sys.main]
if __module__ is sys.main: # assumes PEP (3122), Cannon
...
__class__
的理由
类方法会传递当前实例;由此,它们可以确定 self.__class__
(或 cls,对于类方法)。不幸的是,此引用指向对象的实际类,该类可能是定义类的子类。目前的解决方法是重复类的名称,并假设该名称不会重新绑定。
class C(B):
def meth(self):
super(C, self).meth() # Hope C is never rebound.
class D(C):
def meth(self):
# ?!? issubclass(D,C), so it "works":
super(C, self).meth()
提案:添加一个 __class__
关键字,它引用当前正在定义(执行)的类。(但请参阅未解决的问题。)
class C(B):
def meth(self):
super(__class__, self).meth()
请注意,“新超级”PEP(Spealman)可以进一步简化超级调用。在尝试简化该 PEP 的解释和/或实现时,出现了 __class__
(或 __this_class__
)属性,但将其分离为一个独立的决定。
请注意,__class__
(或 __this_class__
)与绑定超级对象上的 __thisclass__
属性并不完全相同。现有的 super.__thisclass__
属性引用方法解析顺序搜索开始的类。在上面的类 D 中,它将引用(名称的当前引用)C。
__function__
的理由
函数(包括方法)通常希望访问自身,通常用于私有存储位置或真正的递归。虽然有几种解决方法,但所有这些方法都有其缺点。
def counter(_total=[0]):
# _total shouldn't really appear in the
# signature at all; the list wrapping and
# [0] unwrapping obscure the code
_total[0] += 1
return _total[0]
@annotate(total=0)
def counter():
# Assume name counter is never rebound:
counter.total += 1
return counter.total
# class exists only to provide storage:
class _wrap(object):
__total = 0
def f(self):
self.__total += 1
return self.__total
# set module attribute to a bound method:
accum = _wrap().f
# This function calls "factorial", which should be itself --
# but the same programming styles that use heavy recursion
# often have a greater willingness to rebind function names.
def factorial(n):
return (n * factorial(n-1) if n else 1)
提案:添加一个 __function__
关键字,它引用当前正在定义(执行)的函数(或方法)。(但请参阅未解决的问题。)
@annotate(total=0)
def counter():
# Always refers to this function obj:
__function__.total += 1
return __function__.total
def factorial(n):
return (n * __function__(n-1) if n else 1)
向后兼容性
虽然用户可能已经在使用这些名称,但双下划线名称(__anything__
)明确保留给解释器。因此,在单个功能版本中为这些名称引入特殊含义是可以接受的。
实现
理想情况下,这些名称将是字节码编译器专门处理的关键字。
Guido 建议[1] 使用元类填充的单元变量。
Michele Simionato 使用字节码黑客提供了原型[2]。这不需要任何新的字节码运算符;它只是修改了运行的特定现有运算符序列。
未解决的问题
__module__
、__class__
和__function__
是正确的名称吗?特别是,名称是否应该包含单词“this”,例如__this_module__
、__this_class__
和__this_function__
(在 python-3000 和 python-ideas 列表中讨论的格式),或者作为__thismodule__
、__thisclass__
和__thisfunction__
(受 super.``__thisclass__`` 的当前用法启发,但与其冲突)。- 是否需要所有三个关键字,或者此增强功能是否应限于对象的子集?是否应将方法与其他函数分开对待?
参考文献
版权
本文档已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-3130.rst
上次修改时间:2023年9月9日 17:39:29 GMT