为什么在 Python 中从子方法调用父方法时使用 self 关键字?

Why using self keyword when calling parent method from child method in Python?

为什么从子方法调用父方法时需要使用self关键字作为参数?

举个例子,


class Account:

     def __init__(self,filepath):
         self.filepath = filepath
         with open(self.filepath,"r") as file:
              self.blanace = int(file.read())

     def withDraw(self,amount):
          self.blanace = self.blanace - amount
          self.commit()

     def deposite(self,amount):
          self.blanace = self.blanace + amount
          self.commit()


     def commit(self):
          with open(self.filepath,"w") as file:
               file.write(str(self.blanace))



class Checking(Account):

      def __init__(self,filepath):
           Account.__init__(sellf,filepath) ######## I'm asking about this line.

关于这段代码,

据我所知,在声明新对象时,self 会自动传递给 class,因此,

我希望当我声明新对象时,python 将设置 self = 声明的对象,所以现在 self 关键字将在 "'init' 中可用" 子方法,所以不需要像

那样再次手动编写
Account.__init__(sellf,filepath) ######## I'm asking about this line.

一般来说,我会将此统计为 the Zen of Python——具体而言,以下语句:

  1. 显式优于隐式。
  2. 可读性很重要。
  3. 面对歧义,拒绝猜测。

...等等。

这是 Python 的口头禅——这个,连同许多其他情况可能看起来多余且过于简单化,但明确是 Python 的关键之一 "goals." 也许另一位用户可以提供更多 explicit 示例,但在这种情况下,我会说在一次调用中不显式定义参数然后消失是有意义的——这可能会使事情变得不清楚查看子函数而不查看其父函数。

所有实例方法只是 function 值的 class 属性。如果您通过实例访问该属性,一些幕后 "magic"(称为描述符协议)负责将 foo.bar() 更改为 type(foo).bar(foo)__init__ 本身也只是另一个实例方法,尽管您通常只在子对象中覆盖 __init__ 时才显式调用该方法。

在您的示例中,您通过 class 显式调用父 class 的 __init__ 方法,因此您必须显式传递 selfself.__init__(filepath) 会导致无限递归)。

避免这种情况的一种方法是 明确引用父 class,而是让代理为您确定 "closest" 父。

 super().__init__(filepath)

这里有一些神奇之处:super 没有参数,在 Python 实现的一些帮助下,它静态地出现在 class 中(在这种情况下,Checking) 并将其与 self 一起作为隐式参数传递给 super。在 Python 2 中,您始终必须明确:super(Checking, self).__init__(filepath)。 (在 Python 3 中,你仍然可以显式传递参数,因为有一些用例,虽然很少见,用于传递当前静态 class 和 self 以外的参数。最常见的是,super(SomeClass) not 获取 self 作为隐式第二个参数,并处理 class 级代理。)


具体来说,functionclass定义了一个__get__方法;如果属性查找的结果定义了 __get__,则该方法的 return 值被 returned 而不是属性值本身。换句话说,

foo.bar

变成

foo.__dict__['bar'].__get__(foo, type(foo))

并且 return 值是类型 method 的对象。调用 method 实例只会调用原始函数,其第一个参数是 __get__ 作为其第一个参数的实例,其余参数是传递给原始方法的任何其他参数打电话。