Python学习小甲鱼视频做的笔记(持续更新中)

Python

BIF :Built-in functions(内建函数)

Python与大多数其他计算机语言的做法稍有不同,他并不是把值存储在变量中,而更像是把名字贴在值的上边。

在使用变量之前,必须要先对变量赋值

字符串的表示

表示字符串时,用单引号或者双引号将文本包围起来都可以。

如果字符串中需要出现单引号或双引号怎么办?

两种方法:1.使用转义符号(\)对字符串中的引号进行转义

例如:"let\'s go"; 即可将字符串设置为let's go\

原始字符串

反斜杠有时也会带来问题,当打印 >>>str ='C:\now'时,会将\n识别为换行符

解决办法:可以用反斜杠对自身进行转义: >>>str = 'C:\\now'

但如果对于一个字符串中有很多歌反斜杠,这个方法就显得有些麻烦了。

原始字符串的使用

原始字符串的使用非常简单,只需要在字符串前边加一个英文字母r即可:

例如:>>>str=r'C:\now'

长字符串

如果希望得到一个跨越多行的字符串,我们就需要使用到三重引号字符串:

使用"""或者''',将这个跨越多行的字符串包围,即可。

条件分支

if 条件:

条件为真执行的操作

else:

条件为假(False)执行的操作

Python中不使用大括号,而根据缩进来判断哪些代码段是要在一起执行的。

While循环

Python的while循环语法:

while 条件 :

条件为真时的操作

 

注意:条件书写时,没有括号

and, or操作符

and相当于其他语言中的&&

or相当于其他语言中的||

random模块

random模块里边有一个函数叫做 randint(), 会返回一个随机的整型数

secret = random.randint(1,10)//这句话的意思是生成一个1到10之间的随机数

Python的一些数据类型

整型

布尔类型:True是1,False是0

浮点型

e计法(科学计数法)

类型转换

int():将一个数转换为整型

str():将一个数转换为字符串类型

float():将一个数转换为浮点型

这三个函数分别将括号内的参数转换成int类型、字符串类型和浮点类型

如果是浮点数转换为整数,python会采取截断处理:将小数点后面的数抛弃,而不是采用四舍五入。

获取关于类型的信息

isinstance(),type()函数,获取数据的类型,Python官方文档更建议使用isinstance()

isinstance(a,str)

如果a是str类型,返回True,否则返回False

常用操作符

Python中可以写

a = b = c = d = 1

这个式子将a ,b , c , d 4个变量都赋值为1了。这是其他编程语言不允许的操作

也可以写

a

/ 是真正准确的除法符号,会得到一个准确的值而不是取整

// 是整除符号,得到一个整数

**是幂运算的操作符

3 ** 2的意思是3的2次方,幂运算符的左边是底数,右边是指数

幂操作符比其左侧的一元操作符优先级高,比其右侧的一元操作符优先级低

-3**2 ,结果为-9,先计算了3的2次方,再加了个负号

而 3 **-2,就会得到0.111111111111111,说明了幂操作符比左侧的一元操作符优先级高,比右侧的一元操作符优先级低。

 

 

分支和循环

elif 就是else if 的意思

条件表达式(三元操作符)

x=4

y=5

if x

small = x

else:

small = y

这个例子可以改进为

small = x if x

assert(断言)

assert这个关键字我们称之为断言,当这个关键字后边的条件为假的时候,程序自动崩溃并抛出AssertionError的异常。例如: assert 3>4 程序就会报错

一般来说我们可以用他在 程序中置入检查点,当需要确保程序中的某个条件一定为真才能让程序正常工作的话,assert关键字就非常有用了。

while循环

while 条件:

循环体

 

for循环

语法:

for 目标 in 表达式:

循环体

会自动调用迭代器的next方法,就好像是java中的 for-each循环一样

len()函数返回参数的长度

print()函数没有规定参数的个数,不管你在函数中写多少个参数,他都能识别并输出出来

range()

语法:range([start,]stop[,step=1])

这个BIF有三个参数,其中用中括号括起来的两个参数是可选的

step=1表示第三个参数的值默认是1,这个参数表示每一次递增的值是多少

range这个BIF的作用是生成一个从start参数的值开始到stop参数的值结束的数字序列(不包括stop数 )

两个关键的语句break与continue

break:终止循环并跳出循环体

continue:跳过本轮循环的剩下操作,跳到下一轮循环

 

列表(一个打了激素的数组)

序列是Python中最基本的数据结构,序列中的每个元素都分配一个数字-它的位置(索引index)列表的索引从0开始。使用下标的索引可以来访问列表中的值

L=['Google','Runoob','Taobao']

Python 表达式 结果 描述
L[2] 'Taobao' 读取第三个元素
L[-2] 'Runoob' 从右侧开始读取倒数第二个元素: count from the right
L[1:] ['Runoob', 'Taobao'] 输出从第二个元素开始后的所有元素

可以对列表的数据进行修改更新(直接对对应索引的元素直接赋值即可),也可以使用append()方法来添加列表项(以后会讨论)

可以使用del语句来删除列表的元素

list = ['Google', 'Runoob', 1997, 2000]
 
print ("原始列表 : ", list)
del list[2]
print ("删除第三个元素 : ", list)

向列表内添加元素:

append()方法

member.append(‘xiaodingding’)

会将xiaodingding添加到列表的尾部,每次只能有一个参数

extend()方法

member.extend(['竹林小溪','Crazy迷恋'])

extend方法是将一个列表添加到另一个列表的尾部,故他的参数是一个列表

insert()方法

这个方法有两个参数,第一个参数是要插入元素的位置,第二个参数是插入的元素

member.insert(1,'牡丹')

将牡丹插入到第二个索引处

 

从列表中获取元素

可以像数组一样,通过元素的索引值来获取元素值

从列表删除元素

remove(),参数为元素的名称,不需要知道这个元素在列表中的哪个位置

member.remove('怡静'),这样就将怡静从列表当中删除了

 

del

del member[1] 将member列表中的第二个元素进行删除了。

del member ,将member这整个列表删除掉

pop()

pop()方法从列表的尾部弹出一个元素返回,并从列表中删除这个元素

name = member.pop() 会将member列表中的最后一个元素赋值给name,并从列表中删除这个元素。

pop()方法在括号内还可以填上参数,参数为需要弹出的元素的索引值

例如 member.pop(1) 就将列表中的第二个元素弹出来了。

列表分片(Slice)

利用索引值,每次我们可以从列表获取一个元素,如果需要一次性获取多个元素,需要利用列表分片来实现。

member[1:3] 选出从第二个到四个元素的值,组成一个新的列表(左闭右开),新的列表是对原列表中部分元素的拷贝。

member[1:] 选出从第二个元素开始,到列表最后的元素的值

member[:3] 选出从第一个元素开始到第四个元素的值(不包括第四个元素)

member[:] 获得原列表的拷贝,在要复制一个和member一样的列表时,需要用到

member2 = member[:] 就得到了member2,一个内容和member2一样的列表。

如果使用member2=member ,则member2只是获得了member表示的列表的管理权,member2和member的操作会同时对同一个列表进行改变。

member2和member其实是在管理同一片内存,而member1将member列表的数据拷贝过来之后,储存到另外一片新的内存进行管理。

所以在需要进行拷贝的时候,最好使用分片的方式,不然可能会遇到一些意想不到的bug出现。

列表的一些常用操作符

·比较操作符

·逻辑操作符

·连接操作符

·重复操作符

·成员关系操作符

比较操作符

在两个列表进行比较大小时,从第一个元素开始依次比较,若不相同,则得出答案,若相同,则向后依次比较元素的大小。

逻辑操作符

还可以判断两个列表中的元素是否相等,利用== 即可进行判断,返回布尔值,若两个列表中的元素完全相等(包括元素的顺序),则返回True,否则返回False

连接操作符列表可以使用+运算符进行连接,和字符串的连接有相似性,也类似于extend()方法。但+运算符不能实现添加一个新元素的操作,例如 list1+'jiji' 程序会报错

重复操作符

*运算符进行重复操作

list1 * 3,得到一个将list1中的元素重复三遍的列表 list2 = list1*3

也可以使用 list1*=3,将list1重复三遍并又重新赋给list1

成员关系操作符

in 和 not in

123 in list1 如果123在列表list1中存在,返回True,否则返回False

'小鸡鸡' not in list 2

 

list5 = [123,['小鸡鸡',['小鸡']],456]

'小鸡鸡' in list5

返回False,不能直接对列表中嵌套的列表进行元素是否存在的验证

如果写为 '小鸡鸡' in list5[1]

则会返回True

列表类型的内置函数

count():返回参数在列表中出现的次数

list1.count)(123) 看123在list1中出现了多少次

index():返回参数在列表中的位置(索引值)

list1.index(123):会返回第一个123所在位置的索引值

list1.index(123,3,7):第二个参数和第三个参数分别代表从第4个位置开始到第8个位置结束,之间的123出现的索引位置。 3是start位置,7是stop位置。

reverse()方法:将整个列表进行翻转

list1.reverse()

sort()方法:用指定的方法对列表的元素进行排序,默认是从小到大进行排列

sort(func,key,reverse),前两个方法不用管,第三个方法默认值为False:表示从小到大进行排列,如果将其改成True的话,就会进行从大到小的排序了。

list1.sort(reverse=True)

元组:戴上了枷锁的列表

创建和访问一个元组

元组(tuple)和列表是近亲关系,所以元组和列表在实际使用上是非常相似的。创建元组时,一般是使用小括号

元组的访问,拷贝的操作与列表都是一样的

元组的元素是不能够被改变的

逗号在表示是元组中是很重要的,如果要创建一个只有一个元素的元组,要像下面这样创建:

temp =(1,) #这样就创建了一个只有1个元素1 的元组。如果没有加逗号,会认为temp是一个普通的整型变量

只要是创建时为一组以逗号隔开的数据,创建后的类型就为元组,不管有没有加上小括号。

如果要创建一个空元组,则在创建时,将变量声明为小括号()就可以了。

更新和删除一个元组

temp = ('小甲鱼','黑夜','迷途','小布丁') temp = temp[:2]+('怡静',)+temp[2:]

如果要在temp元组中插入一个新的元素'怡静',需要先将元组拆成两部分,使用拼接的方法将2部分和需要插入的元素进行组合起来,重新给temp元组。

注意:对于插入的元素而言,小括号和逗号缺一不可。

如果需要删除一个元素,也可以使用切片的方式,把不进行删除的元素进行拼接,然后重新赋值给temp,这样的话,没在片中的元素就相当于被删除了。

如果要删除整个元组,可以使用del的语句进行删除

元组相关的操作符

+: 连接操作符,+两边都必须是元组

*:重复操作符

in not in :成员操作符

< > = :关系操作符

and or :逻辑操作符

字符串及其内置方法

下表中带有中括号的字段代表这一项是可选的

capitalize() 把字符串的第一个字符改为大写
casefold() 把整个字符串的所有字符改为小写
center(width) 将字符串居中,并使用空格填充至长度 width 的新字符串
count(sub[, start[, end]]) 返回 sub 在字符串里边出现的次数,start 和 end 参数表示范围,可选。
encode(encoding='utf-8', errors='strict') 以 encoding 指定的编码格式对字符串进行编码。
endswith(sub[, start[, end]]) 检查字符串是否以 sub 子字符串结束,如果是返回 True,否则返回 False。start 和 end 参数表示范围,可选。
expandtabs([tabsize=8]) 把字符串中的 tab 符号(\t)转换为空格,如不指定参数,默认的空格数是 tabsize=8。
find(sub[, start[, end]]) 检测 sub 是否包含在字符串中,如果有则返回索引值,否则返回 -1,start 和 end 参数表示范围,可选。
index(sub[, start[, end]]) 跟 find 方法一样,不过如果 sub 不在 string 中会产生一个异常。
isalnum() 如果字符串至少有一个字符并且所有字符都是字母或数字则返回 True,否则返回 False。
isalpha() 如果字符串至少有一个字符并且所有字符都是字母则返回 True,否则返回 False。
isdecimal() 如果字符串只包含十进制数字则返回 True,否则返回 False。
isdigit() 如果字符串只包含数字则返回 True,否则返回 False。
islower() 如果字符串中至少包含一个区分大小写的字符,并且这些字符都是小写,则返回 True,否则返回 False。
isnumeric() 如果字符串中只包含数字字符,则返回 True,否则返回 False。
isspace() 如果字符串中只包含空格,则返回 True,否则返回 False。
istitle() 如果字符串是标题化(所有的单词都是以大写开始,其余字母均小写),则返回 True,否则返回 False。
isupper() 如果字符串中至少包含一个区分大小写的字符,并且这些字符都是大写,则返回 True,否则返回 False。
join(sub) 以字符串作为分隔符,插入到 sub 中所有的字符之间。
ljust(width) 返回一个左对齐的字符串,并使用空格填充至长度为 width 的新字符串。
lower() 转换字符串中所有大写字符为小写。
lstrip() 去掉字符串左边的所有空格
partition(sub) 找到子字符串 sub,把字符串分成一个 3 元组 (pre_sub, sub, fol_sub),如果字符串中不包含 sub 则返回 ('原字符串', '', '')
replace(old, new[, count]) 把字符串中的 old 子字符串替换成 new 子字符串,如果 count 指定,则替换不超过 count 次。
rfind(sub[, start[, end]]) 类似于 find() 方法,不过是从右边开始查找。
rindex(sub[, start[, end]]) 类似于 index() 方法,不过是从右边开始。
rjust(width) 返回一个右对齐的字符串,并使用空格填充至长度为 width 的新字符串。
rpartition(sub) 类似于 partition() 方法,不过是从右边开始查找。
rstrip() 删除字符串末尾的空格。
split(sep=None, maxsplit=-1) 不带参数默认是以空格为分隔符切片字符串,如果 maxsplit 参数有设置,则仅分隔 maxsplit 个子字符串,返回切片后的子字符串拼接的列表。
splitlines(([keepends])) 在输出结果里是否去掉换行符,默认为 False,不包含换行符;如果为 True,则保留换行符。。
startswith(prefix[, start[, end]]) 检查字符串是否以 prefix 开头,是则返回 True,否则返回 False。start 和 end 参数可以指定范围检查,可选。
strip([chars]) 删除字符串前边和后边所有的空格,chars 参数可以定制删除的字符,可选。
swapcase() 翻转字符串中的大小写。
title() 返回标题化(所有的单词都是以大写开始,其余字母均小写)的字符串。
translate(table) 根据 table 的规则(可以由 str.maketrans('a', 'b') 定制)转换字符串中的字符。
upper() 转换字符串中的所有小写字符为大写。
zfill(width) 返回长度为 width 的字符串,原字符串右对齐,前边用 0 填充。

字符串的格式化

format方法

format有两种参数:位置参数和关键字参数

"{0} love {1}.{2}".format("I","fishc","com")

这行代码得到 I love fishc.com

0,1,2可以直接对应后面的3个关键字,进行替换

如果前面不使用数字的方法,就需要在format的参数中加上位置的表示

"{a} love {b}.{c}".format(a="I",b="fishc",c="com")

这样写可以得到和上面相同的结果。

数字0,1,2类似的就是位置参数,在表示位置参数时,还可以根据自己的需求,规定位置里面数据的格式

比如 "{0:.1f}".format(27.658)

这句会打印出27.7 :.1f规定了第0位的参数表示规则为1位浮点数,进行了四舍五入

字符串格式化符号含义

符号 说明
%c 格式化字符及其 ASCII 码
%s 格式化字符串
%d 格式化整数
%o 格式化无符号八进制数
%x 格式化无符号十六进制数
%X 格式化无符号十六进制数(大写)
%f 格式化浮点数字,可指定小数点后的精度
%e 用科学计数法格式化浮点数
%E 作用同 %e,用科学计数法格式化浮点数
%g 根据值的大小决定使用 %f 或 %e
%G 作用同 %g,根据值的大小决定使用 %f 或者 %E

格式化操作符辅助命令

符号 说明
m.n m 是显示的最小总宽度,n 是小数点后的位数
- 用于左对齐
+ 在正数前面显示加号(+)
# 在八进制数前面显示 '0o',在十六进制数前面显示 '0x' 或 '0X'
0 显示的数字前面填充 '0' 取代空格

Python 的转义字符及其含义

符号 说明
' 单引号
" 双引号
\a 发出系统响铃声
\b 退格符
\n 换行符
\t 横向制表符(TAB)
\v 纵向制表符
\r 回车符
\f 换页符
\o 八进制数代表的字符
\x 十六进制数代表的字符
\0 表示一个空字符
\ 反斜杠

'%c' % 97

输出'a'

'%c %c %c' % (97,98,99)

输出'a b c'

用%前面的格式来表示%后面的数字

 

list()方法:把一个可迭代对象转换为列表

tuple()方法:把一个可迭代对象转换为元组

str(obj):把obj对象转换为字符串

len(sub):返回参数sub的长度

max():返回参数(可以是序列或者元组)中的最大值

min():返回最小值

采用min和max方法时,要保证序列的数据类型是统一的,不然就会报错

sum(itreable[,start=0])

返回序列iterable和可选参数start的总和

sorted():进行排序,从小到大排

reversed():翻转,得到的是一个迭代器对象,需要再进行类型转换才能得到想要的序列。

enumerate():返回的也是一个对象,需要进行类型转换,转换后会将每一个元素都变成一个2元组,这个元组的第一位是这个元素的index值,后一位是元素的值

zip(a,b):返回的也是一个对象,转换后会得到一个两元组,这个两元组将a,b的元素组合起来,进行对应。

 

函数

定义函数

用def 关键字来定义一个函数

def MyFirstFunction(name): ​ '函数定义过程中的name是叫形参' ​ #因为只是一个形式,表示占据一个参数位置 ​ print()

单引号' ' 包围的叫做函数文档,当调用

方法时,会将函数文档打印出来。在运行函数时,函数文档和注释都不会显示出来。

关键字参数

在调用参数时,将形参与传入的参数进行对应

def SaySome(name, words):

print(name + '->' +words)

调用时:

SaySome(words='让编程改变世界', name ='小甲鱼')

通过关键字来对参数进行配对

默认参数

在定义参数时,可以给每个形参一个默认值,当调用时没有给参数时,默认使用默认值来调用函数。

如果有多个参数,而只传入了不够数目的实参,那么之后的参数会根据默认值来选取

收集参数(可变参数)

def test(*params):

print('参数的长度是:', len(params));

print('第二个参数是:', params[1]);

参数前面加一个*号,就代表这个参数的数量是可变的,类似于一个可变长度的数组

 

快速地将多个变量的值进行互相交换

x=1,y=2,z=3,让x得到y的值,y得到z的值,z得到x的值

x,y,z = y,z,x

这样就可以了

函数与过程

procedure(过程),没有返回值。

函数有返回值

但是Python的所有函数都是有返回的,如果有return的话,返回return的返回值,如果没有return,返回一个None的对象。

Python可以返回 打包在列表或者元组当中的多个值

def back():

return 1,'aaa',3.14

上面返回一个元组

def back2()

return [1,'aaa',3.14]

上面返回一个列表

局部变量与全局变量

在函数外面定义的变量,全部都是全局变量。在函数中可以直接访问全局变量。如果要在函数中修改全局变量,Python会自动在函数中创建一个名字一样的局部变量,在函数中给他修改后的值。出了函数之后的那个同名的全局变量的值还是没有修改。

如果要在函数内部去修改全局变量,要使用global关键字

count = 5;

def Myfun(){

global count

count = 10

print(10)

}

print(count) #现在打印出来的count就变成10了,因为我们使用了global变量,在函数中对count进行了修改。

在函数中定义的变量为局部变量,局部变量只能在当前函数中生效,出了函数就不存在了。

内嵌函数和闭包

内嵌函数:允许在函数内部创建另一个函数

def fun1():

print('fun1正在被调用')

def fun2()

print('fun2正在被调用')

fun2()

fun2函数是在fun1函数的内部进行定义的,所以,fun2函数的作用域只有fun1函数内部才可以,也就是说,只有fun1函数内部才可以去调用fun2函数,其他地方调用不了fun2函数。

闭包:

def funX(x):

def funY(y):

return x*y

return funY

i=funX(8)

type(i)

i.funY at 0x007AAC48>

i(5)

40

或者直接调用i(8)(5) 得到的也是40

nonlocal关键字:和global关键字类似,不过是在内嵌函数的内部一层使用

lambda表达式

利用lambda关键字创建匿名函数

def ds(x):

return 2 * x +1

 

利用lambda表达式的写法

lambda x : 2 *x + 1

lambda后面,:前面是函数的参数,:后面是函数的返回值

如果要对一个函数g下定义

g = lambda x : 2*x +1

然后直接调用 g(5),即可打印出11

 

若有多个参数,如下例

def add(x,y): return x+y

则用lambda可写为

g = lambda x,y : x+y

g(323,432)#这一句是调用函数

两个牛逼的内置函数

filter():过滤器

filter(,)

第一个参数可以是一个函数或者None,第二个参数是可迭代的数据。

如果第一个参数是函数,则将第二个参数中的每一个数据作为函数的参数进行计算,把返回True的值筛选出来,成为一个列表。

filter(None,[1,0,False,True])

得到一个对象,转换为list,发现变成了[1,True],把非True的内容给筛选掉了

我们可以通过第一个参数function的书写,来决定我们的过滤规则。

写一个可以过滤偶数的过滤器:

def odd(x)

return x % 2

temp = range(10)

show = filter(odd ,temp)

list(show)

输出[1,3,5,7,9]

可利用lambda表达式来简化上述的操作:

list(filter(lambda x : x % 2 ,range(10)));

map(映射)

list(map(lambda x : x*2),range(10))

map将第二个参数中的数据当成第一个函数的参数进行运算,之后我们可以转换为一个列表打印出来。

递归

分治思想

字典:当索引不好用时

键值对 (Key - value),类似于映射。字典不是序列类型,而是映射类型。

创造和访问字典,用大括号表示是一个字典 {}

dict1 = {'李宁':"一切皆有可能",'耐克':'Just do it','阿迪达斯':'Nothing is impossible','慕课风云':'jijijijiji'}

创建了一个字典,里面有4个键值对的对映。

访问时,使用 dict1[],中括号内写入键(key)的值,即可返回对应的值

dict1['李宁'] 返回 '一切皆有可能'

也可以用工厂函数 dict()来创建字典

dict3 = dict((('F',70),('i', 105)('s',115),('h', 104),('C',67)))

也可以用key=value的形式来创建字典

dict4 = dict(小甲鱼='让编程改变世界',苍井空='让av征服所有宅男')

使用这个方法进行定义字典时,Key没有引号,但当要通过Key去使用对应的值时,需要加上引号

如果要像字典内加入新的项,直接定义,如下

dict4['爱迪生']='天才就是99%的汗水+1%的灵感,但这1%的灵感远比99%的汗水更重要'

这样就在dict4字典中加入了一个新的键值对。

如果要对已经存在的键值对进行修改,直接重新赋值

dict4['苍井空'] ='所有AV从业者都要通过学习编程来提高职业技能'

执行这个语句之后,字典dict4中Key为苍井空的对应的值就被修改了

字典的内建方法

dict.fromkeys(S[,v]) ->New dict with keys from S and values equal to v(v defaults to None)

fromkeys方法可以去创建并返回一个新的字典,第一个参数是字典的键,第二个参数是可选的,是键所对应的值,默认为None

dict1 = {}

dict1.fromkeys((1,2,3)) 进行输出后得到 {1: None, 2: None, 3: None}

键1,2,3对应的值都为None,因为我们没有给其指定第二个参数

dict1.fromkeys((1,2,3),'Number')

会得到 {1: Number, 2: Number, 3: Number}

不要试图去使用输入多个第二个参数对前面的键进行分别赋值的操作,他会将你输入的所有参数当成是一个值,与前面的所有键进行对应

访问字典的几个方法

keys()

dict1 = dict1.fromkeys(range(32),'赞')

for eachKey in dict1.keys():

print(eachKey)

会将每个键打印出来

 

values()

与keys的访问方法类似,只是改为了访问值而不是键

for eachValue in dict1.values():

print(eachValue)

items() 像 访问键值对(像)

for eachItem in dict1.items()

print(eachItem)

get方法也可以访问

clear()

清空一个字典

copy()

浅拷贝,对对象表层的拷贝,不是和被拷贝者管理同一块地址。如果是直接赋值,而不是使用浅拷贝的话,赋值得来的是一个管理同一块地址内存的量。

pop()

参数中给定一个键,弹出这个键和对应的值

popitem()

随机从字典里弹出一个键值对数据

setdefault()

a.setdefault(5,'five')

如果字典里面没有5这个键,则将这个值添加进去

update()

b={'小白':'狗'}

a.update(b)

用一个字典去更新另外一个字典的值,在这里,我们用b去更新a的值,在a里面添加了b字典中的键值对。

集合 (set)

num2 = {1,2,4,5,6,78,9}

定义时用花括号括起一段东西,没有表现出映射关系的话,就是集合

集合里面所有的元素都是唯一的,具有唯一性。

集合中的所有元素都是无序的。

还可以使用set()工厂函数来定义集合

set1 = set([1,2,3,4,5,5])

参数中只要是一个序列就行

去除掉一个序列num1中重复的值,可以利用集合,如下:(以num1是一个列表为例)

num1 = list(set(num1))

但是得到的新的列表不是按照之前的顺序来排列的,在使用集合时,顺序可能会被改变。

如何访问集合中的值

·可以使用for把集合中的数据一个个读取出来

·可以通过in和not in判断一个元素是否在集合中已经存在

可以使用add()方法和remove()方法对集合里面的元素进行添加和删除

不可变集合

frozen关键字 frozen:冰冻的,冻结的

num3 = frozenset(1,2,3,4,5)

这样就可以定义一个不可变集合,不允许从外界添加或者移除元素。

文件

打开文件:

open()函数

使用open()函数来打开文件,并决定文件的打开模式

打开模式 执行操作
'r' 以只读方式打开文件(默认)
'w' 以写入的方式打开文件,会覆盖已存在的文件
'x' 如果文件已经存在,使用此模式打开将引发异常
'a' 以写入模式打开,如果文件存在,则在末尾追加写入
'b' 以二进制模式打开文件
't' 以文本模式打开(默认)
'+' 可读写模式(可添加到其他模式中使用)
'U' 通用换行符支持
文件对象方法 执行操作
f.close() 关闭文件
f.read([size=-1]) 从文件读取size个字符,当未给定size或给定负值的时候,读取剩余的所有字符,然后作为字符串返回
f.readline([size=-1]) 从文件中读取并返回一行(包括行结束符),如果有size有定义则返回size个字符
f.write(str) 将字符串str写入文件
f.writelines(seq) 向文件写入字符串序列seq,seq应该是一个返回字符串的可迭代对象
f.seek(offset, from) 在文件中移动文件指针,从from(0代表文件起始位置,1代表当前位置,2代表文件末尾)偏移offset个字节
f.tell() 返回当前在文件中的位置
f.truncate([size=file.tell()]) 截取文件到size个字节,默认是截取到文件指针当前位置

文件的读取

read() , readline()

可以直接用list方法,将文件转换为一个列表

要灵活运用seek语句,这个语句很重要!返回到文件头的操作:f.seek(0,0)

可以直接用for循环,将文件中的数据按行打印出来:

for each_line in f:

print(each_line)

其中f是一个文件对象,可以直接对其进行读取并打印在屏幕上

文件的写入

write(), writelines()方法 ,注意打开方式应该是w 或者a

写入的文件内容要close之后,才写进去,在没close时,在你选取的文件内看不到写入的内容。

 

一些高大上的模块的引用

模块是可用代码段的打包,是一个包含所有你定义的变量和函数的文件,后缀是.py

os模块

os模块中关于文件/目录常用的函数使用方法

函数名 使用方法
getcwd() 返回当前工作目录
chdir(path) 改变工作目录
listdir(path='.') 列举指定目录中的文件名('.'表示当前目录,'..'表示上一级目录)
mkdir(path) 创建单层目录,如该目录已存在抛出异常
makedirs(path) 递归创建多层目录,如该目录已存在抛出异常,注意:'E:\a\b'和'E:\a\c'并不会冲突
remove(path) 删除文件
rmdir(path) 删除单层目录,如该目录非空则抛出异常
removedirs(path) 递归删除目录,从子目录到父目录逐层尝试删除,遇到目录非空则抛出异常
rename(old, new) 将文件old重命名为new
system(command) 运行系统的shell命令
walk(top) 遍历top路径以下所有的子目录,返回一个三元组:(路径, [包含目录], [包含文件])【具体实现方案请看:第30讲课后作业^_^】
以下是支持路径操作中常用到的一些定义,支持所有平台  
os.curdir 指代当前目录('.')
os.pardir 指代上一级目录('..')
os.sep 输出操作系统特定的路径分隔符(Win下为'\',Linux下为'/')
os.linesep 当前平台使用的行终止符(Win下为'\r\n',Linux下为'\n')
os.name 指代当前使用的操作系统(包括:'posix', 'nt', 'mac', 'os2', 'ce', 'java')

os.path模块中关于路径常用的函数使用方法

函数名 使用方法
basename(path) 去掉目录路径,单独返回文件名
dirname(path) 去掉文件名,单独返回目录路径
join(path1[, path2[, ...]]) 将path1, path2各部分组合成一个路径名
split(path) 分割文件名与路径,返回(f_path, f_name)元组。如果完全使用目录,它也会将最后一个目录作为文件名分离,且不会判断文件或者目录是否存在
splitext(path) 分离文件名与扩展名,返回(f_name, f_extension)元组
getsize(file) 返回指定文件的尺寸,单位是字节
getatime(file) 返回指定文件最近的访问时间(浮点型秒数,可用time模块的gmtime()或localtime()函数换算) time.getatime(file)
getctime(file) 返回指定文件的创建时间(浮点型秒数,可用time模块的gmtime()或localtime()函数换算)
getmtime(file) 返回指定文件最新的修改时间(浮点型秒数,可用time模块的gmtime()或localtime()函数换算)
以下为函数返回 True 或 False  
exists(path) 判断指定路径(目录或文件)是否存在
isabs(path) 判断指定路径是否为绝对路径
isdir(path) 判断指定路径是否存在且是一个目录
isfile(path) 判断指定路径是否存在且是一个文件
islink(path) 判断指定路径是否存在且是一个符号链接
ismount(path) 判断指定路径是否存在且是一个挂载点
samefile(path1, paht2) 判断path1和path2两个路径是否指向同一个文件

永久存储

引入pickle模块

为了将列表保存在文件当中

使用的时候,文件都必须用二进制的形式进行操作

import pickle
my_list = [123,3.14,'xiaojiji',['another list']]
pickle_file = open('my_list.pkl','wb')
pickle.dump(my_list, pickle_file)

这样就利用dump方法,把列表的数据放进pickle文件里面去了

如果要从pickle文件里面获取列表数据

pickle_file = open('my_list.pkl','rb')
my_list2 = pickle.load(pickle_file)

通过pickle的load方法,就把pickle文件中的列表数据提取出来,保存在my_list2中了。

在处理数量巨大的列表类型对象时,pickle就显得很方便了。

异常(Exception)

异常检测:使用try语句

try-except-finally语句

语法:

try:

检测范围

except Exception[as reason]:

出现异常后的处理代码

例如

try:
    f = open('我为什么是一个文件.txt')
    print(f.read())
    f.close()
except OSError:
    print('文件出错啦')
​

这样就对这个异常进行了捕获并处理,发生异常时输出 文件出错啦 ,而不是出现系统的红字来提醒出现了异常

as reason的用法是将错误信息保存在reason当中

上面的代码可以改成

try:
    f = open('我为什么是一个文件.txt')
    print(f.read())
    f.close()
except OSError as reason:
    print('文件出错啦T_T 错误的原因是'+str(reason))
​

这样可以将错误的具体信息打印出来

一个try语句可以和多个except语句进行搭配,可以同时捕获多种异常,并作出相应的处理

还可以将except 后面的内容全部去掉,这样就可以捕获所有可能发生的异常

try语句检测到异常,剩下的代码将不会再运行

except 后面可以写多个异常形式,可以对这多个异常进行同时捕获以及同时处理

try-finally

try:

检测范围

except Exception[as reason]:

出现异常后的处理代码

finally:

无论发生异常与否都要执行的语句

 

raise语句

代码通过raise语句,自己引发出一个异常

raise [Exception_name]

例如 raise ZeroDivisionError

还可以在引出的异常名后面加上参数,这样在程序执行到这地方的时候,会引发异常,并将后面的参数信息一同打印出来。

raise ZeroDivisionError('除数为零的异常')

else语句和with语句

else

  • 和if搭配,要么怎样,要么不怎样

  • 和循环语句 for, while进行搭配。干完了能怎样,干不完就别想怎样

  • 和异常处理进行搭配。没有问题的话,那就干吧

和循环语句进行搭配使用

只有正常结束循环,else语句后面跟着的代码段才会被执行。如果是使用break语句跳出了循环,则else语句中的代码段则不会被执行

def showMaxFactor(num):
    count = num//2
    while count+1:
        if num % count == 0:
            print('%d最大的约数是%d'%(num, count))
            break
        count -=1
    else:
        print('%d是素数!' % num)
​
num = int(input('请输入一个数:'))
showMaxFactor(num)

上面这个例子,如果整除成功,则打印出num的最大约数,并在之后break,break后不会执行else里面的代码

如果没有找到整除的数,循环正常结束而没有break,则执行else里面的代码。

for-else语句的用法和while-else语句的用法相似

和异常进行搭配使用

try:
    int('abc')
except ValueError as reason:
    print('出错了:'+str(reason))
else:
    print('没有任何异常')

else语句和finally语句的差别:

finally语句无论是否出现异常,都要执行,而else语句只有不出现异常的情况下才要执行

with语句

在打开文件时使用,之后就不用再去关闭这个文件了,with语句会自动帮你关闭。

try:
    with open('data.txt','w') as f
    for each_line in f:
        pring(each_line)
except OSError as reason:
    print('出错了 '+str(reason))
​

这样写,就不需要再在下面加一句

finally:

f.close()

了,with语句的引入可以帮我们自动关闭这个文件

图形用户界面入门:EasyGui

引用easygui模块时,推荐使用的方法是

import easygui as g

这样可以将命名简化,又不会产生函数冲突的情况

 

msgbox()的实现函数

def msgbox(msg="(Your message goes here)",title="", ok_button ="OK"):

.....

这三个参数都有默认参数,所以在写框时不需要每个参数都加上,方便的方法是通过关键字的方法来引入参数。

例如 msgbox("我一定会学会编程!",ok_button="加油!")

或者直接按照参数顺序 g.msgbox("我一定会学会编程!","CC程序员","加油!")

 

ccbox()

ccbox()提供一个选择:Continue或者Cancel,并相应的返回1(选中Continue)或者0(选中Cancel)

ccbox()是返回整型的1或0,不是布尔类型,但仍可以当成判断来使用,因为Python中默认false是0。

buttonbox()

buttonbox(msg='',title='',choices=('Button1','Button2','Button3'),image=None,root=None)

可以使用buttonbox()定义自己的一组按钮,当用户点击任意一个按钮时,buttonbox()会返回按钮的文本内容。如果用户取消或者关闭窗口,会返回默认选项(第一个选项)

import easygui as g  
import sys
​
a = g.buttonbox("sss","dwad",choices=('长腿','大胸','巨臀'));
print(a)

 

选择之后,选项的值会被赋给a

 

indexbox()

indexbox(msg='Shall I continue?',title='',choices=('YES','NO'),image = None)

用户选择第一个按钮的时候返回序号0,选择第二个按钮的时候返回序号1

boolbox()

boolbox(msg='Shall I continue?', title=' ', choices=('Yes', 'No'), image=None)

如果第一个按钮被选中则返回 1,否则返回 0。

 

如何在buttonbox里面显示图片

当调用一个buttonbox函数(例如msgbox(),ynbox(),indexbox()等等)的时候,你还可以为关键字参数image赋值,这是设置一个.gif格式的图像(仅支持gif格式)

为用户提供一系列选项

choicebox()

choicebox(msg='Pick something', title = '',choices =())

按钮组件方便提供用户一个简单的按钮选项,但若有很多选项或者选项的内容特别长的话,更好的策略是为它们提供一个可选择的列表。

choicebox()为用户提供了一个可选择的列表,使用序列(元组或者列表)作为选项,这些选项显示前会按照不区分大小写的方法排好序

multchoicebox()

multchoicebox(msg='Pick as many items as you like.',title='',choices=().**kwargs)

multchoicebox()函数也是提供一个可选择的列表,与choicebox()不同的是,multchoicebox()是一个多选框,它支持用户选择0个,1个或者同时选择多个选项。这些选项也是由序列(元组或列表)组成,这些选项显示前会按照不区分大小写的方法排好序。

 

让用户输入消息

enterbox()

enterbox(msg='Enter something.', title=' ', default='', strip=True, image=None, root=None)

这个函数为用户提供一个最简单的输入框,返回值为用户输入的字符串。默认返回的值会自动去除首尾的空格,如果需要保留首尾空格的话,请设置参数strip=False

import easygui as g  
import sys
​
a = g.enterbox(msg = '老公骂我',title='CC程序员',default='秋梨膏')
​
print(a)

 

interbox()

为用户提供一个简单的输入框,用户只能输入范围内(lowerbound参数设置最小值,upperbound参数设置最大值)的整型数值,否则会要求用户重新输入

integerbox(msg='', title=' ', default='', lowerbound=0, upperbound=99, image=None, root=None,

**invalidKeywordArguments)

multenterbox()

multenterbox(msg = 'Fill in values for the fields.',title= '', fields = ([list]),values=())

例:

list1 = ['用户名','密码']

g.multpasswordbox(msg='请输入用户名和密码',title='登陆',fields=(list1))

multenterbox()为用户提供了多个简单的输入框,要注意以下几点

·如果用户输入的值比选项少的话,则返回列表中的值用空字符串填充用户未输入的选项。

·如果用户输入的值比选项多的话,则返回的列表中的值将截断为选项的数量

·如果用户取消操作,则返回域中的列表的值或者None值

让用户输入密码

就是用户输入的东西看上去都是 ****

passwordbox()

passwordbox(msg='Enter your password.', title=' ', default='', image=None, root=None)

passwordbox()跟enterbox()样式一样,不同的是用户输入的内容用*显示出来,返回的是用户输入的字符串

multpasswordbox()

和multenterbox()使用相同的接口,但当他显示的时候,最后一个输入框显示为密码的形式

multpasswordbox(msg='Fill in values for the fields.', title=' ', fields=(), values=())

显示文本

Easygui提供函数用于显示文本

textbox()

textbox(msg='', title=' ', text='', codebox=0)

例如: g.textbox(text = open('E:\\新建文本文档.txt','r'))

textbox()函数默认会以比例字体(参数codebox=1设置为等宽字体)来显示文本内容(会自动换行),这个函数适合用于显示一般的书面文字。

注意:text参数可以是字符串类型,列表类型,元组类型

codebox()

codebox(msg='',title='',,text='')

codebox()以等宽字体显示文本内容,相当于textbox(codebox=1)

目录和文件

GUI编程中一个常见的场景是要求用户输入目录及文件名,Easygui提供了一些基本函数让用户来浏览文件系统。选择一个目录或文件

diropenbox()

diropenbox(msg=None, title=None, default=None)

default参数用于设置默认的打开目录(请确保目录已存在)

diropenbox() 函数用于提供一个对话框,返回用户选择的目录名(带完整路径哦),如果用户选择"Cancel"则返回 None。

fileopenbox()

fileopenbox(msg=None,title=None,default='*',filetypes=None)

fileopenbox()函数用于提供一个对话框,返回用户选择的文件名(带完整路径),如果用户选择'cancel'则返回None

关于 default 参数的设置方法:

  • default 参数指定一个默认路径,通常包含一个或多个通配符。

  • 如果设置了 default 参数,fileopenbox() 显示默认的文件路径和格式。

  • default 默认的参数是'*',即匹配所有格式的文件。

    例如:

  • default="c:/fishc/*.py" 即显示 C:\fishc 文件夹下所有的 Python 文件。

  • default="c:/fishc/test*.py" 即显示 C:\fishc 文件夹下所有的名字以 test 开头的 Python 文件。

关于 filetypes 参数的设置方法:

  • 可以是包含文件掩码的字符串列表,例如:filetypes = ["*.txt"]

  • 可以是字符串列表,列表的最后一项字符串是文件类型的描述,例如:filetypes = [".css", [".htm", "*.html", "HTML files"]]

filesavebox()

filesavebox(msg=None, title=None, default='', filetypes=None)

filesavebox() 函数提供一个对话框,让用于选择文件需要保存的路径(带完整路径哦),如果用户选择"Cancel"则返回 None。

default 参数应该包含一个文件名(例如当前需要保存的文件名),当然你也可以设置为空的,或者包含一个文件格式掩码的通配符。

filetypes 参数的设置方法请参考上边。

 

记住用户的设置

GUI 编程中一个常见的场景就是要求用户设置一下参数,然后保存下来,以便下次用户使用你的程序的时候可以记住他的设置。 为了实现对用户的设置进行存储和恢复这一过程,EasyGui 提供了一个叫做 EgStore 的类。为了记住某些设置,你的应用程序必须定义一个类(暂时称之为"设置"类,尽管你随意地使用你想要的名称设置它)继承自 EgStore 类。

设置类的构造函数(init 方法)必须初始化所有的你想要它所记住的那些值。

下面是创建一个"设置"类的例子:

  1. #-----------------------------------------------------------------------

  2. # create "settings", a persistent Settings object

  3. # Note that the "filename" argument is required.

  4. # The directory for the persistent file must already exist.

  5. #-----------------------------------------------------------------------

  6. settingsFilename = os.path.join("C:", "FishCApp", "settings.txt") # Windows example

  7. settings = Settings(settingsFilename)

下面是使用"设置"对象的例子:

  1. # we initialize the "user" and "server" variables

  2. # In a real application, we'd probably have the user enter them via enterbox

  3. user = "奥巴马"

  4. server = "白宫"

  5.  

  6. # we save the variables as attributes of the "settings" object

  7. settings.userId = user

  8. settings.targetServer = server

  9. settings.store() # persist the settings

  10.  

  11. # run code that gets a new value for userId

  12. # then persist the settings with the new value

  13. user = "小甲鱼"

  14. settings.userId = user

  15. settings.store()

 

类和对象

面向对象oo(Object Oriented)

oo的特征

封装

将方法封装起来,使用者不需要知道这些方法是如何具体实现的,直接去使用就行了。

继承

子类自动共享父类里面数据和方法的机制

多态

不同对象对同一方法响应不同的行动

 

对象=属性+方法

类名约定以大写字母开头

 

self是什么?

Python的self相当于java中的this

在Python的方法当中,需要加上参数self,也就是将对象自身作为一个参数,传给方法当中进行操作。

self在后来输入参数时,可以忽略,可以假装没有这个参数,而直接从第二个参数进行输入

 

__init__()方法

称为对象的构造方法,只要在创建一个实例化对象时,这个方法就会被自动调用,里面可以定义对象的初始化操作。这个方法不应当返回除了None以外的任何对象。

class Ball:
    def __init__(self, name):
        self.name = name
    def kick(self):
        print("我叫%s"%self.name)

name mangling

在Python中定义私有变量只需要在变量名或者函数名前加上__两个下划线,那么这个函数或变量就会变为私有的

class Person:

__name = '小鸡鸡'

p = Person()

如果现在要打印p.name

则会出现找不到属性的异常

如果需要访问这个属性,需要在内部进行访问,如果要在外部访问,可以写一个方法,将其作为返回值传出。

class Person:

__name = '小鸡鸡'

def getName(self):

return self.__name

 

p = Person()

p.getName()

这样就可以访问对象的私有属性啦

Python的名字重整机制,是把你想要作为的私有变量改成了 _类名__变量名

我们也可以直接通过_类名__变量名来访问想要访问的对象。

继承

在定义一个类时,在类名后面的括号里,写上父类即可

class DerivedClassName(BaseClassName)

其中BaseClassName类是DerivedClassName类的父类(或者称为基类,超类)

子类的性质子类会拥有父类的属性和方法,如果子类中定义了与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性。

子类如果重写了父类的__init__方法,则父类的那些属性全部都被抹去,而只剩下子类中的init方法初始化的属性了

所以我们在重写__init__方法并想要保留父类的属性时,需要先调用父类的属性,将父类的属性引入到子类当中。

有2种方法可以实现这个

--调用未绑定的父类方法

直接在子类的Init方法中写上 父类的名字.__init__(self) 就可以了,这里的这个self是子类的实例对象而不是父类的

--使用super函数

super().__init__()

super().后面加需要传入的父类方法就可以了。上面这一个语句就将父类的初始化构造方法给了子类。

Python支持多重继承

class Child(Parent1,Parent2,Parent3):

.....

在可以不使用多重继承时,尽量不要去使用它,因为有时候可能会遇到不可预见的Bug

如果要去掉父类中的某些方法(子类中没有这些方法),可以使用覆盖父类方法的做法

在子类中声明与要覆盖的方法同名的方法,在函数体内容里写pass,这样调用这个方法就没有任何反应了。

组合

class Turtle:
    def __init__(self,x):
        self.num = x
​
class Fish:
    def __init__(self,x):
        self.num = x
​
class Pool:
    def __init__(self,x,y):
        self.turtle = Turtle(x)
        self.fish = Fish(y)
    def print_num(self):
        print("水池里总共有乌龟%d只, 小鱼%d条"% (self.turtle.num,self.fish.num))
​

组合就是把一个类和实例化放到一个新类里边,通过参数进行调用,创建一个包括多个对象的对象。

如果属性的名字和方法相同,属性会把方法覆盖掉

对象中的赋值,相当于直接给这个对象创建了一个属性并赋值(Python中不需要声明)

如果你的属性名和方法名相同,属性会把方法给覆盖掉,方法就无法被调用了。

绑定

就是通过self完成的。Python严格要求方法要有实例才能被调用。实例对象会被作为第一个参数传入方法,所以在书写类方法时,不要忘了写上self参数!

与类和对象相关的一些BIF

issubclass(class, classinfo)

如果第一个参数class是第二个参数classinfo的一个子类,就返回True

这个检查是非严格性的检查,原因:

1.一个类可以被看成是自己类的子类

2.classinfo可以是类对象组成的元组,只要class是其中任何一个候选类的子类,则返回True

3.在其他的情况

isinstance(object , classinfo)

检查一个实例对象object是否属于类classinfo或者是classinfo类的子类。classinfo同样可以传入一个元组,object属于元组中的任意一个类时,就返回True

如果第一个参数不是对象,则永远返回False

如果第二个参数不是类或者由类对象组成的元组,会抛出一个TypeError的异常

若object是classinfo的子类的实例化对象,则也返回true。

属性访问及修改、删除的方法

hasattr(object, name)

attr = attribute,属性

该方法测试一个对象里面是否有指定的属性。name是属性名,要加上双引号或者单引号

getattr(object,name[,default])

返回对象指定的属性值。如果你要求返回的属性值不存在,如果设置了default,则返回default中的值,如果没有设置,则抛出一个异常

setattr(object, name , value)

设置对象中指定属性的值。如果指定的这个属性不存在,则会给其新建一个属性并给他赋值,name还是要加上引号来使用

delattr(object, name)

删除object对象中的name属性,如果该属性不存在,则会抛出一个异常

*注意:上面的几个方法,属性名name都必须用引号来括起来,不然就会抛出异常!

property

设置一个属性

property(fget = None , fset = None, fdel = None , doc = None)

property需要传入写好的方法,第一个参数是获取属性的方法,第二个参数是获取属性的方法,第三个参数是删除属性的方法

class C:

def __init__(self, size = 10):

self.size = size

def getSize(self):

return self.size

def setSize(self , value):

self.size = value

def delSize(self)

del self.size

x= property(getSize, setSize, delSize)

c1 = C()

c1.x即可打印出size的值

c1.x=18 即可设置size的值

del c1.x即可删除size属性

魔法方法

魔法方法总是被双下划线包围,比如__init__

魔法方法是面向对象的Python当中非常重要的部分

魔法方法的魔力体现在它们总是能够在适当的时候被自动调用

__init__(self[,])方法

相当于其他编程语言的构造方法,也就是类在实例化对象时,首先会调用的一个方法

__new__(cls[,])

实例化对象时,调用的第一个方法,在init之前,返回class这个类的实例对象。一般我们极少去重写这个方法

有一种情况需要去重写它,如果一个类继承了一个不可改变的类型,就需要在new函数里面对其进行替换

class Capstr(str):
    def __new__(cls, string):
        string = string.upper()
        return str.__new__(cls, string)
    
a = Capstr('I love fishc.com')

__del__(self)

垃圾回收机制。当没有引用指向这个实例化对象时,这个对象就自动调用__del__方法,将自己垃圾回收

对象的运算方法

在论坛上有总结

对象之间可以做运算

当对象进行算术操作时,就会触发对应的魔法方法

__add__(self,other)

定义加法

__sub__(self,other)

定义减法

其他的方法都类似。如果要重写这些方法,注意要做适当的类型转换

在前面加个r,代表反运算

time模块的详解:在论坛扩展阅读

 

显示方法

__str____repr__方法

重写这两个魔法方法后,在输入对象的名字时,可以打印函数中返回的内容。

__str__

class A():
    def__str__(self):
        return '小甲鱼是帅哥!'
a = A()
print(a)#str方法需要写print,才能将里面的内容打印出来

__repr__方法

class B():
    def __repr__(self):
        return '小甲鱼是帅哥!'
    
b = B()
#直接访问b,就可以打印出函数中的内容

 

属性访问

set,get,del attr

property(getattribute, setattribute, delattribute)#第一个参数是获得属性方法的名字,第二个参数是设置属性的方法的名字,第三个参数是删除属性的方法的名字

属性访问的魔法方法

__getattr__(self , name):定义当用户试图获取一个不存在属性时的行为

__getattribute__(self, name):定义当该类的属性被访问时的行为

__setattr__(self, name, value):定义当一个属性被设置时的行为

__delattr__(self, name):定义当一个属性被删除时的行为

class info(object):
    message = 'student'
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __setattr__(self, key, value):
        if key == 'name':
            print('student的name属性被修改!')
        super().__setattr__(key,value)  # 简化的写法,实际上super()内带有默认参数,与如下同理。
        # super(type(self), self).__setattr__(key,value)  # 直接引用父类未经重写的__setattr__方法操纵对象的属性
        # super(info, self).__setattr__(key,value)  # 也可以显式地在super()内用类自己的名称。不建议。因为显式引用失去了通用性。直接type(self)就能表示self所属的类info
    def get_name(self):
        return self.name

 

重要!!!!

注意super().__setattr__(key, value)这一句的使用。这里不能使用self.name = value或者setattr(self, key ,value),

这两种方法都会造成死循环,因为都是对属性进行修改,会访问到__setattr__函数,里面又会调用赋值语句,陷入无限循环。如果使用super(). __setattr__(key,value),就不会出现这个问题。

这样相当于将 要设置的属性和值作为参数传入__setattr__当中,要设置的属性作为key,对应的值相当于value,然后调用父类的方法,将要设置的属性和值进行匹配起来。

这个方法的原理是,使用父类未被重写的方法,来避免造成无限递归

修饰符

你可能感兴趣的:(Python学习小甲鱼视频做的笔记(持续更新中))