当前位置:首页 » 编程语言 » pythonmro

pythonmro

发布时间: 2023-05-01 12:32:36

1. python可以多继承吗

Python支持多继承,与C++一样都会出现一种问题:子类继承的多个父类又继承了同一个父类,这时就有可能会出现父类构造方法被调用多次的情况。关于这个问题,我找了一些资料,虽然没有亲自全部验证,这里我总结一下自己对这个问题的看法。

Python和C++的关于这个问题的解决方案不太一样,当然Python还要看它的版本。

C++用的方案是引入了虚继承的语法避免同一个类被构造了多次。

Python用的方法是MRO(method resolution order,方法解析顺序) 。在在Python2.3之前,MRO的实现是基于DFS的,而在Python2.3以后MRO的实现是基于C3算法。找到的资料解释了一下更换算法的原因:

为什么采用C3算法

C3算法最早被提出是用于Lisp的,应用在Python中是为了解决原来基于深度优先搜索算法不满足本地优先级,和单调性的问题。

本地优先级:指声明时父类的顺序,比如C(A,B),如果访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类。

单调性:如果在C的解析顺序中,A排在B的前面,那么在C的所有子类里,也必须满足这个顺序。

------------------------------新式类和旧式类中查找属性的顺序不同-------------------------------------

在新式类中,查找一个要调用的函数或者属性的时候,是广度优先搜搜的。

在旧式类当中,是深度优先搜索的。

2. python的类和对象中的super函数的问题

问题一
因为在B类中调用了super方法,所以没有执行完B类就去执行C类的程序
super方法在多重继承程序中的调用顺序,采用的是C3算法(在python3中)。
C3算法的规则如下

①.从底层开始,选择入边为零的点。

②.从左到右。

③深度探索。但受限于②规则。

每一个类都可以用mro函数查看自己的继承顺序(MRO全称Method Resolution Order,就是用来定义继承方法的调用顺序)

对于你的程序

分析

①规则。得到D类,去掉D类以后,入边为零的是B类和C类

②规则。选择B类,去掉B类后,入边为零的只有C类。结论是D–>B–>C–>A。

在d=D()语句前加print(D.mro()),就可以打印出D类的继承顺序

[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
问题二
python3的继承不同于普通的继承,super函数已经考虑到了重复继承的问题,所以对于A类只访问一次

3. Python入门精华-OOP调用父类的方法及MRO方法解析序列

在继承关系中,我们想调用已经被覆盖了的父类的方法,就需要如下实现:

解决方法:

要调用父类中的方法,就要使用超类(超集)方法super(),该方法旨在调用已经被覆盖的父类的成员方法。

讨论:

有关python是如何实现继承的?

针对每一个定义的类,都会计算出一个成为方法解析顺序(MRO)的元组,其只是简单的对所有基类进行简单地线性排列。

通过上述的C类调用MRO表,我们不难看出,它将本类开始一直到object类直接所有的父类一次性从左向右逐层向上的排列了出来(先排列自己,在排列自己的父类,最后排列父类的父类,以及最后的object)

然而MRO为何如此排列,这里要涉及到一个非常令人讨厌的数学算法,C3线性化处理,这里只是总结其三个约束:(简单点说,其实就是对父类进行归并排列)

1、先检查子类,再检查父类

2、有多个父类时,按照MRO表的顺序依次查看

3、如果下一个待选的类出现了两个合法的选择,那察销闷么就从第一个父类中选取。

4、补充一点:MRO对类的排序几乎适用于任何定义的类层次结构。

来了来了,它真的来了:重点~~

有很多同学是否仔细看过上边的代码?

有关super()函数,以下重点需要各位明白:

在重写的方法中仅使用一次super()方法时,会按照MRO表从下一个类开始搜索对应的方法或属性,以此类推。 所以C中重写了父类的构造,构造中有super,所以会按照顺序去查找MRO中下一个类的方法,发现A中败弯也有super,就会再去B中找对应的方法(同名方法是__init__),所以找到B的构造,可是B中又有super,就会再去MRO中B的下一个类(Base)中找对应的方法(Base的__init__()方法),所以会先打印“Base.__init__”,打印完后又因为B的__init__中还有打印“B.__init__”,所以接着打印‘B.__init__’,又因为打印完后A中还有打印“A.__init__”,所以再打印“A.__init__”,最后打印“C.__init__”。这样就可以遍历MRO整张表中所有的对应的__init__()方法,并且让每个方法只会被调用一次。

为了更好的记忆:当所有重写的方法中只使用了一次super函数时,会从最上层的类依次调用其指定的方法即可以理解为(object->Base->B->A->C)。

所以,输出结果为:

甚至于如下情况更为耐人寻味,仔细品一斗哪品:

值的一提的是:AB均没有显式的继承的父类,为何结果为打印‘AB’呢?这里就要理解MRO的含义了哦!

4. python 多重继承,继承的几个父类都需要传递参数,怎么在子类计算出父类传递的参数总和呢

运行你的代码:出错位置: c = C()

出错结果:TypeError: __init__() missing 1 required positional argument: ' num1 '

先来看你的程序__main()__部分:a = A(2) 和 b = B(5) 这是类A和类B的一个实例。在python中实例变量是用于每个实例的唯一数据,这就说明你这里的传递参数2或者是5只能用在实例化的 a 或者是 b 下才有作用。 那么重点看c = C( ) ,c是类对象C的实例化,c 只能用自身实例变量才有用,因此前面的实例 a 下的变量 num1=2 和 实例 b 下的变量 num1=5对实例c是无用的。所以,出错结果很明显了缺少传递的位置参数了。这为什么提示缺少1个位置参数呢?下面为你简单讲解一下吧。你也可以用内置方法__mro__() :查看方法或者属性的调用路径——print(类名.__mro__)

类C是多继承类A和类B的,多继承(不存在super()重写方法下),类C的实例化c是怎么工作的——对于实例c调用方法或属性过程是这样的:查找当前类C中是否存在,然后在多个父类中按照从左往右顺序查找(类A中先查找,类B中后查找),只要在这个过程中找到就退出了,后面的就不再查找了。

好吧,给你分析一下你程序的过程:类A和类B中都有__init__()同一个方法,方法相同那首先就查找呗——先查找类C(没有对__init__()进行修改,那就是跳过了),然后再去类A查找,好嘛这就找到了__init__(self, num1),找到了就退出了。所以这样一看对类C进行实例化就需要传递一个参数给num1就够了。你也可以交换继承位置class C(B, A),这样就是类C实例化需要传递一个参数给num2就够了。这样过程就清晰了。

好第三个问题来了:你类C中有两个参数呀num1和num2,而实例化又仅需要一个参数就够了,这样就肯定会产生问题了。

不信你试试给c = C(2)产生错误:AttributeError: 'C' object has no attribute 'num2'

解决方法1:既然没有属性num2就在类C中删掉就是了,然后c = C(2)就可以运行成功了。

解决方案2:类变量用于类的所有实例共享的属性和方法。因此,要想共用这两个变量num1和num2,就得让搜索的时候不要进到类A和类B中前提下,将它们变成对应的类变量就可以了。第一个前提很好实现:在类C下 定义:def __init__(self) : pass 第二个条件也比较好实现:将类A或类B的 __init__(self, num) : X.num = num X为对应的类名。(说明:self表示类实例化对象,即self.num 表示实例变量;X表示类对象,则X.num表示类变量),这样就可以共享类A和类B的变量了。

classA:
def__init__(self,num1):
A.num1=num1


classB:
def__init__(self,num2):
B.num2=num2


classC(A,B):

def__init__(self):
pass

defnum_sum(self):
returnself.num2+self.num1


if__name__=='__main__':
a=A(2)
b=B(5)
c=C()
print(c.num_sum())

5. python列名称有中文括号怎么读取

一、萌新语法
输入和输出
print()

#打印括号的内容

#第一种:不带引号,让计算机读懂括号里的内容,打印最终的结果

>>>print(1+1)

#第二种:带单引号,计算机无须理解,原样复述引号中的内容

>>>print('秋水共长天一色')

秋水共长天一色

#第三种:带双引号,作用和单引号一样;当打印内容中有单引号时,可以使用双引号

>>>print("Let's go")

Let's go

>>> print('Let's go')

Let's go

#也可以使用转义字符+单引号(')来实现单引号

#第四种:带三引号,实现换行

>>>print('''python小课

最好的python课程''')
pyton小课

最好的python课程

# 采用转义字符"n"也可以换行

input()

#收集信息

>>>name = input('请输入你的forchange ID:')

# 使用变量赋值来获取输入的信息

变量的命名
1.只能是一个词;

2.只能包含字母、数字闹饥和下划线;

3.不能以数字开头;

4.尽量描述包含的数据内容;

5.不要使用python函数名和关键字。

>>>number = 34

>>>name = 'forchange'

>>>list_class = ['基础语法课程','爬虫分析初阶','爬虫分析进阶','自动化办公']

#以上number,name,list_class都是是变量名

条件判断
条件判断的解释:让计算机知道,在什么条件下,该去做什么。

单向判断
if…

#如果条件成立,就执行语句

>>>number = 6

>>>if number > 3:

... pirnt(number)

6

#注意格式!if后面要加冒号,同时执行语句要缩进四个空格。(空格和tab,我选空格?^^)

双向判断
if…else…

#条件成立执行if语句,否则执行else语句

number = 7

if number < 3:

pirnt(number)

else:

number = number - 3

print(number)

#结果输出为4

#if和else是同一层级,不需要缩进。if和else下的执行语句都需要缩进四个空格。

if…else…和if…if…的区别

#if…else…一个条件满足后就不会进行其他判断(if代表的条件和else代表的条件是互斥的)

#if…if…会遍历所有条件,一个条件无论满足还是不满足,都会进行下一个条件的判断

多向判断
if…elif…else

#三个及其以上条件的判断

grade = 65

if 80 <= grade <=100:

print('成绩优秀')

elif 60 <= grade < 80:

print('成绩中等')

else :

print('成绩差')

#结果输出为成绩中等

IF嵌套
if 嵌套

#使用if进行条件判断,还希望在条件成立的执行语句中再增加条件判断,即if中还有if,这两个if非平级

grade = 15

if 80 <= grade <=100:

print('成绩优秀')

elif 60 <= grade < 80:

print('成绩中等')

else :

print('成绩差')

if 20<= grade <60:

print('再努力一把,还有救!')

else :

print('你要比以前更努力才行,你可以的!')

#结果输出为:

成绩差

你要比以前更努力才行,你可以的!

#注意,嵌套的第二个if缩进了4个空格,表示不同的层级。

二、数据类型
数据类型
python常见的数据类型:字符串,整数型,浮点数,列表,字典,布尔值,元组。

最基本的数据类型有三种:

字符串str:用引号括起来的文本(如:'python'、'123'、'风变编程')

整数int:不带小数点的数字(如:-1、1、0、520、1314)

浮点数float:带小数点的数字,运算结果存在误差(如:-0.15、3.1415、1.0)

以下的数据结构会有一节或两节的课程介绍,可轻松上手。

列表list:是一种闷毕有序的集合,可以随时增加或删除其中的元素。标识是中括号[]。

元组tuple:一种类似列表的数据类型,但是不能被修改。

字典dice:全称为dictionary,使用键值对(蚂弯芹key-value)作为存储方式。标识是大括号{}。

布尔值bool:表示真假的数据类型,只有两个值,True和False。

数据的操作
字符串的拼接
初阶用法:使用 ' + ' 进行字符串的拼接

>>>print('风变'+'编程')

风变编程

>>>name = '酱酱'

>>>begin = '我叫'

>>>print(begin + name)

我叫酱酱

进阶用法:使用 ' % ' 进行字符串的拼接

>>>name = '《凤求凰》'

>>>number = 1

>>>print('司马相如以%d曲%s打动了卓文君' %(number,name))

司马相如以1曲《凤求凰》打动了卓文君

四则运算
运算符 表示 例子
+ 加 1 + 1 输出结果为2
- 减 1 - 1 输出结果为0
* 乘 3 * 2 输出结果为6
/ 除 2 / 1 输出结果为2
% 取模-返回除法的余数 5 % 2 输出结果为1
** 幂-返回x的y次幂 2 ** 3 输出结果为8
// 取整除-返回商的整数部分 11 // 2 输出结果为5
运算优先级:

与平时运算优先级一样:从左到右顺着来,括号里的优先算,乘除排在加减前。

数据转换
type()

#查看变量的数据类型

>>>who = 'xiaojiangjiang'

>>>print(type(who))

<class 'str'>

#结果显示这是一个字符串类型的数据

str()

#将其他数据类型强制转换为字符串

>>>begin = '我吃了'

>>>number = 1

>>>fruit = '个水果'

>>>print(begin + str(number) +fruit)

我吃了1个水果

#进行字符串拼接时,不同数据类型不能直接使用'+'连接,需要现将整数转化为字符串类型

int()

#将整数形式的字符串转化为整数(文本类字符串和浮点形式的字符串不能转化为整数)

#对浮点数直接抹零取整

>>>print(int(3.8))

3

float()

#将整数和字符串转换为浮点数(文字类字符串无法转换)

>>>print(float(8))

8.0

list()

#将数据转换为列表类型

>>>a = 'python小课'

>>>print(list(a))

['p', 'y', 't', 'h', 'o', 'n', '小', '课']

len()

#用于检查某个数据的长度

>>>bros = ['刘备','关羽','张飞']

>>>print(len(bros))

3

>>>emotion = 'happy'

>>>print(len(emotion))

5

数据的常用语法
列表语法
列表的操作可分为两种类型,一种类型为对列表元素的处理,另一种类型为对列表的处理,每种类型都有四种操作:提取,修改,增加,删除(取改增删)。

偏移量:对列表元素的位置编号。

#列表的偏移量从0开始计算

#如果要提取一段列表,需要使用切片的形式[a:b]:从a到b的元素,但不包括b(a <= X < b);冒号某侧如果没有数字,则全取

>>>list = ['松','竹','梅']

>>>print(list[0])

>>>print(list[1:2])

>>>print(list[:2])



['竹']

['松','竹']

#松,竹,梅三者的偏移量分辨是0,1,2。

列表元素的提取

>>>list = ['松','竹','梅']

>>>print(list[0])



>>>list = [['松','松树'],['竹','竹子'],['梅','梅花']]

>>>print(list[0][1])

松树

#嵌套列表的提取

列表元素的修改

>>>list = ['松','竹','梅']

>>>list[0] = '松树'

>>>print(list)

['松树', '竹', '梅']

列表元素的增加

append()

#是列表的方法,在括号内添加一个元素,可以将该元素添加到列表末尾

>>>list = ['松','竹']

>>>list.append('梅')

>>>print(list)

['松','竹','梅']

易错一:用append时不能对列表赋值

>>>list = ['松','竹']

>>>list = list.append('梅')

>>>print(list)

None

#第二行语法错误

易错二:append后面是小括号,而非中括号

>>>list = ['松','竹']

>>>list.append['梅']

>>>print(list)

TypeError: 'builtin_function_or_method' object is not subscriptable

#第二行语法错误

易错三:append不能一次添加多个元素

>>>list = ['松','竹']

>>>list.append('梅','岁寒三友')

>>>print(list)

TypeError: append() takes exactly one argument (2 given)

#第二行语法错误

列表元素的删除

del

#删除命令

易错一:每次只能删除一个元素,

易错二:删除多个元素时,要重新计算偏移量

>>>list = ['松','竹','梅']

>>>del list[0]

>>>print(list)

>>>del list[0]

>>>print(list)

['竹', '梅']

['梅']

列表的切片(即列表层面的提取,一次提取若干个元素)

>>>list = ['松','竹','梅']

>>>print(list[1:2])

>>>print(list[:2])

['竹']

['松','竹']

#注意:列表的切片提取出来的是列表

列表的修改

#同样是使用赋值语句,注意是对列表的赋值

>>>list = ['松','竹','梅']

>>>list[:] = ['岁寒三友']

#list[:]表示将列表的所有元素取出来

>>>print(list)

['岁寒三友']

#注意以下的错误做法:

>>>list = ['松','竹','梅']

>>>list[:] = '岁寒三友'

>>>print(list)

['岁', '寒', '三', '友']

列表的增加

列表的增加叫作列表的合并会更合理

#使用符号'+'

#符号'+'只能用在列表之间,不能用在列表和元素之间

>>>list1 = ['松']

>>>list2 = ['竹']

>>>list3 = ['梅']

>>>list = list1 + list2 +list3

>>>print(list)

['松', '竹', '梅']

列表的删除

del

#删除命令

>>>list = ['松','竹','梅']

>>>del list[:2]

>>>print(list)

['梅']

字典语法
字典数据的提取

#列表使用偏移量来提取,字典使用键来提取

>>>group = {'师父':'唐三藏', '大师兄':'孙行者', '二师兄':'猪八戒', '沙师弟':'沙和尚'}

>>>print(group['师父'])

唐三藏

字典数据的修改

>>>group = {'师父':'唐三藏', '大师兄':'孙行者', '二师兄':'猪八戒', '沙师弟':'沙和尚'}

>>>group['师父']='唐玄奘'

>>>print(group)

{'师父': '唐玄奘', '大师兄': '孙行者', '二师兄': '猪八戒', '沙师弟': '沙和尚'}

字典数据的增加

>>>group = {'师父':'唐三藏', '大师兄':'孙行者', '二师兄':'猪八戒', '沙师弟':'沙和尚'}

>>>group['白龙马']='敖烈'

>>>print(group)

{'师父': '唐三藏', '大师兄': '孙行者', '二师兄': '猪八戒', '沙师弟': '沙和尚', '白龙马': '敖烈'}

字典数据的删除

>>>group = {'师父':'唐三藏', '大师兄':'孙行者', '二师兄':'猪八戒', '沙师弟':'沙和尚'}

>>>del group['师父']

>>>print(group)

{'大师兄': '孙行者', '二师兄': '猪八戒', '沙师弟': '沙和尚'}

dict.keys()

#提取字典中所有的键

>>>group = {'师父':'唐三藏', '大师兄':'孙行者', '二师兄':'猪八戒', '沙师弟':'沙和尚'}

>>>print(group.keys())

dict_keys(['师父', '大师兄', '二师兄', '沙师弟'])

#打印出了所有字典的键,但是都是元组的形式

>>>group = {'师父':'唐三藏', '大师兄':'孙行者', '二师兄':'猪八戒', '沙师弟':'沙和尚'}

>>>print(list(group.keys()))

['师父', '大师兄', '二师兄', '沙师弟']

#通过list()函数将元组转化为列表的形式

dict.values()

#提取字典中所有的值

>>>group = {'师父':'唐三藏', '大师兄':'孙行者', '二师兄':'猪八戒', '沙师弟':'沙和尚'}

>>>print(group.values())

dict_values(['唐三藏', '孙行者', '猪八戒', '沙和尚'])

dict.items()

#提取字典中所有的键值对

>>>group = {'师父':'唐三藏', '大师兄':'孙行者', '二师兄':'猪八戒', '沙师弟':'沙和尚'}

>>>print(group.items())

dict_items([('师父', '唐三藏'), ('大师兄', '孙行者'), ('二师兄', '猪八戒'), ('沙师弟', '沙和尚')])

产生布尔值的表达式
bool()

#检查数值的真假

>>>print(bool(1))

True

值本身作为条件

假的 其他都是真的
False True
0 5(任意整数)1.0(任意浮点数)
''(空字符串) '风变编程'(字符串)
[](空列表) [1,2,3]
{}(空字典) {1:'a',2:'b'}
None
比较运算符产生布尔值

运算符 释义 作用
== 等于 如果两侧的值相等,条件为真
!= 不等于 如果两侧的值不相等,条件为真
> 大于 如果左侧的值大于右侧,条件为真
< 小于 如果左侧的值大于右侧,条件为真
>= 大于等于 如果左侧的值大于或等于右侧,条件为真
<= 小于等于 如果左侧的值小于或等于右侧,条件为真
注意:运算符之间不用空格,不可以写成= =、> =
成员运算符产生布尔值

运算符 释义 作用
in 属于 如果值在指定序列里,条件为真
not in 不属于 如果值不在指定序列里,条件为真
逻辑运算符产生布尔值

运算符 释义 作用
and 且 连接两个布尔值,如果两个都为真,该条件才为真
or 或 连接两个布尔值,如果有一个为真,该条件即为真
not 非 反逻辑状态,a为True,not a则为False,反之亦然
三、循环
for循环
for循环的基本格式是:for…in…

#遍历字符串

>>>for i in 'coding':

... print(i)

c

o

d

i

n

g

#遍历列表

>>>for i in ['for','change']

... print(i)

for

change

for…in dict:

#遍历字典的键

>>>list = {1:'a',2:'b',3:'c'}

>>>for i in list:

... print(i)

1

2

3

for…in dict.values():

#遍历字典的值

>>>list = {1:'a',2:'b',3:'c'}

>>>for i in list.values():

... print(i)

a

b

c

for…in dict.items():

#遍历字典的键值对

>>>list = {1:'a',2:'b',3:'c'}

>>>for k, v in list.items():

... print(k)

... print(v)

1

a

2

b

3

c

range()函数

#range()有最基本的三种用法:range(b), range(a,b),range(a,b,c)。

#函数中各个数值的意义:a:计数从a开始。不填时,从0开始;b:计数到b结束,但不包括b;c:计数的间隔,不填时默认为1。

>>>range(5)

#计数依次为0,1,2,3,4

>>>range(1,5)

#计数依次为1,2,3,4

>>>range(2,8,2)

#计数依次为2,4,6

for…in range()

#处理指定次数的循环

>>>for i in range(3):

... print('第%d遍风变编程' %i)

第0遍风变编程

第1遍风变编程

第2遍风变编程

while循环
while循环

#当条件为真时,执行循环语句,只要条件为真,便会一直循环

>>>count = 3

>>>while count > 1:

... print('happy coding')

... count = count -1

happy coding

happy coding

while循环和for循环的区别:

#for擅长处理固定次,自动遍历各序列

#while处理不定次数的循环,条件为False便停止

循环进阶
break

#如果满足条件,则结束循环

>>>while True:

... print('happy coding')

... break

happy coding

#break会结束循环,如果只有前两行代码,会无限循环打印happy coding

>>>count = 3

>>>while count >1:

... print('happy coding')

... count = count - 1

... if count == 2: #当count等于2的时候,停止循环

... break

happy coding

#对比while循环的例子,我们发现这里只打印了一次happy coding

continue

#如果满足条件,则跳过当前循环的剩余语句,直接开始下一轮循环

count = 3

while count >1:

print('happy')

count = count - 1

if count == 2: #当count等于2的时候,跳过下列语句,重新开始新的一轮循环

continue

print('coding') #由于continue语句,coding只会打印一次

#打印的结果为:

happy

happy

coding

else

#无论是否进入循环,最后都会执行esle语句,除非执行break语句跳出循环

count = 3

while count >2:

print('在风变')

count = count -1

else: #无论是否进入循环都会执行else语句

print('happy coding')

#打印结果为:

在风变

happy coding

循环嵌套

#即循环中有循环

>>>for i in ['风变','编程']: #首先遍历列表元素

... for t in i: #然后遍历元素(字符串)

... print(t)









四、函数
函数基本知识
函数
函数是组织好的、可以重复使用的、用来实现单一功能的代码

函数类型可分为自定义函数和内置函数,自定义函数是需要自己定义,而内置函数是python内部已经定义好的函数,比如print()、input()等

函数定义的语法
def

#定义函数

return

#函数的返回值

#函数定义的格式

def 函数名(参数):

函数体

return 语句

#一个简单的例子

def math_func(x):

y = x + 5

print(y)

return y

math_func(2)

#打印结果为7

变量作用域
变量作用域可认为是变量作用的范围

全局变量:在全局内生效的变量

局部变量:只能函数内或者一定代码块内生效

global

#将局部变量转化为局部变量

python内置函数
五、类与对象
概念
类:具有相同属性和方法的对象的抽象

实例:类的个例

对象:Python中的对象是类和实例的集合,类可以看作是对象,实例也可以看作是对象

基本语法
class

#定义类,注意类名需要大写

class MyClass: #定义类MyClass

i =12345 #定义类的属性(变量)

def f(self): #定义类的方法

return('hello world') #执行这个方法会返回'hello word'这个字符串

x = MyClass() #创建类的实例x

print(x.i) #打印实例x的属性

print(x.f()) #打印实例x的f方法

#输出的结果为

12345

hello world

class A(B)

#定义B类的子类A类,A类具有B类的属性和方法,也将B类称为A类的父类

class SecondClass(MyClass):

pass

#定义SecondClass是MyClass的子类,SecondClass可以调用MyClass的属性和方法

x = SecondClass()

print(x.i)

print(x.f())

#输出的结果为

12345

hello world

class A(B, C)

#多重继承,A类同时是B类和C类的子类,A类在调用属性和方法的时候,会优先调用位于左侧的类

class B:

i = 123 #B类的属性是i=123

class C:

i = 12345 #C类的属性是i=12345

class A(B,C): #A类是B类和C类的子类

pass

x = A() #创建A类的实例x

print(x.i) #调用属性,会优先调用B类的属性

#结果输出为

123

def __init__(self):

#创建类的初始化方法,只要调用类,便自动调用初始化方法的语句,常用于创建实例属性

>>>class A:

... def __init__(self): #只要创建实例,便会自动执行初始化方法下的语句

... print('hello world')

>>>x = A()

hello world #只要创建实例就会调用方法,打印hello world

#对比以下没有初始化的方法:

>>>class A:

... def f(self):

... print('hello world')

>>>x = A()

#不使用初始化方法,创建实例无任何输出

super()

#在子类的方法里调用父类的方法,使子类的方法可以在继承父类方法的基础上进行扩展

123 def super(cls, inst): mro = inst.__class__.mro() return mro[mro.index(cls) + 1]
cls代表类,inst代表实例,可以看出上面的代码做了两件事:

· 获取inst的MRO列表。

· 查找cls在MRO的index,并返回它的下一个类,即mro[index + 1]

当你使用super(cls, inst)时,python会在inst的MRO列表上搜索下cls的下一个类。

六、模块与库
模块类型
内置模块

#python官方组织编写和维护的模块

自定义模块

#自己写代码,然后将代码块保存为 .py 文件

第三方模块

#从自定义模块而来,代码写作者公开自己的代码

#根据模块的组织形式的不同,也可分为单个模块文件、模块包、模块库

模块和模块对象导入方法
import A

#导入模块A

#现在可以调用模块里函数和变量,但是必须通过【模块名.函数名()】和【模块名.变量名】的方式调用

#创建类实例的时候,需要使用【实例名 = 模块名.类名()】进行创建,创建实例后调用类方法和属性可以使用【实例名.函数名()】和【实例名.变量名】

import A as a

#导入模块A,并将模块A重新命名为a

#调用模块中的类、函数和变量如上述操作一样

from A import B

#导入模块A中的对象B

#调用对象B中的函数和变量可以不加模块名

from A import B,C,D

#导入模块A中的多个对象B,C,D

from A import *

#导入模块A中的所有对象

if __name__=="__main__":

#当.py文件被直接运行时,if __name__=="__main__":之下的代码块将被运行

#当.py文件以模块形式被导入时,if __name__=="__main__":之下的代码块不被运行

七、文件读写
文件读写三步骤
第一步,打开文件

第二步,读(写)文件

第三步,关闭文件

打开文件语法
open(file, mode, encoding)

#打开文件

f = open('/letter.txt', 'r', encoding = 'UTF-8')

with open() as…

#使用这种方式打开文件,可以不使用close()关闭文件

with open('/letter.txt', 'r', encoding = 'UTF-8') as f:

读写模式mode

模式mode 操作 若不存在 是否覆盖
r 只能读不能写 报错 -
rb 二进制只读 报错 -
r+ 可读可写 报错 是
rb+ 二进制读写 报错 是
w 只能写不能读 创建文件 是
wb 二进制只写 创建文件 是
w+ 可读可写 创建文件 是
wb+ 二进制读写 创建文件 是
a 追加不能读 创建文件 否,追加写
ab 二进制追加不能读 创建文件 否,追加写
a+ 可读可写 创建文件 否,追加写
ab+ 二进制追加可读可写 创建文件 否,追加写
读写文件语法
read()

#读取文件内容

with open('/letter.txt','r',encoding = 'UTF-8') as f:

content = f.read()

#以字符串的形式读取文件内容,将文件内容赋值给变量content

readlines()

#以列表的方式读取文件内容

with open('/letter.txt','r',encoding = 'UTF-8') as f:

content = f.readlines()

#以列表的形式读取文件内容,将文件内容赋值给变量content

write()

#清空文件内容,并写入字符串入内容

with open('/letter.txt','r',encoding = 'UTF-8') as f:

f.write('python')

writelines()

#清空文件内容,以列表的方式写入

with open('/letter.txt','r',encoding = 'UTF-8') as f:

f.writelines('python')

关闭文件语法
close()

#关闭文件

csv文件读写的相关函数

reader()

#读取csv文件的函数

import csv #导入csv模块

with open('letter.csv') as f:

reader = csv.reader(f) #读取csv文件,将文件内容赋值到reader

writer()

#将内容写入csv文件

writerow()

#写入一行内容

writerows()

#一次写入多行csv文件

import csv #导入csv模块

with open('letter.csv','w',newline = '') as f:

writer = csv.writer(f) #写入csv文件

writer.writerow(['python小课','风变编程']) #写入一行内容

data = [['交互式学习','更简单'],['助教酱酱','为你答疑解惑']]

writer.writerows(data) #写入多行内容

os模块

os.getcwd()

#返回当前的工作目录

八、debug
try…except…语句

用于处理

for i in range(6):

try:

print(6/i)

#使用6依次除于0,1,2,3,4,5,并打印

except ZeroDivisionError

#除非发生ZeroDivisionError类型的错误,执行下列语句

print('0是不能做除数的!')

九、其他
str.spilt()

#返回一个由字符串内单词组成的列表

>>>'1,2,3'.split()

['1',',','2',',','3']

>>>'1,2,3'.split('?,')

['1','2','3']

random模块

#随机模块

import random

#需要先导入random模块,然后再调用相应方法

print(random.randint(1,10)) # 产生 1 到 10 的一个整数型随机数

print(random.random()) # 产生 0 到 1 之间的随机浮点数

print(random.uniform(1.1,5.4)) # 产生 1.1 到 5.4 之间的随机浮点数,区间可以不是整数

print(random.choice('tomorrow')) # 从序列中随机选取一个元素

print(random.randrange(1,100,2)) # 生成从1到100的间隔为2的随机整数

转义字符

转义字符 意义
a 响铃(BEL)
b 退格(BS),将当前位置移到前一列
f 换页(FF),将当前位置移到下页开头
n 换行(LF),将当前位置移到下一行开头
r 回车(CR),将当前位置移到本行开头
t 水平制表(HT) (跳到下一个TAB位置)
v 垂直制表(VT)
代表一个反斜杠字符""
' 代表一个单引号(撇号)字符
" 代表一个双引号字符
? 代表一个问号
0 空字符(NUL)
ddd 1到3位八进制所代表的任意字符
xhh 1到2位十六进制所代表的任意字符
注意1:区分斜杠“/”和反斜杠“”,此处不可互换。注意2:以上表格内容也不需要硬记。

6. 又来求助了,大神求解答 python类继承的问题

老式类就是经典类,不是继承自object类.在多继承时采用深度优先遍历父类.
新式类就是基类继承自object类 class xxx(object).多继承时采用一种新的C3 算法来遍历父类.
实例如下:

新式类的打配绝印结果如下:

1speak: I am mother

旧式类的打印结果如下:

1speak: I am GrandFather

由此我们可以看出新式类的搜索过程为:Son-->Father-->Mother,而旧式类的搜索过程为:Son-->Father-->GrandFather

我们可以看出旧式类和我们预期的继承不太一样。

老式类就是经典类,不是继承自object类.在多继承时采用深度优先遍历父类.
新式类就是基类继承自object类 class xxx(object).多继承时采用一种新的C3 算法来遍历父类.

为什么采用C3算法呢?

C3算法最早被提出是用于Lisp的,应用在Python中是为了解决原来基于深度优先搜索算法不满足本地优先级,和单调性的问题。

本地优先级:指声明时父类的顺序,比如C(A,B),如果培亏姿访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类。

单调性:如果在C的解析顺序中,A排在B的前面,那么在C的所有子类里,也必须满足这个顺序。

为了解释C3算法,我们引入了mro(mro即 method resolution order (方法解释顺序),主要用于在多继承时判断属性的路径(来自于哪个类))。

我们可以通过class.mro()来查看python类的mro

C3算法
判断mro要先确定一个线性序列,然后查找路径由由序列中类的顺序决定。所以C3算法就是生成一个线性序列。
如果继承至一个基类:
class B(A)
这时B的mro序列为[B,A]

如果继承至多个基类
class B(A1,A2,A3 ...)
这时B的mro序列 mro(B) = [B] + merge(mro(A1), mro(A2), mro(A3) ..., [A1,A2,A3])


merge操作就是C3算法的核心。
遍历执行merge操作的序列,如果一个序列的第一个元素,是其他序列中的第一个元素,或不在其他序列出现,则从所有执行merge操作序列中删除这个元素,合并到当前的mro中。
merge操作后的序列,继续执行merge操作,直到merge操作的序列为空。
如果merge操作的序列无法为空,则说明不合法。

例子:
class A(O):pass
class B(O):pass
class C(O):pass
class E(A,B):pass
class F(B,C):pass
class G(E,F):pass

A、B、C都继承至一个基类,所以mro序列依次为[A,O]、[B,O]、[C,O]
mro(E) = [E] + merge(mro(A), mro(B), [A,B])
= [E] + merge([A,O], [B,O], [A,B])
执行merge操作的序列为[A,O]、[B,O]、[A,B]
A是序列[A,O]中的第空拿一个元素,在序列[B,O]中不出现,在序列[A,B]中也是第一个元素,所以从执行merge操作的序列([A,O]、[B,O]、[A,B])中删除A,合并到当前mro,[E]中。
mro(E) = [E,A] + merge([O], [B,O], [B])
再执行merge操作,O是序列[O]中的第一个元素,但O在序列[B,O]中出现并且不是其中第一个元素。继续查看[B,O]的第一个元素B,B满足条件,所以从执行merge操作的序列中删除B,合并到[E, A]中。
mro(E) = [E,A,B] + merge([O], [O])
= [E,A,B,O]

7. Python中的多继承

单继承:一个派生类的基类只有一个
多继承:一个派生类的基类有多个
一句话区分就是:单继承是一个生一个,多继承是多个生一个
多继承的基本语法:

子类定义构造方法时,需要将父类的构造方法调用一次。
案例演示:

在则答掘多继承中,所有基类的方法可以直接继承,但是属性需要手工初始举闭化。如果派生类中没有 __init__ 方法,则默认获得第一个类的属性。如果派生类中有 __init__ 方法,则所有基类的属性都不会获得,需要手动逐孙核一初始化。

我们定义一个ChineseStudent类,其继承关系如下:

调用基类的属性和方法

在不同的基类中存在相同的方法,派生类对象调用方法时会调用哪个父类的方法呢?
默认情况下,如果多个基类中有相同的方法,越在前面,优先级越高。
为了避免后期没必要的错误,建议基类之间存在重名的属性和方法应该尽量避免。

MRO(Method Resolution Order)方法解析顺序

如果是经典类(旧式类),MRO的方法--DFS(深度优先搜索)策略

如果是新式类,MRO的方法--BFS(广度优先搜索)策略

8. 怎么理解python方法__mro_entries__,__orig_bases__

def __mro_entries__(self, bases):
如果在类定义中出现的基类不是 type 的实例, 则使用 __mro_entries__ 方法对雀运其进行搜索
当找到结果时, 它会以原始基类元组做参数进行调用
此方法必须返回类的元组以替颤茄代此基类被使用
元组可以为空, 在此情况下原始基类将被忽略
__mro_entries__获取origin变茄岁察量
__class_getitem__返回一个实例化的

热点内容
安卓模拟器10开配什么电脑 发布:2025-07-19 16:30:36 浏览:804
sql2008链接服务器 发布:2025-07-19 16:23:47 浏览:845
香港阿里腾讯云服务器报价 发布:2025-07-19 16:18:52 浏览:417
日语翻译存储安全 发布:2025-07-19 16:18:09 浏览:213
虚拟机访问主机ip 发布:2025-07-19 16:16:37 浏览:999
dz手机源码 发布:2025-07-19 16:14:50 浏览:704
如何利用服务器挂机器人 发布:2025-07-19 16:13:35 浏览:532
解压缩已 发布:2025-07-19 16:02:46 浏览:580
预处理编译链接 发布:2025-07-19 15:59:03 浏览:874
文件夹无限打开 发布:2025-07-19 15:57:01 浏览:277