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()
请注意,通过“New Super”PEP(Spealman)可以进一步简化 super 调用。__class__(或 __this_class__)属性是在尝试简化该 PEP 的解释和/或实现时出现的,但被分离出来作为一个独立决定。
请注意,__class__(或 __this_class__)与绑定 super 对象上的 __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