为什么从类中访问类变量需要"自我".在Python?

Gil*_*tes 8 python oop scope namespaces class

可能重复:
Python'self'解释

我正在学习Python,对于来自这个类的方法的访问类变量,我有一个问题,理论上比实际上更多.

例如,我们有:

class ExampleClass:
    x = 123
    def example_method(self):
        print(self.x)
Run Code Online (Sandbox Code Playgroud)

为什么必须准确写出self.x,而不仅仅是xx属于类的命名空间,使用它的方法也属于它.我错过了什么?这种风格背后有什么理由?

在C++中,您可以编写:

class ExampleClass {
public:
    int x;
    void example_method()
    {
        x = 123;
        cout << x;
    };
};
Run Code Online (Sandbox Code Playgroud)

它会工作!

Bak*_*riu 25

Python的历史:添加对用户定义的类的支持:

相反,我决定放弃对实例变量的隐式引用的想法.像C++这样的语言允许你编写this-> foo来显式引用实例变量foo(如果有一个单独的局部变量foo).因此,我决定将这种显式引用作为引用实例变量的唯一方法.另外,我决定不将当前对象("t​​his")作为特殊关键字,而是简单地将"this"(或其等价物)作为方法的第一个命名参数.实例变量将始终作为该参数的属性引用.

使用显式引用,不需要为方法定义提供特殊语法,也不必担心有关变量查找的复杂语义.相反,只需定义一个函数,其第一个参数对应于实例,按惯例,该实例名为"self".例如:

def spam(self,y):
    print self.x, y
Run Code Online (Sandbox Code Playgroud)

这种方法类似于我在Modula-3中看到的东西,它已经为我提供了导入和异常处理的语法.Modula-3没有类,但是它允许你创建包含完全类型化的函数指针成员的记录类型,这些成员默认初始化为附近定义的函数,并添加语法糖,这样如果x是这样的记录变量,m是该记录的函数指针成员,初始化为函数f,然后调用xm(args)相当于调用f(x,args).这与对象和方法的典型实现相匹配,并且可以将实例变量与第一个参数的属性等同起来.

因此,BDFL本人表示,他决定使用显式自我而不是隐式自我的唯一真正原因是:

  • 这是明确的
  • 它更容易实现,因为查找必须在运行时完成(而不是像其他语言一样在编译时完成),并且具有隐式self可能会增加查找的复杂性(从而增加成本).

编辑:Python 常见问题解答中也有答案.


hel*_*ker 5

它似乎与Python中的模块与类范围处理有关:

COLOR = 'blue'

class TellColor(object):
    COLOR = 'red'

    def tell(self):
        print self.COLOR   # references class variable
        print COLOR        # references module variable

a = TellColor()
a.tell()

> red
> blue
Run Code Online (Sandbox Code Playgroud)


eyq*_*uem 5

这是我在有关此功能的古老答案中所做的内容:


您遇到的问题是由于:

块是一段Python程序文本,作为一个单元执行.以下是块:模块,函数体和类定义.

(......)

范围定义块内名称的可见性.

(......)

类块中定义的名称范围仅限于类块; 它没有扩展到方法的代码块 - 这包括生成器表达式,因为它们是使用函数作用域实现的.这意味着以下内容将失败:

A类:

   a = 42  

   b = list(a + i for i in range(10))
Run Code Online (Sandbox Code Playgroud)

http://docs.python.org/reference/executionmodel.html#naming-and-binding

上述方法:函数体是代码块,方法是函数,然后在类定义中存在的函数体中定义的名称不会扩展到函数体.


当我读这篇文章时,我觉得很奇怪,但这就是Python的制作方法:

类块中定义的名称范围仅限于类块; 它没有扩展到方法的代码块

这是说明这一点的官方文件.

.

编辑

heltonbiker写了一个有趣的代码:

COLOR = 'blue'

class TellColor(object):
    COLOR = 'red'

    def tell(self):
        print self.COLOR   # references class variable
        print COLOR        # references module variable

a = TellColor()
a.tell()

> red
> blue
Run Code Online (Sandbox Code Playgroud)

它让我想知道print COLOR在方法中编写的指令如何tell()激发打印在类外定义的全局对象COLOR的值.
我在官方文档的这一部分找到了答案:

方法可以以与普通函数相同的方式引用全局名称.与方法关联的全局范围是包含其定义的模块.(一个类永远不会被用作全局范围.)虽然在方法中很少遇到使用全局数据的充分理由,但全局范围有许多合法用途:一方面,导入全局范围的函数和模块可以由方法,以及在其中定义的函数和类使用.通常,包含该方法的类本身在此全局范围内定义(...)

http://docs.python.org/2/tutorial/classes.html#method-objects

当解释器必须执行时print self.COLOR,因为COLOR不是实例属性(也就是说标识符'COLOR'不属于实例的命名空间),解释器进入实例的类的命名空间搜索标识符'COLOR'并找到它,因此它打印TellColor.COLOR的值

当解释器必须执行时print COLOR,因为在该指令中没有写入属性访问,它将在全局命名空间中搜索标识符"COLOR",官方文档称它是模块的命名空间.