为什么在 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——具体而言,以下语句:
- 显式优于隐式。
- 可读性很重要。
- 面对歧义,拒绝猜测。
...等等。
这是 Python 的口头禅——这个,连同许多其他情况可能看起来多余且过于简单化,但明确是 Python 的关键之一 "goals." 也许另一位用户可以提供更多 explicit 示例,但在这种情况下,我会说在一次调用中不显式定义参数然后消失是有意义的——这可能会使事情变得不清楚查看子函数而不查看其父函数。
所有实例方法只是 function
值的 class 属性。如果您通过实例访问该属性,一些幕后 "magic"(称为描述符协议)负责将 foo.bar()
更改为 type(foo).bar(foo)
。 __init__
本身也只是另一个实例方法,尽管您通常只在子对象中覆盖 __init__
时才显式调用该方法。
在您的示例中,您通过 class 显式调用父 class 的 __init__
方法,因此您必须显式传递 self
(self.__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 级代理。)
具体来说,function
class定义了一个__get__
方法;如果属性查找的结果定义了 __get__
,则该方法的 return 值被 returned 而不是属性值本身。换句话说,
foo.bar
变成
foo.__dict__['bar'].__get__(foo, type(foo))
并且 return 值是类型 method
的对象。调用 method
实例只会调用原始函数,其第一个参数是 __get__
作为其第一个参数的实例,其余参数是传递给原始方法的任何其他参数打电话。
为什么从子方法调用父方法时需要使用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——具体而言,以下语句:
- 显式优于隐式。
- 可读性很重要。
- 面对歧义,拒绝猜测。
...等等。
这是 Python 的口头禅——这个,连同许多其他情况可能看起来多余且过于简单化,但明确是 Python 的关键之一 "goals." 也许另一位用户可以提供更多 explicit 示例,但在这种情况下,我会说在一次调用中不显式定义参数然后消失是有意义的——这可能会使事情变得不清楚查看子函数而不查看其父函数。
所有实例方法只是 function
值的 class 属性。如果您通过实例访问该属性,一些幕后 "magic"(称为描述符协议)负责将 foo.bar()
更改为 type(foo).bar(foo)
。 __init__
本身也只是另一个实例方法,尽管您通常只在子对象中覆盖 __init__
时才显式调用该方法。
在您的示例中,您通过 class 显式调用父 class 的 __init__
方法,因此您必须显式传递 self
(self.__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 级代理。)
具体来说,function
class定义了一个__get__
方法;如果属性查找的结果定义了 __get__
,则该方法的 return 值被 returned 而不是属性值本身。换句话说,
foo.bar
变成
foo.__dict__['bar'].__get__(foo, type(foo))
并且 return 值是类型 method
的对象。调用 method
实例只会调用原始函数,其第一个参数是 __get__
作为其第一个参数的实例,其余参数是传递给原始方法的任何其他参数打电话。