Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 增强提案

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