python里的super().__init__()有什么作用
先分别看看python里的__init__()和super()的意思
【关于 super()和__init__()官网的说法可见:
https://docs.python.org/zh-cn/3/reference/datamodel.html?highlight=object%20__new__#object.__init__
https://docs.python.org/zh-cn/3/library/functions.html?highlight=super#super 】
先介绍__init__()
在学习 Python 类的时候,总会碰见书上的类中有 __init__() 这样一个方法【注:特殊方法(魔法函数)之一:初始化方法,相当于其它语言的构造函数,故也称为构造方法】,__init__() 方法可以包含多个参数,但必须包含一个名为 self 的参数,且必须作为第一个参数。即便你不手动为类添加任何构造方法,在程序编译期间有一个默认构造函数由python隐式注入一个空的默认构造函数:
def __init__(self):
# no body, does nothing.
下面结合例子介绍。
__init__() 方法可以包含多个参数,但必须包含一个名为 self 的参数,且必须作为第一个参数:
class classDemo:
# 构造方法
def __init__(self,name,s):
print(name,"说:",s)
# 下面定义了一个类属性
text = 'Hello!'
# 下面定义了一个say方法
def say(self, content):
print(content)
#使用类classDemo
result = classDemo("某某","爱你!") # 某某 说: 爱你!
print("text属性的值:" + result.text) # text属性的值:Hello!
result.say("呵呵") # 呵呵
Python类中的成员方法中的self【python的self只有在类的方法中才会有】。
self在方法中只是一个形参,并不是关键字【换言之,可以用其它的合法变量名替换self,但是,规范和标准建议我们一致使用self】。
self在类的方法中代表当前这个对象【self代表类的实例,而非类】,self代表调用这个方法的对象,谁调用了这个方法,self就代表谁self 就可以在类的内部代替对象进行各种操作,self这个变量是无需用户手动传送值的,解释器会自动帮我们给其传递实例。
1)self在类的方法中代表当前这个对象,可以在类的内部代替对象进行操作,使用self可以在类的内部访问和操作成员。
2)类中的方法含有self,可用对象名.方法名()方式来调用该方法。
3)类中的方法不含self,可用类名.方法名()方式来调用该方法。不建议这样。
上述三点,如何理解呢?下面通过例子解释
★self在类的方法中代表当前这个对象,可以在类的内部代替对象进行操作,使用self可以在类的内部访问和操作成员。示例源码:
class Person():
#成员属性
name='张三'
#成员方法
def funA(self):
return self.name #使用self可以在类的内部像外部一样访问和操作成员
def funB(self):
self.name='李四' #同理也能使用self在类的内部添加修改调用属性
return self.name
#实例化对象
zs=Person()
#print(zs.name) # 张三
print(zs.funA()) # 张三
print(zs.funB()) # 李四
★类中的方法写self形参,可用对象.方法名()来调用方法,而用类名.方法名()的方式调用报错。示例源码:
class TestDemo():
# 定义一个方法,使用self形参
def testFn(self):
print("使用形参self")
# 创建对象,
td = TestDemo()
td.testFn()# 用对象.方法名()来调用方法
#TestDemo.testFn()# 使用类名.方法名()的方式报错
★类中的方法不写self形参,可用类名.方法名()的方式调用,而用对象.方法名()来调用方法报错。示例源码:
#类中的方法不用self形参的情况
class TestDemo():
# 定义一个方法,不使用self形参
def testFn():
print("不使用形参self")
td = TestDemo()# 创建对象
#td.testFn()# 用对象.方法名()来调用方法报错
TestDemo.testFn()# 只能使用类名.方法名()的方式来调用该方法。
现在介绍super()
super()内置函数的语法:
super(type[, object-or-type=None])
返回一个代理对象(proxy object),该对象将方法调用委托给type的父类或兄弟类。这对于访问已在类中被重载的继承方法非常有用。
其中
object_or_type确定要搜索的方法解析顺序。搜索从type后面的类开始。例如,如果object_or_type的__mro__是D->B->C->A->object,并且type的值是B,则super()搜索C->A->object。
如果省略了第二个参数,则返回的超级对象未绑定。
super 有两个典型用例。 在具有单继承的类层级结构中,super 可用来引用父类而不必显式地指定它们的名称,从而令代码更易维护。 这种用法与其他编程语言中 super 的用法非常相似。
第二个用例是在动态执行环境中支持协作多重继承。
【super() 函数是用于调用父类(超类)的一个方法。
super() 是用来解决多重继承问题的。
对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能来自于基类,所以在方法调用时就需要对当前类和基类进行搜索以确定方法所在的位置。而搜索的顺序就是所谓的“方法解析顺序”(Method Resolution Order,或MRO)。对于只支持单继承的语言来说,MRO 一般比较简单;而对于 Python 这种支持多继承的语言来说,MRO 就复杂很多。MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。
Python 至少有三种不同的 MRO:
早期版本经典类(classic class)的深度遍历。
Python 2.2 的新式类(new-style class)预计算。
Python 2.3 的新式类的 C3 算法。它也是 Python 3 唯一支持的方式。
详见https://hanjianwei.com/2013/07/25/python-mro/
super()的使用
python2必须写成 super(父类,self).方法名(参数)
python3也可直接写成 super().方法名(参数)
特别提示:因为Python2.x已被放弃,重点关注Python3.x。又,Python 3.x 版本中,不再保留(不支持)旧式类。因此重点关注Python 3的用法。】
下面通过例子解释python的super()的作用
当存在继承关系的时候,有时候需要在子类中调用父类的方法,此时最简单的方法是把对象调用转换成类调用,需要注意的是这时self参数需要显式传递,例如:
class FooParent:
def bar(self, message):
print(message)
class FooChild(FooParent):
def bar(self, message):
FooParent.bar(self, message)
f=FooChild()
f.bar("Hello, Python.") # Hello, Python.
这样做有一些缺点,比如说如果修改了父类名称,那么在子类中会涉及多处修改,另外,Python是允许多继承的语言,如上所示的方法在多继承时就需要重复写多次,显得累赘。为了解决这些问题,Python引入了super()机制,例子代码如下:
class FooParent:
def bar(self, message):
print(message)
class FooChild(FooParent):
def bar(self, message):
super(FooChild, self).bar(message)
f=FooChild()
f.bar("Hello, Python.") # Hello, Python.
表面上看 super(FooChild, self).bar(message)方法和FooParent.bar(self, message)方法的结果是一致的,实际上这两种方法的内部处理机制大大不同,推荐使用后者。更多细节可见https://mozillazg.com/2016/12/python-super-is-not-as-simple-as-you-thought.html
有了上面的铺垫,现在可以来看python里的super().init()有什么用了,下面通过例子说明。
☆没用super(A, self).__init__()时调用A的父类属性情况:
class Root(object): #可不写object
def __init__(self):
self.x= '这是属性'
def fun(self):
#print(self.x) #调用属性出错
print('这是方法')
class A(Root):
def __init__(self):
print('实例化时执行')
test = A() #实例化类
test.fun() #调用方法出错
#test.x #调用属性出错
☆使用super(A, self).__init__()时调用A的父类的属性情况:
class Root(object): #可不写object
def __init__(self):
self.x = '这是属性'
def fun(self):
print(self.x)
print('这是方法')
class A(Root):
def __init__(self):
super(A,self).__init__() #可不写 A,self
print('实例化时执行')
test = A() # 实例化类
test.fun() # 调用方法
test.x # 调用属性
由此可知,super().__init__()的作用也就显而易见了,就是执行父类的构造函数,使得我们能够调用父类的属性。
进一步学习了解:
Python中super函数的用法 - 时光若止~~~ - 博客园
python类中super()与__init__()_51CTO博客_python super().__init__()
python super()详解,一篇文章告诉你python的super是什么,如何使用_ZHHHHHJ66的博客-CSDN博客_python super
附录:
一、python新式类和旧式类
python的新式类是2.2版本引进来的,都从object继承,我们可以将(python2.1之前只存在旧式类)之前的类叫做经典类或者旧式类。
☆Python 2.x中定义旧式类的方式:
class A: # A是旧式类,因为没有显示继承object
pass
class B(A): # B是旧式类,因为B的基类A是旧式类
pass
☆Python 2.x中定义新式类的方式:
class A(object): # A是新式类,因为显式继承object
pass
class B(A): # B是新式类,因为B的基类A是新式类
pass
Python 2.x中默认都是经典类,只有显式继承了object才是新式类。
Python 3.x都是新式类,不必显式的继承object。经典类被移除。
新式类的MRO(method resolution order 基类搜索顺序)算法采用C3算法广度优先搜索,而旧式类的MRO算法是采用深度优先搜索。
新式类相同父类只执行一次构造函数,经典类重复执行多次。
官方宣布,2020 年 1 月 1 日, 停止 Python 2 的更新。现在通常使用的是Python 3.x,因此不必深入过于关注旧式类了。
二、Python函数中的->none是什么意思
如:
def foo () -> None:
print('I am foo')
这个类型注解是在Python3.5介绍进来的。
注解表示函数的返回类型,用标识符-> 。注解是可选的,如果删掉,什么都不会影响。
对执行完全没有影响 。
Python 运行时不强制执行函数和变量类型注解,但这些注解可用于类型检查器、IDE、静态检查器等第三方工具。(换句话说,是供代码检查器,IDE提示用的,并不是说你设置了类型,就真的变成像 java 那样的强类型定义语言了)
下面的函数接收与返回的都是字符串,注解方式如下:
def greeting(name: str) -> str:
return 'Hello ' + name
这个类型注解是在Python3.5介绍进来的。注解是可选的,如果删掉,什么都不会影响。
对执行完全没有影响 。