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

2022-01-14 00:00:00 python class oop namespaces scope

问题描述

可能重复:
Python自我"解释

我正在学习 Python,我有一个关于从此类的方法访问类变量的问题,理论多于实践.

I'm learning Python and I have a question, more theoretical than practical, regarding access class variables from method of this class.

例如我们有:

class ExampleClass:
    x = 123
    def example_method(self):
        print(self.x)

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

Why is necessarily to write exactly self.x, not just x? x belongs to namespace of the class, and method using it belongs to it too. What am I missing? What a rationale stands behind such style?

在 C++ 中你可以这样写:

In C++ you can write:

class ExampleClass {
public:
    int x;
    void example_method()
    {
        x = 123;
        cout << x;
    };
};

它会起作用的!


解决方案

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

相反,我决定放弃隐式引用实例变量.像 C++ 这样的语言可以让你把 this->foo 写成显式引用实例变量 foo(如果有单独的局部变量 foo).因此,我决定做出这样的明确引用引用实例变量的唯一方法.此外,我决定不要让当前对象(t​​his")成为特殊关键字,我会简单地使this"(或其等价物)方法的第一个命名参数.实例变量总是被引用为该参数的属性.

Instead, I decided to give up on the idea of implicit references to instance variables. Languages like C++ let you write this->foo to explicitly reference the instance variable foo (in case there’s a separate local variable foo). Thus, I decided to make such explicit references the only way to reference instance variables. In addition, I decided that rather than making the current object ("this") a special keyword, I would simply make "this" (or its equivalent) the first named argument to a method. Instance variables would just always be referenced as attributes of that argument.

使用显式引用,不需要特殊的语法对于方法定义也不必担心复杂关于变量查找的语义.相反,一个简单的定义第一个参数对应于实例的函数,通过约定被命名为自我".例如:

With explicit references, there is no need to have a special syntax for method definitions nor do you have to worry about complicated semantics concerning variable lookup. Instead, one simply defines a function whose first argument corresponds to the instance, which by convention is named "self." For example:

def spam(self,y):
    print self.x, y

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

This approach resembles something I had seen in Modula-3, which had already provided me with the syntax for import and exception handling. Modula-3 doesn’t have classes, but it lets you create record types containing fully typed function pointer members that are initialized by default to functions defined nearby, and adds syntactic sugar so that if x is such a record variable, and m is a function pointer member of that record, initialized to function f, then calling x.m(args) is equivalent to calling f(x, args). This matches the typical implementation of objects and methods, and makes it possible to equate instance variables with attributes of the first argument.

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

So, stated by the BDFL himself, the only real reason he decided to use explicit self over implicit self is that:

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

Python FAQ中也有答案.

There is also an answer in the Python FAQ.

相关文章