【python】速查手册(基础笔记) - 人生苦短,我用python
python学习笔记:小甲鱼python全套视频 + python基础教程 第2版修订版(书附10个大型案例)
python学习环境:(python3)win10下python3.5.4的IDLE + ubuntu下python3辅助
python分享范围:适合有C/C++/JAVA任意语言之一为基础,不适合纯新手入门
python语言优势:至今还没有一门编程语言,开发速度比Python快,运行速度比C快
python常用工具手册:
http://bbs.fishc.com/forum.php?mod=collection&action=view&ctid=198
---------------------------------2017.08.27--------------------------------------
00丶python背景与特点
Python语言起源
在1989年末,Guido van Rossum为了打发圣诞节的无聊,创造了python(大蟒蛇)。 1991年,第一个 Python 版本诞生。最新版本是Python3 3.6.2 。Guido van Rossum 是蒙提·派森的飞行马戏团(Monty Python‘s Flying Circus)的爱好者。logo是由两只蟒蛇的图形组成。
官网下载地址:
https://www.python.org/downloads/
Python 3 与 Python 2 不完全兼容
官方表示对 Python2 支持到2020年, Python2 2.7.13。Python 2 的生态库远远大于 Python 3。
简单:
学习曲线平滑, 45分钟学会基本使用,使用简单。
跨平台:
一次编写、到处运行。 Windows, Linux, Mac, Android
功能强大:
动态类型、自动内存管理
非常实用的内置对象类型
强大的内置工具和标准库
易于扩展,很多成熟易用第三方库
大型程序支持
应用广泛:
数据库、网络、图形图像、科学计算、机器学习、web开发、操作系统扩展等
缺点:
运行速度不够快(硬件的发展可以为此弥补不足)
开发速度与运行速度之间的矛盾:
至今还没有一门编程语言,开发速度比Python快,运行速度比C快
知名软件包:Django/Numpy/Pandas/Matplotlib/PIL (Pillow)/PyQt5/Tensorflow/Scipy/Theano/NLTK
知名项目:(网站)豆瓣/知乎/美团/Gmail/Youtube/Instagram/Calibre/……
01丶第一次亲密接触 first love
(1) win下的python IDLE集成开发环境自动缩进,table键补齐变量名
(2) linux下使用vi编辑.py的python文件,需要声明 #!/usr/bin/python3
(3) python使用等量(1个tab)的缩进来严格对齐表示作用域
#!/usr/bin/python3
#guess game
print ("---------游戏开始-----------")
temp = input ("输入一个我现在想的数字:")
guess = int (temp)
if guess == 8:
print ("猜对了!!!")
else:
print ("哈哈,猜错了。。")
print ("游戏结束喽~")
#---end---
BIF == Built-in functions(内置函数)
>>> dir(__builtins__)
..., 'input', ...
>>> help(input)
#可以查询内置函数的说明和用法,类似于C语言的man手册
02丶变量 variable
(1) python没有"变量"只有"名字"
(2) 变量使用之前,需要对其先赋值
(3) 变量名命名同C的规则,不能以数字开头,保证可读性命名即可
(4) 大小写敏感,区分
(5) =左右依次为左值和右值
(6) 十六进制,以0x 或 0X 开头 ,数字由"0"到"9" 或者 "a"到"f" 或者 "A"到"F"组成
八进制,0o或0O 开头,数字由"0" 到 "7"组成
二进制,0b或0B 开头表示,数字由"0" 或者"1"组成
十进制由数字"0"到"9"组成,并且不能以0开头
>>> teacher = 'jiangyuan'
>>> print (teacher)
jiangyuan
>>> teacher = 'somebody'
>>> print (teacher)
somebody
>>> first = 3
>>> second = 8
>>> third = first + second
>>> print (third)
11
>>> myteacher = 'jiangyuan'
>>> yourteacher = 'somebody'
>>> ourteacher = myteacher + yourteacher
>>> print (ourteacher)
jiangyuansomebody
03丶运算符及优先级 precedence of operator
#符合数学运算优先原则,括号最优先,最安全。
lambda lambda表达式
or 布尔或
and 布尔与
not 布尔非
in 和 not in 成员是否属于测试
is 和 is not 对象是否是同一个
> >= < <= == != 比较操作符
| 按位或
^ 按位异或
& 按位与
<< 和 >> 移位
+ 和 - 加法和减法
* 和 / 和 % 乘法、除法、取余
+x 和 -x 正负号
~x 按位翻转
** 指数(幂运算)
// 地板除法,舍弃小数部分
---python运算符优先级(图)---
#=连续赋值,自右向左,同C语言
>>> a = b = c = d = 10
>>> print (a, b, c, d)
10 10 10 10
>>> a += 1
>>> b -= 1
>>> c *= 10
>>> d /= 8 #真除法,精确值
>>> print (a, b, c, d)
11 9 100 1.25
>>> d = 10
>>> d // 3 #地板除法(Floor)舍弃小数部分
3
>>> 3 < 4 < 5 #支持连续判断,不建议这样用,可读性不高
True
>>> 3 < 4 and 4 < 5
True
04丶类型 type
数值类型:整型(int)、浮点型(float)、布尔类型(bool)、e记法(科学计数法,属于float)
(1) 整型与浮点型的区别就是是否含有小数点'.'
(2) bool类型的值是以大写开头的两个单词: True / False
(3) 纯数字的字符串可以使用int转为数字,进而参与计算,相当于C的atoi,非纯数字的不能使用int转换为数字
(4) float类型转换为int类型时,会丢弃小数部分
(5) str类型均可被其他类型转换,即变成字符串无障碍
(6) type (value) 返回变量类型,isinstance(value, type)类型判断返回bool值
#float→int,丢弃小数部分
>>> a = 5.99
>>> b = int (a)
>>> print (b)
5
#e记法示例
>>> 0.00000000000000111
1.11e-15
>>> 150000000000
150000000000
>>> 15e10
150000000000.0
#isinstance类型判断
>>> isinstance ('hello', str)
True
>>> isinstance (520, str)
False
>>> isinstance (520, int)
True
05丶条件分支与循环 condition and loop
条件bool值: True False
False 的值: False None 0 "" () [] {}
if-else
if condition:
#condition == True, 执行的操作,可多层嵌套
else:
#condition == False, 执行的操作,可多层嵌套
if-elif-else
if condition:
#condition == True, 执行的操作,可多层嵌套
elif condition:
#condition == True, 执行的操作,可多层嵌套
else:
#condition == False, 执行的操作,可多层嵌套
x if condition else y #三元操作符
举例:
>>> x, y = 4, 5
>>> small = x if x < y else y
>>> print (small)
4
assert 断言
当assert关键字后面的条件为假的时候,程序自动崩溃并抛出AssertionError异常。
>>> assert 3 > 4
Traceback (most recent call last):
File "", line 1, in
assert 3 > 4
AssertionError
>>> assert 3 < 4
>>>
while 循环
while condition:
#condition == true, 执行的循环体操作
#condition == false, 循环体外的操作
for 循环
for target in expression:
#循环体
示例:
>>> favourite = 'string'
>>> for i in favourite:
print (i, end=' ') #end以空格隔开
s t r i n g
range()函数
range ([start], [stop], [step]) #step默认每次递增1,且range的取值范围到stop-1
常与for循环一起使用。
示例:
>>> for i in range (2, 5):
print (i, end=' ')
2 3 4
>>> for i in range (1, 10, 2):
print (i, end=' ')
1 3 5 7 9
break 和 continue
同C语言的break和continue,依次为跳出循环和跳过当前循环。
pass 和 del 和 exec
pass 什么也不敢,暂时预留
del 删除不再使用的对象
exec 执行python语句
exal 计算python表达式,并返回结果值
06丶列表 list
普通列表:member = ['name', 'id', 'age', 'weight']
混合列表:mix = [1, 'name', 3.14, [1, 2, 3]]
空列表:empty = []
列表常用方法: len()/max()/min()/append()/extend()/insert()/remove()/pop()/count()/index()/reverse()/sort()
len()
功能:列表长度(元素个数)
len(listname)
>>> len(member)
4
append()
功能:向列表添加单个元素
listname.append(element)
>>> member.append('class')
>>> member
['name', 'id', 'age', 'weight', 'class']
extend()
功能:使用子列表扩展列表
listname.extend([element1, element2, ...])
>>> member.extend (['str1', 'str2'])
>>> member
['name', 'id', 'age', 'weight', 'class', 'str1', 'str2']
insert()
功能:向列表指定位置插入元素
listname.insert(position, element)
#list和数组一样,下标/索引均从0开始
>>> member.insert (1, 'new_elem')
>>> member
['name', 'new_elem', 'id', 'age', 'weight', 'class', 'str1', 'str2']
列表元素访问
listname[index]
#index从0开始,到index-1位置的索引访问
列表元素删除
listname.remove(element) #删除元素element
del listname[index] #删除index位置的元素
listname.pop() #删除最后一个元素,相当于C语言的弹栈
listname.pop(index) #删除index位置指定的元素
列表元素分片
listname[start_index:stop_index]
(1) 分片不会修改原列表的值,输出的是一份拷贝
(2) 分片输出的是从 start_index 到 stop_index-1 位置的值
(3) 分片的start和stop位置均可省略,start省略表示从头取值,stop省略表示取值到结尾,都省略表示取列表所有的值
示例:
>>> member = ['name', 'id', 'age', 'weight', 'class', 'str1', 'str2', 'str3']
0 1 2 3 4 5 6 7
>>> member[1:3]
['id', 'age']
>>> member[1:]
['id', 'age', 'weight', 'class', 'str1', 'str2', 'str3']
>>> member[:3]
['name', 'id', 'age']
>>> member[:]
['name', 'id', 'age', 'weight', 'class', 'str1', 'str2', 'str3']
>>> member[5:len(member)] #访问最后3个元素
['str1', 'str2', 'str3']
>>> member[0:len(member):2] #最后的2代表步长
['name', 'age', 'class', 'str2']
列表常用操作符
(1) list元素的判断只会判断第一个元素,然后理解返回bool结果
(2) list支持比较、逻辑、连接(+)、重复(*)、成员关系(in)操作符
(3) list赋值list时需要注意加上[:],左值会表现为一份拷贝
示例:
list2 = list1[:]#list2是list1的一份拷贝
list3 = list1 #list3是list1的一个引用(list1被修改,list3也会跟着被修改)
(4) dir(list) 查看list支持的所有方法:
listname.count(element)#element元素出现的次数
listname.index(element, [range_s], [rang_t])#查找元素在起止范围里第一次出现的下标位置
listname.reverse()#将list中的元素原地翻转
listname.sort()#将list中的元素进行排序,默认从小到大(修改原list内容)
listname.sort(reverse=True)#排序元素,实现从大到小(修改原list内容)
07丶元组 tuple
元组和列表使用上相似:
(1) 最大区别:列表可以任意修改和插入等操作,元组是不可改变的
(2) 创建:列表使用[],元组使用()
元组只有1个元素时使用(element,)注意逗号
()可以省略,但是,逗号不能省略
(3) 访问:都使用name[index]来访问
(4) 元组在映射中当做键使用,而列表不行
示例:
>>> temp = 1,
>>> type (temp)
>>> 8 * (8)
64
>>> 8 * (8,)
(8, 8, 8, 8, 8, 8, 8, 8) #重复元组
#元组元素插入
>>> temp = ('name1','name2','name3','name4')
>>> temp = temp[:2] + ('new_name',) + temp[2:]
>>> temp
('name1', 'name2', 'new_name', 'name3', 'name4')
08丶字符串 string
(1) \可以进行符号转义
(2) 单引号等同于双引号
(3) 定义字符串时使用r写在右值前面声明为原始字符串
(4) 使用三引号('''或""")可以指定多行字符串。并且字符串里可以包含单引号和双引号'''
(5) +号运算符可以连接字符串为1个字符串
(6) *号运算符可以复制多个相同字符串
列表和元组应用于字符串,所有标准的序列操作均适用于字符串。
>>> str1 = 'hello, python!' #字符串相当于元素是字符的元组
>>> str1 = str1[:5] + ';' + str1[5:]
>>> str1
'hello;, python!'
字符串常用方法: find()/join()/lower()/replace()/split()/strip()/translate()/
>>> dir(str)
...'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill'...
【F1】可以从python的帮助文档中【索引】查找操作方法的介绍内容及举例。
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])) 按照 '\n' 分隔,返回一个包含各行作为元素的列表,如果 keepends 参数指定,则返回前 keepends 行。
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 填充。
字符串操作:格式化
(1) 通过format方法将位置参数传递给对应字段
(2) : 冒号表示格式化符号的开始
位置参数:{0~n}
>>> "{0} love {1},{2}.".format("I", "you", "too")
'I love you,too.'
关键字参数:{自定义}
>>> "{a} love {b}, {c}.".format(a="I", b="you", c="too")
'I love you, too.'
注意:位置参数和关键字参数可以同时使用,但位置参数必须在关键字参数的前面。
字符串格式化符号含义
%c 格式化字符及其 ASCII 码
%s 格式化字符串
%d 格式化整数
%o 格式化无符号八进制数
%x 格式化无符号十六进制数
%X 格式化无符号十六进制数(大写)
%f 格式化浮点数字,可指定小数点后的精度,默认精确到小数点后6位
%e 用科学计数法格式化浮点数
%E 作用同 %e,用科学计数法格式化浮点数
%g 根据值的大小决定使用 %f 或 %e
%G 作用同 %g,根据值的大小决定使用 %f 或者 %E
举例:
>>> '%c' % 97 # 此处 % 为占位符,同C语言中printf函数中的%
'a'
>>> '%c %c %c' % (97, 98, 99) #此处的元组()小括号不能省略
'a b c'
格式化操作符辅助命令
m.n m 是显示的最小总宽度,n 是小数点后的位数
- 用于左对齐
+ 在正数前面显示加号(+)
# 在八进制数前面显示 '0o',在十六进制数前面显示 '0x' 或 '0X'
0 显示的数字前面填充 '0' 取代空格
举例:
>>> '%5.1f' % 27.658 #m.n
' 27.7'
>>> '%-10d' % 5 #填充的位数都是空格
'5 '
>>> '%#x' % 160 #对应进制显示方式
'0xa0'
>>> '%010d' % 5 #用0填充。'%-010d' % 5 负号的时候填充的只会是空格
'0000000005'
Python 的转义字符及其含义
\' 单引号
\" 双引号
\a 发出系统响铃声
\b 退格符
\n 换行符
\t 横向制表符(TAB)
\v 纵向制表符
\r 回车符
\f 换页符
\o 八进制数代表的字符
\x 十六进制数代表的字符
\0 表示一个空字符
\\ 反斜杠
09丶序列方法 sequence method
列表、元组、字符串的共同点:
(1) 都可以通过索引得到每一个元素
(2) 默认索引值总是从0开始
(3) 可以通过分片的方法得到一个范围内的元素的集合
(4) 有很多共同的操作符(重复*、拼接+、成员关系in/not in等)
(5) 统称为序列,以下(成员函数)为序列方法
list()
list(iterable) 把一个可迭代对象转换为列表
举例:
>>> b = 'I love you.' # b也可以是元组 b = (1, 2, 3, 4, 5)
>>> b = list(b)
>>> b
['I', ' ', 'l', 'o', 'v', 'e', ' ', 'y', 'o', 'u', '.']
tuple()
tuple(iterable) 把一个可迭代对象转换为元组
举例:
>>> b = 'I love you.'
>>> b = tuple(b)
>>> b
('I', ' ', 'l', 'o', 'v', 'e', ' ', 'y', 'o', 'u', '.')
max(...) 返回集合或者序列中的最大值(要求类型一致)
min(...) 返回集合或者序列中的最小值(要求类型一致)
>>> max(iterable, *[, default=obj, key=func]) -> value
>>> max(arg1, arg2, *args, *[, key=func]) -> value
举例:
>>> numbers = [1, 18, 13, 0, -98, 34, 53, 76, 32]
>>> max(numbers)
76
>>> min(numbers)
-98
sum(...) 返回序列iterable和可选参数的总和(要求类型一致)
>>> sum(iterable, start=0, /)
举例:
>>> tuple1 = (3.1, 2.3, 3.4)
>>> sum(tuple1)
8.8
>>> sum(tuple1, 0.2) #0.2为可选参数,会加在一起
9.0
sorted(...) 返回序列的排序结果
>>> sorted(iterable, /, *, key=None, reverse=False)
举例:
>>> tuple1 = (3.1, 2.3, 3.4)
>>> sorted(tuple1)
[2.3, 3.1, 3.4]
reversed(...) 翻转一个序列的内容
>>> reversed(sequence)
举例:
>>> numbers = [1, 24, 5, -98, 54, 32]
>>> reversed(numbers)
#这种格式都是:迭代器对象
>>> list(reversed(numbers)) # 将迭代器对象转换为list列表
[32, 54, -98, 5, 24, 1]
enumerate(...) 生成由序列组成的元组
>>> enumerate(iterable[, start])
举例:
>>> numbers = [1, 24, 5, -98, 54, 32]
>>> list(enumerate(numbers))
[(0, 1), (1, 24), (2, 5), (3, -98), (4, 54), (5, 32)]
zip(...) 返回由各个参数的序列组成的元组
>>> zip(iter1 [,iter2 [...]])
举例:
>>> a = [1, 2, 3, 4, 5, 6, 7, 8]
>>> b = [4, 5, 6, 7, 8]
>>> zip(a, b)
>>> list(zip(a, b))
[(1, 4), (2, 5), (3, 6), (4, 7), (5, 8)]
>>> for i,j in zip(a, b): #并行迭代,同时迭代两个变量
print(str(i) + ' is ' + str(j))
1 is 4
2 is 5
3 is 6
4 is 7
5 is 8
10丶函数 function
(1) python只有函数(return)没有过程(no return)
(2) 函数返回多个值的时候,使用list列表或tuple元组进行返回
(3) 局部变量和全局变量的规则同C语言
(4) 在函数内部使用 global 修饰变量,使函数可以修改同名的全局变量
(5) 函数嵌套时,内部函数的作用域都在外部函数之内,出了外部函数就不能被调用
函数定义和调用
def function_name():
#函数体内容
function_name() #函数调用,执行函数体的内容
函数返回值
def function_name():
#函数体中返回
return value
print(function_name()) #调用函数并打印其返回值
函数参数
def function_name(param): #形参:多个参数使用,逗号隔开
#函数体使用参数param
function_name(parameter) #实参:传递实际参数
函数文档
举例:
>>> def my_sec_func(name):
'function document.'#函数文档部分,单引号引起来即可
print(name)
>>> my_sec_func('myname')
myname
>>> my_sec_func.__doc__ #打印输出函数文档部分
'function document.'
>>> help(my_sec_func)
Help on function my_sec_func in module __main__:
my_sec_func(name)
function document.
关键字参数与默认参数
举例:
>>> def say_some(name, words):
#>> def say_some(name='abc', words='string'): #形参可设置默认值
print(name + ' -> ' + words)
>>> say_some('Jan', 'learning python.')
Jan -> learning python.
>>> say_some(words='learning python.', name='Jan') #指定形参对应实参
Jan -> learning python.
#>>> say_some()
#abc -> string
*params搜集其余的位置参数
>>> def test(*params): # *params把实参打包为元组
print('len = ', len(params))
print('second params = ', params[1])
>>> test(1, 'Jan', 3.14)
len = 3
second params = Jan
#搜集参数param加上普通形参
>>> def test(*params, tmp):
print('len = ', len(params))
print('second params = ', params[1])
print('tmp = ', tmp)
>>> test(1, 'Jan', 3.14, tmp = 520) #注意传参需要单独指定
len = 3
second params = Jan
tmp = 520
global 关键字
举例:
>>> cnt = 5
>>> def my_func():
global cnt
cnt= 10
print(cnt)
>>> my_func()
10
>>> print(cnt)
10
函数嵌套
举例:
>>> def func1():
print('func1 called...')
def func2():
print('func2 called...')
func2()
>>> func1() #调用func1
func1 called...
func2 called...
闭包closure
举例1:
>>> def funX(x):
def funY(y):
return x * y
return funY
>>> i = funX(8)
>>> i
.funY at 0x000001EFE75E87B8>
>>> type(i)
>>> i(5)
40
>>> funX(8)(5)
40
>>> funY(5) #不可被调用,解决办法有2:list或者nonlocal
举例2 - list:
>>> def fun1():
x = [5] #对func2函数来说x是全局变量,在func2中没有定义x,是用list即可安全
def fun2():
x[0] *= x[0]
return x[0]
return fun2()
>>> fun1()
25
举例2 - nonlocal:
>>> def fun1():
x = 5
def fun2():
nonlocal x #在内部函数中声明x为非局部变量,再调用func1()也是安全的
x *= x
return x
return fun2()
>>> fun1()
25
lambda 表达式(匿名函数)
(1) 不需要考虑函数名的命名问题
(2) 极大简化函数编写的步骤
举例:
>>> def ds(x):
return 2*x + 1
>>> ds(5)
11
>>> lambda x : 2*x + 1
at 0x000002170B3D87B8> #可以理解为返回的是C语言的函数指针
>>> g = lambda x : 2*x + 1 #赋值后,传参即可,g相当于接收了匿名函数
>>> g(5)
11
>>> g = lambda x, y : x+y #lambda匿名函数多个参数
>>> g(1, 3)
4
两个牛逼的BIF:filter和map
(1) filter 过滤:返回其函数为真的元素的列表
>>> filter(function or None, iterable)
举例:
>>> filter(None, [1, 0, False, True])
>>> list(filter(None, [1, 0, False, True]))
[1, True] #验证filter过滤的是非true的内容
>>> def odd(x):
return x % 2
>>> temp = range(10)
>>> show = filter(odd, temp)
>>> list(show)
[1, 3, 5, 7, 9]
>>> list(filter(lambda x : x % 2, range(10))) #简化一行实现求奇数
[1, 3, 5, 7, 9]
(2) map 映射:对序列中每个元素都应用函数
>>> list(map(lambda x : x + 2, range(10)))
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
---------------------------------2017.08.28--------------------------------------
11丶递归 recursion
#递归求阶乘:
def factorial(n):
if n == 1:
return 1 #(1)必须包含退出条件,同C语言
else:
return n * factorial(n-1) #(2)必须调用函数自身,同C语言
number = int(input("请输入一个正整数:"))
result = factorial(number)
print("%d 的阶乘为:%d" % (number, result))
#运行:
请输入一个正整数:10
10 的阶乘为:3628800
斐波那契数列(递归)
def fab(n):
if n < 1:
print("input error!")
return -1
if n == 1 or n == 2:
return 1
else:
return fab(n-1) + fab(n-2)
num = int(input("请输入一个数字:"))
result = fab(num)
print("斐波那契数列结果为:%d" % result)
汉诺塔游戏(递归)
def hanoi(n, x, y, z):
if n == 1:
print(x, '-->', z)
else:
hanoi(n-1, x, y, z) #将前n-1个盘子从x移动到y上
print(x, '-->', z) #将最底下的最后一个盘子从x移动到z上
hanoi(n-1, y, x, z) #将y上的n-1个盘子移动到z上
n = int(input('请输入汉诺塔的层数:'))
hanoi(n, 'x', 'y', 'z')
---------------------------------2017.08.29--------------------------------------
12丶字典 dict
(1) 字典是一种映射类型(key:value 键值映射项),类型名为 dict
(2) 字典的表示使用{}大括号,元素映射之间使用:冒号,使用dictname[]访问字典映射的值
(3) 新建字典有两种方法:三层小括号,一层小括号中key=value
(4) 字典中的键值映射项是无序的,popitem时是随机弹出
(5) 字典基本操作:
len(d) 返回d中项的数量
d[k] 返回映射到键k上的值
d[k]=v 将值v映射到键k上
del d[k] 删除键为k的项
k in d 检查d中是否含有键为k的项
(6) 字典常用方法: clear()/copy()/fromkeys()/get()/has_key()/items()/iteritems()/keys()/iterkeys()/pop()/popitem()/setdefault()/update()/values()/itervalues()
映射关系示例
>>> brand = ['李宁', '耐克', '阿迪达斯', 'xx工作室']
>>> slogan = ['一切皆有可能', 'Just do it', 'Impossible is nothing', '让编程改变世界']
>>> print('鱼c工作室的口号是: ', slogan[brand.index('xx工作室')])
xx工作室的口号是: 让编程改变世界
#使用字典来完成映射工作
>>> dict1 = {'李宁':'一切皆有可能', '耐克':'Just do it', '阿迪达斯':'Impossible is nothing', 'xx工作室':'让编程改变世界'}
>>> print('xx工作室的口号是: ', dict1['xx工作室'])
xx工作室的口号是: 让编程改变世界
#新建一个字典方法1:dict(((key1, value1), (key2, value2), ...))
>>> dictname = dict((('y', 1), ('u', 2), ('a', 3), ('n', 4)))
>>> dictname
{'u': 2, 'a': 3, 'y': 1, 'n': 4}
#新建一个字典方法2:(key1=value1, key2=value2, ...)
>>> dictname = dict(苍井空='让AV改变宅男', 工作室='让编程改变世界')
>>> dictname
{'工作室': '让编程改变世界', '苍井空': '让AV改变宅男'}
>>> dictname['苍井空']
'让AV改变宅男'
#字典中新增映射元素
>>> dictname['爱迪生'] = '天才是99%的汗水+1%的灵感,但这1%的灵感比99%的汗水更重要。'
>>> dictname
{'工作室': '让编程改变世界', '爱迪生': '天才是99%的汗水+1%的灵感,但这1%的灵感比99%的汗水更重要。', '苍井空': '让AV改变宅男'}
字典中键、值、键值映射项的访问
>>> dict1 = dict1.fromkeys(range(10), '赞')
>>> dict1
{0: '赞', 1: '赞', 2: '赞', 3: '赞', 4: '赞', 5: '赞', 6: '赞', 7: '赞', 8: '赞', 9: '赞'}
>>> for eachKey in dict1.keys():
print(eachKey, end=' ')
0 1 2 3 4 5 6 7 8 9
>>> for eachValue in dict1.values():
print(eachValue, end=' ')
赞 赞 赞 赞 赞 赞 赞 赞 赞
>>> for eachItems in dict1.items():
print(eachItems, end=' ')
(0, '赞') (1, '赞') (2, '赞') (3, '赞') (4, '赞') (5, '赞') (6, '赞') (7, '赞') (8, '赞') (9, '赞')
fromkeys(...) 创建并返回一个新的字典
dictname.fromkeys(S[, V])
@S key;@V value 可选参数
举例:
>>> dict1 = {}
>>> dict1.fromkeys((1, 2, 3))
{1: None, 2: None, 3: None}
>>> dict1.fromkeys((1, 2, 3), 'number')
{1: 'number', 2: 'number', 3: 'number'}
>>> dict1.fromkeys((1, 2, 3), ('one', 'two', 'three'))
{1: ('one', 'two', 'three'), 2: ('one', 'two', 'three'), 3: ('one', 'two', 'three')}
>>> dict1.fromkeys((1, 3), 'num')
{1: 'num', 3: 'num'} #还是返回新的字典,并不会修改dict1
get(...) 从字典中找到key的映射值value
举例:
>>> dict1 = dict.fromkeys(range(10), 'Yes!')
>>> dict1
{0: 'Yes!', 1: 'Yes!', 2: 'Yes!', 3: 'Yes!', 4: 'Yes!', 5: 'Yes!', 6: 'Yes!', 7: 'Yes!', 8: 'Yes!', 9: 'Yes!'}
>>> dict1.get(10)
>>> print(dict1.get(10))
None
>>> dict1.get(10, '木有')
'木有'
>>> dict1.get(9, '木有')
'Yes!'
setdefault(...) 类似于get但在字典里如果找不到的话会将映射项添加到字典中
dictname.setdefault(key, value)
举例:
>>> a
{3: 'three', 4: 'four'}
>>> a.setdefault(5, '小白')
'小白'
>>> a
{3: 'three', 4: 'four', 5: '小白'}
clear() 清空一个字典(包括使用当前字典赋值的其他字典)
举例:
>>> dict1.clear()
>>> dict1
{}
copy() 拷贝一个字典(浅拷贝,不受字典修改影响)
>>> a = {1:'one', 2:'two', 3:'three'}
>>> b = a.copy()
>>> c = a #相当于C的指针,C++的引用,修改字典c的值会同时影响字典a
>>> a
{1: 'one', 2: 'two', 3: 'three'}
>>> b
{1: 'one', 2: 'two', 3: 'three'}
>>> c
{1: 'one', 2: 'two', 3: 'three'}
>>> print(id(a), id(b), id(c))
2334673012680 2334672609672 2334673012680
>>> c[4] = 'four'
>>> c
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> a
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> b
{1: 'one', 2: 'two', 3: 'three'}
pop(...) 给定一个键弹出一个值
popitem() 随机弹出一个项(映射关系的键和值)
举例:
>>> a
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> a.pop(2)
'two'
>>> a
{1: 'one', 3: 'three', 4: 'four'}
>>> a.popitem()
(1, 'one')
>>> a
{3: 'three', 4: 'four'}
update(...) 使用一个子字典去更新原字典
dictname1.update(dictname2)
举例:
>>> a
{3: 'three', 4: 'four', 5: '小白'}
>>> b = {'小白':'狗'}
>>> a.update(b)
>>> a
{'小白': '狗', 3: 'three', 4: 'four', 5: '小白'}
13丶集合 set
(1) 使用{}创建的没有映射关系的字典,成为集合类型,如num = {1, 2, 3, 4, 5}
(2) 集合中元素唯一,重复的数据会被自动清理掉
(3) 集合中元素无序,不能索引取到其元素的值
(4) 集合使用关键字 set([]) 来创建
(5) 集合支持 in 和 not in 来判断是否属于集合
举例:
>>> num = {}
>>> type(num)
#set没有体现字典的映射
>>> num1 = {1, 2, 3, 4, 5}
>>> type(num1)
#set唯一性
>>> num2 = {1, 2, 3, 4, 2, 3, 5, 1, 5, 5}
>>> num2
{1, 2, 3, 4, 5}
#set无序性
>>> num2[2]
TypeError: 'set' object does not support indexing
#set关键字创建集合
>>> set1 = set([1, 2, 3, 4, 5, 5, 5, 3, 1])
>>> set1
{1, 2, 3, 4, 5}
#list实现set的唯一性
>>> num1 = [1, 2, 3, 4, 5, 5, 3, 1, 0]
>>> temp = []
>>> for each in num1:
if each not in temp:
temp.append(each)
>>> temp
[1, 2, 3, 4, 5, 0]
#简化: 实现set的唯一性,并且会把set的无序性变为有序
>>> num1
[1, 2, 3, 4, 5, 5, 3, 1, 0]
>>> num1 = list(set(num1))
>>> num1
[0, 1, 2, 3, 4, 5]
add(...) 往集合中加入元素
remove(...) 从集合中删除指定元素
举例:
>>> num2
{1, 2, 3, 4, 5}
>>> num2.add(6)
>>> num2
{1, 2, 3, 4, 5, 6}
>>> num2.remove(4)
>>> num2
{1, 2, 3, 5, 6}
frozenset(...) 将集合设置为不可变集合,frozen:冰冻的,冻结的
举例:
>>> num3 = frozenset([1, 2, 3, 4, 5])
>>> num3
frozenset({1, 2, 3, 4, 5})
>>> num3.add(6)
AttributeError: 'frozenset' object has no attribute 'add'
集合内建方法(整理出来):
http://bbs.fishc.com/forum.php?mod=viewthread&tid=45276&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
14丶文件操作 file operation
open(...) 打开一个文件返回一个流对象
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) #除了file参数,其他参数均有默认值
'r' 只读模式
'w' 写入(会覆盖已存在的文件)模式
'x' 文件存在,报异常的模式
'a' 写入(文件存在则追加)模式
'b' 二进制模式
't' 文本模式
'+' 可读写模式(可添加到其他模式)
'U' 通用换行符支持
举例:
#打开一个文件,注意路径的中\反斜杠的转义(或用/斜杠一根即可)
>>> f = open('C:\\Users\\Jan\\Desktop\\IP.txt')
>>> f
<_io.TextIOWrapper name='C:\\Users\\Jan\\Desktop\\IP.txt' mode='r' encoding='cp936'>
文件对象方法
(整理)
http://bbs.fishc.com/forum.php?mod=viewthread&tid=45279&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
(1) 文件对象支持直接使用list转换读出
(2) 文件对象支持 for...in 的迭代方式读取
举例:
>>> f = open('C:\\Users\\Jan\\Desktop\\IP.txt') #f,打开的文件流对象
>>> f.read()
'【本机】\nIP:192.168.31.217\n[ Ctrl + r ]\ncmd\nping 192.168.31.207\nmstsc\n\n\n【虚拟机】 - 虚拟网络编辑器(自动) - 桥接模式\nIP:192.168.31.207\nlinux账户:jiangyuan\nlinux密码:123456\n'
>>> f.read()
''
>>> f.close()
>>> f = open('C:\\Users\\Jan\\Desktop\\IP.txt')
>>> f.read(5)
'【本机】\n'
>>> f.tell()
10
>>> f.seek(45, 0) #0,文件起始位置;45,偏移字节数。从文件起始位置偏移一定量字节
45
>>> f.readline()
'md\n'
>>> list(f)
['ping 192.168.31.207\n', 'mstsc\n', '\n', '\n', '【虚拟机】 - 虚拟网络编辑器(自动) - 桥接模式\n', 'IP:192.168.31.207\n', 'linux账户:jiangyuan\n', 'linux密码:123456\n']
>>> for each_line in f:
print(each_line)#逐行读取文件内容的高效方法
【本机】
IP:192.168.31.217
[ Ctrl + r ]
cmd
ping 192.168.31.207
mstsc
...
#创建一个新的可写入的文件,写入内容,然后关闭文件流对象
>>> f = open('C:\\Users\\Jan\\Desktop\\test.txt', 'w')
>>> f.write('some lines')
10
>>> f.close()
任务:将文件record.txt中的数据进行分割并且按照规律保存起来。
record.txt下载:
链接:http://pan.baidu.com/s/1sjzAhNR (密码:tf2e)
#最终代码如下:
def save_file(boy, girl, count):
# 文件的分别保存操作
file_name_boy = 'boy_' + str(count) + '.txt'
file_name_girl = 'girl_' + str(count) + '.txt'
boy_f = open(file_name_boy, 'w')
girl_f = open(file_name_girl, 'w')
boy_f.writelines(boy)
girl_f.writelines(girl)
boy_f.close()
girl_f.close()
def split_file(filename):
f = open(filename)
boy = []
girl = []
count = 1
for each_line in f:
if each_line[:6] != '======':
# 我们再这里进行字符串分割操作
(role, line_spoken) = each_line.split(':', 1) #中文冒号:否则会报错
if role == '小甲鱼':
boy.append(line_spoken)
if role == '小客服':
girl.append(line_spoken)
else:
save_file(boy, girl, count)
boy = []
girl = []
count += 1
save_file(boy, girl, count)
f.close()
split_file('C:\\Users\\Jan\\Desktop\\python_study\\record.txt')
文件操作练习题及答案(伪代码可以保存一下):
http://blog.csdn.net/junwei0206/article/details/44988195
---------------------------------2017.08.30--------------------------------------
15丶模块 modules
(1) 模块是.py的python文件
(2) 使用模块是需要进行导入,使用关键字 import
举例:
>>> import random
>>> secret = random.randint(1, 10)
>>> secret
3
os 模块(系统模块)
os模块方法表格:http://bbs.fishc.com/thread-45512-1-2.html
举例:
>>> import os
>>> os.getcwd() #输出当前工作目录
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35'
>>> os.chdir('E:\\') #改变工作目录
>>> os.getcwd()
'E:\\'
>>> os.listdir('E:\\') #列举指定目录中的文件名
['$RECYCLE.BIN', '.cache', '360Downloads', 'Jan_mi', 'Jan个人总资料', 'Qiyi', 'QQMusicCache', 'qycache', 'System Volume Information', 'Youku Files', 'Youxun', '博客'] #RECYCLE.BIN是个回收站
>>> os.mkdir('E:\\A') #创建单层目录,如该目录已存在抛出异常
>>> os.mkdir('E:\\A\\B')
>>> os.mkdir('E:\\C\\D')
FileNotFoundError: [WinError 3] 系统找不到指定的路径。: 'E:\\C\\D'
>>> os.remove('E:\\A\\B\\test.txt') #删除文件
>>> os.rmdir('E:\\A\\B\\') #删除单层目录,如该目录非空则抛出异常
>>> os.system('cmd') #运行系统的shell命令:windows shell窗口
-1073741510
>>> os.system('calc') #运行系统的shell命令:calc计算器
0
>>> os.curdir #当前目录('.')
'.'
>>> os.listdir(os.curdir) # 等同于 os.listdir('.')
['$RECYCLE.BIN', '.cache', '360Downloads', 'A', 'Jan_mi', 'Jan个人总资料', 'Qiyi', 'QQMusicCache', 'qycache', 'System Volume Information', 'Youku Files', 'Youxun', '博客']
>>> os.sep #输出操作系统特定的路径分隔符(Win下为'\\',Linux下为'/')
'\\'
>>> os.linesep #当前平台使用的行终止符(Win下为'\r\n',Linux下为'\n')
'\r\n'
>>> os.name #指代当前使用的操作系统(包括:'posix', 'nt', 'mac', 'os2', 'ce', 'java')
'nt' #nt是windows系统平台
os.path 模块(系统路径模块属于os的子模块)
>>> os.path.basename('E:\\A\\B\\C\\sexy.avi') #去掉目录路径,单独返回文件名
'sexy.avi'
>>> os.path.dirname('E:\\A\\B\\C\\sexy.avi') #去掉文件名,单独返回目录路径
'E:\\A\\B\\C'
>>> os.path.join('A', 'B', 'C') #将path1, path2...各部分组合成一个路径名
'A\\B\\C'
>>> os.path.join('D:', 'A', 'B', 'C')
'D:A\\B\\C'
>>> os.path.join('D:\\', 'A', 'B', 'C') #注意盘符需要带上斜杠
'D:\\A\\B\\C'
>>> os.path.split('E:\\A\\SEXY.AVI') #分割文件名与路径,返回(f_path, f_name)元组。
('E:\\A', 'SEXY.AVI')
>>> os.path.split('E:\\A\\B\\C')
('E:\\A\\B', 'C')
>>> os.path.splitext('E:\\A\\SEXY.AVI') #分离文件名与扩展名,返回(f_name, f_extension)元组
('E:\\A\\SEXY', '.AVI')
>>> os.path.getatime('E:\\A\\test.txt') #返回指定文件最近的访问时间
1504103243.229383 #浮点型秒数,可用time模块的gmtime()或localtime()函数换算
>>> import time
>>> time.gmtime(os.path.getatime('E:\\A\\test.txt'))
time.struct_time(tm_year=2017, tm_mon=8, tm_mday=30, tm_hour=14, tm_min=27, tm_sec=23, tm_wday=2, tm_yday=242, tm_isdst=0)
>>> time.localtime(os.path.getatime('E:\\A\\test.txt'))
time.struct_time(tm_year=2017, tm_mon=8, tm_mday=30, tm_hour=22, tm_min=27, tm_sec=23, tm_wday=2, tm_yday=242, tm_isdst=0)
>>> time.localtime(os.path.getmtime('E:\\A\\test.txt'))
time.struct_time(tm_year=2017, tm_mon=8, tm_mday=30, tm_hour=22, tm_min=30, tm_sec=1, tm_wday=2, tm_yday=242, tm_isdst=0)
>>> time.localtime(os.path.getctime('E:\\A\\test.txt'))
time.struct_time(tm_year=2017, tm_mon=8, tm_mday=30, tm_hour=22, tm_min=27, tm_sec=23, tm_wday=2, tm_yday=242, tm_isdst=0)
>>> os.path.ismount('E:\\') #判断指定路径是否存在且是一个挂载点
True
>>> os.path.ismount('E:\\A')
False
pickle 模块(泡菜模块)
举例:
>>> import pickle
>>> my_list = [123, 3.14, '名字', ['another list']]
>>> pickle_f = open('E:\\A\\my_list.pkl', 'wb')
>>> pickle.dump(my_list, pickle_f) #将list的内容倾倒入文件流对象中
>>> pickle_f.close()
>>> pickle_f = open('E:\\A\\my_list.pkl', 'rb')
>>> my_list2 = pickle.load(pickle_f) #将.pkl文件的内容装载到list中
>>> print(my_list2)
[123, 3.14, '名字', ['another list']]
>>> city = {'城市1':'000001', '城市2':'000002', '城市n':'999999'} #此字典映射有70k这么大
>>> import pickle
>>> pickle_f = open('E:\\A\\city.pkl', 'wb') #将70k的字典映射写入文件
>>> pickle.dump(city, pickle_f)
>>> pickle_f.close()
>>> pickle_file = open('E:\\A\\city.pkl', 'rb') #使用字典的时候打开文件装载即可
>>> city = pickle.load(pickle_file)
>>> print(city)
{'城市2': '000002', '城市n': '999999', '城市1': '000001'}
---------------------------------2017.08.31--------------------------------------
16丶异常 exception
异常汇总
AssertionError 断言语句(assert)失败
AttributeError 尝试访问未知的对象属性
EOFError 用户输入文件末尾标志EOF(Ctrl+d)
FloatingPointError 浮点计算错误
GeneratorExit generator.close()方法被调用的时候
ImportError 导入模块失败的时候
IndexError 索引超出序列的范围
KeyError 字典中查找一个不存在的关键字
KeyboardInterrupt 用户输入中断键(Ctrl+c)
MemoryError 内存溢出(可通过删除对象释放内存)
NameError 尝试访问一个不存在的变量
NotImplementedError 尚未实现的方法
OSError 操作系统产生的异常(例如打开一个不存在的文件)
OverflowError 数值运算超出最大限制
ReferenceError 弱引用(weak reference)试图访问一个已经被垃圾回收机制回收了的对象
RuntimeError 一般的运行时错误
StopIteration 迭代器没有更多的值
SyntaxError Python的语法错误
IndentationError 缩进错误
TabError Tab和空格混合使用
SystemError Python编译器系统错误
SystemExit Python编译器进程被关闭
TypeError 不同类型间的无效操作
UnboundLocalError 访问一个未初始化的本地变量(NameError的子类)
UnicodeError Unicode相关的错误(ValueError的子类)
UnicodeEncodeError Unicode编码时的错误(UnicodeError的子类)
UnicodeDecodeError Unicode解码时的错误(UnicodeError的子类)
UnicodeTranslateError Unicode转换时的错误(UnicodeError的子类)
ValueError 传入无效的参数
ZeroDivisionError 除数为零
部分举例:
>>> my_list = ['我是帅哥', '你是美女']
>>> assert len(my_list) > 0
>>> my_list.pop()
'你是美女'
>>> my_list.pop()
'我是帅哥'
>>> assert len(my_list) > 0
Traceback (most recent call last):
File "", line 1, in
assert len(my_list) > 0
AssertionError #断言语句(assert)失败
>>> my_list.abcd
Traceback (most recent call last):
File "", line 1, in
my_list.abcd
AttributeError: 'list' object has no attribute 'abcd'#尝试访问未知的对象属性
>>> my_list = [1, 2, 3]
>>> my_list[3]
Traceback (most recent call last):
File "", line 1, in
my_list[3]
IndexError: list index out of range #索引超出序列的范围
>>> my_list[2]
3
>>> my_dict = {'one':1, 'two':2, 'three':3}
>>> my_dict['one']
1
>>> my_dict['four']
Traceback (most recent call last):
File "", line 1, in
my_dict['four']
KeyError: 'four' #字典中查找一个不存在的关键字
>>> my_dict.get('four')
>>> #dict.get(...)方法比较安全合适
异常检测与处理
(1) try语句一旦检测出现异常,则剩下的其他代码则不会执行
(2) raise Exception_name 主动引发一个自定义异常名字的异常,可定义异常描述
try:
#检测范围
except Exception[as reason]:
#出现异常(Exception)后的处理代码
finally:
#无论如何都会被执行的代码(收尾工作)
举例:
try:
f = open('我为什么是一个文件.txt')
print(f.read())
f.close()
except OSError:
print('文件出错啦T_T')
运行:
文件出错啦T_T
try:
f = open('我为什么是一个文件.txt')
print(f.read())
f.close()
except OSError as reason:
print('文件出错啦T_T\n错误的原因是:' + str(reason))
运行:
文件出错啦T_T
错误的原因是:[Errno 2] No such file or directory: '我为什么是一个文件.txt'
try:
sum = 1 + '1'
f = open('我为什么是一个文件.txt')
print(f.read())
f.close()
except (OSError, TypeError): #多个异常同时捕获
print('出错啦T_T')
运行:出错啦T_T
try:
f = open('我为什么是一个文件.txt', 'w')
print(f.write('我存在了!')) #没有finally时并不会写入文件
sum = 1 + '1'
f.close()
except (OSError, TypeError):
print('出错啦T_T')
finally:
f.close()
运行:
5
出错啦T_T
>>> raise ZeroDivisionError('除数为0的异常')
Traceback (most recent call last):
File "", line 1, in
raise ZeroDivisionError('除数为0的异常')
ZeroDivisionError: 除数为0的异常
17丶丰富的esle-简洁的with
else
举例:while-else / for-else
def showMaxFactor(num):
count = num // 2
while count > 1:
if num % count == 0:
print('%d最大的约数是%d' % (num, count))
break
count -= 1
else: #while循环完没有break就会执行else
print('%d是素数!' % num)
num = int(input('请输入一个数:'))
showMaxFactor(num)
举例:try-else
try:
print(int('123'))
except ValueError as reason:
print('出错啦:' + str(reason))
else:
print('Good!没有任何异常。')
运行:
123
Good!没有任何异常。
with as
举例:
try:
with open('data.txt', 'w') as f: #比 f = open(...) 多了文件不使用时自动关闭功能
for each_line in f:
print(each_line)
except OSError as reason:
print('出错啦:' + str(reason))
#finally: #有了with就不需要finally去调用关闭,会自动关闭
# f.close() #如果文件data.txt不存在就试图去关闭一个不存在的文件
18丶图形用户界面 EasyGui
EasyGui官网:http://easygui.sourceforge.net
中文的教学文档:http://bbs.fishc.com/thread-46069-1-1.html (要看完并实操)
模块库:easygui-0.96.zip
安装方法:
(1) 使用命令窗口切换到easygui-docs-0.96的目录下
(2) 【Windows下】执行C:\Python33\python.exe setup.py install
> cd Desktop
> cd puthon_study\easygui-0.96
#然后修改C:\Program Files (x86)\python\python.exe为管理员权限:右键-兼容性-更改所有用户的设置-以管理员身份运行此程序-确定
> "C:\Program Files (x86)\python\python.exe" setup.py install
#生成了文件模块库C:\Program Files (x86)\python\Lib\site-packages\easygui.py
> "C:\Program Files (x86)\python\python.exe" easygui.py
#easygui的演示程序
PS: 【Linux或Mac下】sudo /Library/Framworks/Python.framework/Versions/3.3/bin/python3.3 setup.py install
使用方法:
【遇到难题】import easygui 出错~!!!
【解决办法】
(1) 重装python IDLE勾选添加python路径,选择目录安装到C:\python文件夹,如重装则忽略(2),如此一来win-cmd下的python中sys.path和IDLE中的sys.path则一致了。
(2) 对比windows命令窗口中启动python与IDLE中python的系统路径,添加到IDLE即可。
windows中系统路径:
C:\Users\Jan> "C:\Program Files (x86)\python\python.exe"
>>> import sys
>>> sys.path
['',
'C:\\Program Files (x86)\\python\\python35.zip',
'C:\\Program Files (x86)\\python\\DLLs',
'C:\\Program Files (x86)\\python\\lib',
'C:\\Program Files (x86)\\python',
'C:\\Program Files (x86)\\python\\lib\\site-packages']
IDLE中系统路径:
>>> import easygui as g
Traceback (most recent call last):
File "", line 1, in
import easygui as g
ImportError: No module named 'easygui'
>>> import sys
>>> sys.path
['',
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\Lib\\idlelib',
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\python35.zip',
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\DLLs',
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\lib',
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35',
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\lib\\site-packages']
>>> sys.path.append('C:\\Program Files (x86)\\python\\python35.zip')
>>> sys.path.append('C:\\Program Files (x86)\\python\\DLLs')
>>> sys.path.append('C:\\Program Files (x86)\\python\\lib')
>>> sys.path.append('C:\\Program Files (x86)\\python')
>>> sys.path.append('C:\\Program Files (x86)\\python\\lib\\site-packages')
>>> import easygui as g #import ... as ... 导入模块的同时重定义模块名字
>>> g.msgbox('嗨,python!')
'OK'
>>>
# No error, success... 但每次重启IDLE都需要将windows下的sys.path进行添加。
# 示例,gui界面文字小游戏
import easygui as g
import sys
while 1:
g.msgbox("嗨,欢迎进入第一个界面小游戏^_^")
msg ="请问你希望在鱼C工作室学习到什么知识呢?"
title = "小游戏互动"
choices = ["谈恋爱", "编程", "OOXX", "琴棋书画"]
choice = g.choicebox(msg, title, choices)
# note that we convert choice to string, in case
# the user cancelled the choice, and we got None.
g.msgbox("你的选择是: " + str(choice), "结果")
msg = "你希望重新开始小游戏吗?"
title = "请选择"
if g.ccbox(msg, title): # show a Continue/Cancel dialog
pass # user chose Continue
else:
sys.exit(0) # user chose Cancel
---------------------------------2017.09.01--------------------------------------
19丶类和对象 class and object
面向对象(Object Oriented)
(1) python约定类名以大写字母开头
(2) 面向对象特征:封装(信息隐蔽)、继承(子类共享父类公共内容)、多态(不同对象对同一方法响应不同的行动)
类的示例:
class Turtle:
#属性
color = 'green'
weight = 60
legs = 2
shell = True
age = 26
#方法
def climb(self):
print('我正在学习...')
def run(self):
print('我正在奔跑...')
运行:
>>> tt = Turtle() #类Turtle的示例对象tt
>>> Turtle
>>> type(Turtle)
>>> type('abc')
>>> tt.climb()
我正在学习...
>>> tt.run()
我正在奔跑...
#封装
>>> list1 = [2, 1, 7, 5, 3]
>>> list1.sort() #sort() 方法封装在list1对象中
>>> list1
[1, 2, 3, 5, 7]
>>> list1.append(9) #append() 方法封装在list1对象中
>>> list1
[1, 2, 3, 5, 7, 9]
#继承
>>> class Mylist(list):
pass
>>> list2 = Mylist()
>>> list2.append(5) #list2可以使用append()方法,继承了Mylist(list)中的list参数类
>>> list2.append(3)
>>> list2.append(7)
>>> list2
[5, 3, 7]
>>> list2.sort()
>>> list2
[3, 5, 7]
#多态
>>> class A:
def fun(self):
print('我是小A')
>>> class B:
def fun(self):
print('我是小B')
>>> a = A()
>>> b = B()
>>> a.fun() #不同对象对同一方法响应不同的行动
我是小A
>>> b.fun() #不同对象对同一方法响应不同的行动
我是小B
self
相当于C++的this指针(指向当前对象本身的地址),表明类自身
举例:
>>> class Ball:
def setName(self, name): #默认self的写法
self.name = name
def kick(self): #默认self的写法
print('我叫%s, 该死的谁踢我...' % self.name)
>>> a = Ball()
>>> a.setName('球A')
>>> b = Ball()
>>> b.setName('球B')
>>> c = Ball()
>>> c.setName('土豆')
>>> a.kick()
我叫球A, 该死的谁踢我...
>>> c.kick()
我叫土豆, 该死的谁踢我...
魔法方法:__init__(self)
__init__(self, parma1, parma2, ...)
举例:
>>> class Ball:
def __init__(self, name):
self.name = name
def kick(self):
print('我叫%s,该死的,谁踢我!!' % self.name)
>>> b = Ball('土豆')
>>> b.kick()
我叫土豆,该死的,谁踢我!!
>>> a = Ball() #__init__默认设置了name,所以必须传递name实参,否则报错
TypeError: __init__() missing 1 required positional argument: 'name'
公有和私有
name mangling 名字改变/名字重造
公有成员:默认创建的成员均为公有。
私有成员:
(1) 在变量或函数名前加上"_"两个下划线即可。
(2) python中类的私有均属于伪私有,通过"对象._类_变量"的形式可以访问私有成员
举例:
>>> class Person:
__name = 'yuan.jiang'
>>> p = Person()
>>> p.name
AttributeError: 'Person' object has no attribute 'name'
>>> p.__name
AttributeError: 'Person' object has no attribute '__name'
>>> class Person:
__name = 'yuan.jiang'
def getName(self):
return self.__name
>>> p = Person()
>>> p.getName()
'yuan.jiang'
>>> p._Person__name #python中类的私有属于伪私有,此方式可访问私有成员
'yuan.jiang'
继承 inherit
class DerivedClassName(BaseClassName):
...
(1) 如果子类中定义于父类同名的成员时,则会自动覆盖父类对应的方法或属性
(2) 解决子类中__init()
举例:
>>> class Parent:
def hello(self):
print('正在调用父类的方法...')
>>> class Child(Parent):
pass
>>> p = Parent()
>>> p.hello()
正在调用父类的方法...
>>> c = Child()
>>> c.hello()
正在调用父类的方法...
>>> class Child(Parent):
def hello(self):
print('正在调用子类的方法...')
>>> c = Child()
>>> c.hello()
正在调用子类的方法...
>>> p.hello()
正在调用父类的方法...
举例:
import random as r
class Fish:
def __init__(self):
self.x = r.randint(0, 10)
self.y = r.randint(0, 10)
def move(self):
self.x -= 1
print('我的位置是:', self.x, self.y)
class Goldfish(Fish):
pass
class Carpfish(Fish):
pass
class Salmonfish(Fish):
pass
class Sharkfish(Fish):
def __init__(self): #重写了__init__方法覆盖了父类的__init__子类无法调用到self.x和self.y属性成员,导致了子类无法访问到父类的属性或方法的问题
self.hungry = True
def eat(self):
if self.hungry:
print('吃货的梦想就是天天有的吃^_^')
self.hungry = False
else:
print('太撑了,吃不下了!')
运行:
>>> fish = Fish()
>>> fish.move()
我的位置是: 3 0
>>> fish.move()
我的位置是: 2 0
>>> goldfish = Goldfish()
>>> goldfish.move()
我的位置是: 4 9
>>> goldfish.move()
我的位置是: 3 9
>>> shark = Sharkfish()
>>> shark.eat()
吃货的梦想就是天天有的吃^_^
>>> shark.eat()
太撑了,吃不下了!
>>> shark.move() #无法访问到父类的__init__()方法中的x变量
AttributeError: 'Sharkfish' object has no attribute 'x'
--------------------------------2017.09.02----------------------------------------
覆盖属性或方法问题优化
问题:针对子类属性或方法覆盖父类属性或方法的情况,导致子类无法访问父类中被覆盖的属性
(1) 调用未绑定的父类的方法
(2) 使用super方法(推荐)
举例:
def __init__(self):
Fish.__init__(self) #调用未绑定的父类的方法,相当于>>>Fish.__init__(Sharkfish)
self.hungry = True
运行:
>>> shark = Sharkfish()
>>> shark.move()
我的位置是: -1 2
>>> shark.move()
我的位置是: -2 2
举例:
def __init__(self):
super().__init__() #使用super方法解决
self.hungry = True
运行:
>>> shark = Sharkfish()
>>> shark.move()
我的位置是: 8 3
>>> shark.move()
我的位置是: 7 3
多重继承
class DerivedClassName(Base1, Base2, Base3, ...):
...
#建议少用,有可能会导致不可预见的bug(不可预见最麻烦)
>>> class Base1:
def fool(self):
print('我是fool,我为Base1代言...')
>>> class Base2:
def fool2(self):
print('我是fool2,我为Base2代言...')
>>> class C(Base1, Base2):
pass
>>> c = C()
>>> c.fool()
我是fool,我为Base1代言...
>>> c.fool2()
我是fool2,我为Base2代言...
组合
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): #组合的方式嵌套class
self.turtle = Turtle(x)
self.fish = Fish(y)
def print_num(self):
print('水池里总共有乌龟 %d 只,小鱼 %d 条!' % (self.turtle.num, self.fish.num))
运行:
>>> pool = Pool(1, 10)
>>> pool.print_num()
水池里总共有乌龟 1 只,小鱼 10 条!
类、类对象、示例对象
类定义 C
类对象 C
实例对象 a b c
举例:
>>> class C: #C, 既是类,也是类对象
count = 0
>>> a = C() #a,实例对象
>>> b = C() #b,实例对象
>>> c = C() #c,实例对象
>>> a.count
0
>>> b.count
0
>>> c.count
0
>>> c.count += 10
>>> c.count
10
>>> a.count
0
>>> b.count
0
>>> C.count #C,作为类对象
0
>>> C.count += 100 #C,作为类对象
>>> a.count
100
>>> b.count
100
>>> c.count
10
(1) 当属性名与方法名冲突,会导致方法不能正常调用。
(2) 一般遵循规则:属性名用英文名词,方法名用英文动词。
(3) python严格要求方法需要有实例才能被调用,即绑定的概念。
举例:
>>> class C:
def x(self):
print('X-man!')
>>> c = C()
>>> c.x()
X-man!
>>> c.x = 1
>>> c.x
1
>>> c.x() #方法名字被属性名字覆盖,调用出错
TypeError: 'int' object is not callable
>>> class BB:
def printBB():
print('no zuo no die.')
>>> BB.printBB()
no zuo no die.
>>> #没有self,也没有将类实例化
>>> bb = BB()
>>> bb.printBB()
Traceback (most recent call last):
File "", line 1, in
bb.printBB()
TypeError: printBB() takes 0 positional arguments but 1 was given
>>> class CC:
def setXY(self, x, y):
self.x = x;
self.y = y
>>> class CC:
def setXY(self, x, y):
self.x = x
self.y = y
def printXY(self):
print(self.x, self.y)
>>> dd = CC()
>>> dd.__dict__
{} #返回空的字典类型
>>> CC.__dict__
mappingproxy({'printXY': , '__doc__': None, '__dict__': , 'setXY': , '__module__': '__main__', '__weakref__': }) #使用类对象显示类的属性详情
>>> dd.setXY(4, 5)
>>> dd.__dict__
{'y': 5, 'x': 4} #将实例对象dd使用类的属性详情实例化了
>>> # setXY(self, x, y) <==> dd.setXY(dd, x, y)
>>> del CC
>>> ee = CC()
NameError: name 'CC' is not defined
>>> dd.printXY()
4 5 #类中定义的属性是静态的,类的实例对象中也会静态存储,所以实例对象dd正常存在。
类与对象的内置函数
issubclass
功能:测试一个类是否是另外一个类的子类
issubclass(class, classinfo)
(1) 一个类被认为是其自身的子类
(2) classinfo可以是类对象的元组,只要class属于其中任何一个候选类的子类,则返回True
举例:
>>> class A:
pass
>>> class B(A):
pass
>>> issubclass(B, A)
True
>>> issubclass(B, B)
True
>>> issubclass(B, object) #object是所有类的基类
True
>>> class C:
pass
>>> issubclass(B, C)
isinstance
功能:测试一个对象是否是一个类的实例对象
isinstance(object, classinfo)
(1) object为类的实例对象,如果不是类的实例对象,永远返回False
(2) 如果第二个参数不是类或者由类对象组成的元组,会抛出一个TypeError异常
举例:
>>> class A:
pass
>>> class B(A):
pass
>>> class C:
pass
>>> b1 = B()
>>> isinstance(b1, B)
True
>>> isinstance(b1, A)
True
>>> isinstance(b1, C)
False
>>> isinstance(b1, (A, B, C)) #b1对象是否在A/B/C里面,答案是True
True
hasattr
功能:测试一个对象里面是否有指定的属性
hasattr(object, name)
(1) object 对象名, name 是属性名(需要用引号引起来,否则报错)
getattr
功能:返回对象指定的属性值
getattr(object, name[, default])
(1) 如果属性值不存在打印default,没有default则抛出异常
setattr
功能:设置对象中指定属性的值,如果属性不存在则创建并赋值
setattr(object, name, value)
delattr
功能:删除对象中指定的属性,如果属性不存在则抛出异常
delattr(object, name)
举例:
>>> class C:
def __init__(self, x=0):
self.x = x
>>> c1 = C()
>>> hasattr(c1, 'x') #测试对象属性是否存在
True
>>> hasattr(c1, x)\
NameError: name 'x' is not defined
>>> getattr(c1, 'x') #获取对象属性的值
0
>>> getattr(c1, 'y')
AttributeError: 'C' object has no attribute 'y'
>>> getattr(c1, 'y', '您所访问的属性不存在!') #设置default默认提示语
'您所访问的属性不存在!'
>>> setattr(c1, 'y', 100) #设置对象属性的值
>>> getattr(c1, 'y')
100
>>> delattr(c1, 'y') #删除对象属性的值
>>> delattr(c1, 'y')
Traceback (most recent call last):
File "", line 1, in
delattr(c1, 'y')
AttributeError: y
property
功能:设置一个定义好的属性,通过对象属性来设置对象属性
property(fget=None, fset=None, fdel=None, doc=None)
(1) fget获取属性的方法, fset设置属性的方法, fdel删除属性的方法
举例:
>>> 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.getSize()
10
>>> c1.x
10
>>> c1.x = 18
>>> c1.x
18
>>> c1.getSize()
18
>>> c1.size
18
>>> del c1.x
>>> c1.size #x与size相当于相互引用关系,删除其中一个另一个即不能访问
AttributeError: 'C' object has no attribute 'size'
20丶魔法方法 magic methods
(1) 魔法方法总是被双下划綫包围,如 __init__
(2) 魔法方法是面向对象的python的一切
(3) 魔法方法的魔力体现在能够在适当的时候被调用
魔法方法汇总:http://bbs.fishc.com/forum.php?mod=viewthread&tid=48793&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
__init__(self[, ...])
功能:初始化类对象(根据需求决定是否增加属性参数)
返回值: None
举例:
>>> class Rectangle: #矩形类,需要长和宽,所以重写__init__
def __init__(self, x, y):
self.x = x
self.y = y
def getPeri(self): #获得周长
return (self.x + self.y) * 2
def getArea(self): #获得面积
return self.x * self.y
>>> rect = Rectangle(3, 4)
>>> rect.getPeri()
14
>>> rect.getArea()
12
__new__(class[, ...])
功能:创建一个类对象
返回值:返回一个对象
(1) 在__init__方法之前被调用,属于类创建时第一个被调用的方法
举例:
>>> class CapStr(str): #继承一个不可改变的类型str
def __new__(cls, string): #使用new将类型的功能进行转换
string = string.upper()
return str.__new__(cls, string) #把重写后的str中的new方法带传代餐返回
>>> a = CapStr("I love M.")
>>> a
'I LOVE M.'
__del__(self)
功能:对象将要被销毁的时候,自动调用,属于自动垃圾回收方法
注意:del x != x.__del__()
举例:
>>> class C:
def __init__(self):
print('我是init方法,我被调用了!')
def __del__(self):
print('我是del方法,我被调用了!')
>>> c1 = C()
我是init方法,我被调用了!
>>> c2 = c1 #对象的赋值不会调用__init__
>>> c3 = c2
>>> del c3
>>> del c2
>>> del c1 #其他的赋值对象del时不会调用__del__ (c2和c3只是c1的一份拷贝)
我是del方法,我被调用了!
算术运算魔法方法
__add__(self, other) 加法:+
__sub__(self, other) 减法:-
__mul__(self, other) 乘法:*
__truediv__(self, other) 真除法:/
__floordiv__(self, other) 整数除法://
__mod__(self, other) 取模算法:%
__divmod__(self, other) divmod()调用时的行为
__pow__(self, other[, modulo]) power()调用或 ** 运算时的行为
__lshift__(self, other) 按位左移:<<
__rshift__(self, other) 按位右移:>>
__and__(self, other) 按位与:&
__xor__(self, other) 按位异或:^
__or__(self, other) 按位或:|
举例:
>>> class New_int(int):
def __add__(self, other):
return int.__sub__(self, other)
def __sub__(self, other):
return int.__add__(self, other)
>>> a = New_int(3)
>>> b = New_int(5)
>>> a + b
-2
>>> a - b
8
>>> class Try_int(int):
def __add__(self, other):
return int(self) + int(other)
def __sub__(self, other):
return int(self) - int(other)
>>> a = Try_int(3)
>>> b = Try_int(5)
>>> a + b
8
类定制的计时器
(1) 定制一个计时器的类
(2) start和stop方法代表启动计时和停止计时
(3) 假设计时器对象t1,print(t1)和直接调用t1均显示结果
(4) 当计时器未启动或已经停止计时,调用stop方法会给与温馨的提示
(5) 两个计时器对象可以进行相加:t1 + t2
需要的资源:
(1) 使用time模块的localtime方法获取时间
(2) __str__ 方法 __repr__ 方法可用来打印文字
time 模块
详解链接:http://bbs.fishc.com/forum.php?mod=viewthread&tid=51326&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
struct_time元组
time.struct_time(tm_year=2017, tm_mon=9, tm_mday=2, tm_hour=12, tm_min=18, tm_sec=55, tm_wday=5, tm_yday=245, tm_isdst=0)
类定制计时器代码:http://blog.csdn.net/sinat_36184075/article/details/77806778
属性访问
__getattribute__(self, name) #定义当该类的属性被访问时的行为
__getattr__(self, name) #定义当用户试图获取一个不存在的属性时的行为
__setattr__(self, name, value) #定义当一个属性被设置(包括初始化)时的行为
__delattr__(self, name) #定义一个属性被删除时的行为
举例:
>>> class C:
def __getattribute__(self, name):
print('getattribute')
return super().__getattribute__(name)
def __getattr__(self, name):
print('getattr')
def __setattr__(self, name, value):
print('setattr')
super().__setattr__(name, value)
def __delattr__(self, name):
print('delattr')
super().__delattr__(name)
>>> c = C()
>>> c.x
getattribute
getattr
>>> c.x = 1
setattr #初始化时自动调用setattr
>>> c.x
getattribute
1
>>> del c.x
delattr
举例:属性访问时的严重问题,无限递归
class Rectangle: #矩形
def __init__(self, width=0, height=0): #宽高不相等,长方形
self.width = width
self.height = height
def __setattr__(self, name, value):
if name == 'square': #宽高相等,正方形
self.width = value
self.height = value
else:
#self.name = value #会导致类无限递归自己
super().__setattr__(name, value) #解决办法①:super() 推荐。
#self.__dict__[name] = value #解决办法②:字典
def getArea(self):
return self.width * self.height
运行:
>>> r1 = Rectangle(4, 5)
>>> r1.getArea()
20
>>> r1.square = 10 #正方形
>>> r1.width
10
>>> r1.height
10
>>> r1.getArea()
100
>>> r1.__dict__ #以字典的形式查看类中的属性和值
{'width': 10, 'height': 10}
--------------------------------2017.09.03----------------------------------------
描述符 decriptor
描述符就是将某种特殊类型的类的实例指派给另一个类的属性。
__get__(self, instance, owner) #用于访问属性,返回属性的值
__set__(self, instance, value) #将在属性分配操作中调用,不反悔任何内容
__delete__(self, instance) #控制删除操作,不返回任何内容
@self, 描述符类本身的类实例
@instance, 拥有者的类实例
@owner, 拥有者类本身
@value, 所赋的值
举例:
>>> class MyDecriptor:
def __get__(self, instance, owner):
print('getting: ', self, instance, owner)
def __set__(self, instance, value):
print('setting: ', self, instance, value)
def __delete__(self, instance):
print('deleting: ', self, instance)
>>> class Test:
x = MyDecriptor()
>>> #MyDecriptor是x的描述符类
>>> test = Test() #实例化Test()类
>>> test.x
getting: <__main__.MyDecriptor object at 0x000002164DC31FD0> <__main__.Test object at 0x000002164DBB6F28>
>>> test
<__main__.Test object at 0x000002164DBB6F28>
>>> test.x = 'X-man'
setting: <__main__.MyDecriptor object at 0x000002164DC31FD0> <__main__.Test object at 0x000002164DBB6F28> X-man
>>> del test.x
deleting: <__main__.MyDecriptor object at 0x000002164DC31FD0> <__main__.Test object at 0x000002164DBB6F28>
自定义的描述符
>>> class MyProperty:
def __init__(self, fget=None, fset=None, fdel=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
def __get__(self, instance, owner):
return self.fget(instance) #instance拥有者的实例对象
def __set__(self, instance, value):
self.fset(instance, value)
def __delete__(self, instance):
self.fdel(instance)
>>> class C:
def __init__(self):
self._x = None
def getX(self):
return self._x
def setX(self, value):
self._x = value
def delX(self):
del self._x
x = MyProperty(getX, setX, delX)
>>> c = C()
>>> c.x = 'X-man'
>>> c.x
'X-man' #使用x影响_x的值
>>> c._x
'X-man'
>>> del c.x #删除后,c.x和c._x都不存在
练习:温度转换
定义一个温度类,然后定义两个描述符类用于描述摄氏度和华氏度两个属性。
要求两个属性会自动进行转换,也就是说可以给摄氏度这个属性赋值,打印华氏度是自动转换后的结果。
代码:
class Celsius:
def __init__(self, value = 26.0):
self.value = float(value)
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
self.value = float(value)
class Fahrenheit:
def __get__(self, instance, owner): #instance就是Temperature(属性:cel, fah)
return instance.cel * 1.8 + 32
def __set__(self, instance, value):
#instance.cel = ('%.1f' % ((float(value) - 32) / 1.8)) #控制精度方法1
instance.cel = round((float(value) - 32) / 1.8, 1) #控制精度方法2
class Temperature:
cel = Celsius() #摄氏度
fah = Fahrenheit() #华氏度, fah在实例对象中被赋值时调用对应类的__set__
运行:
>>> temp = Temperature()
>>> temp.cel
26.0
>>> temp.cel = 30
>>> temp.fah
86.0
>>> temp.fah = 100
>>> temp.cel
37.8
定制序列(容器)
(1) 如果希望定制的容器不可变,只需要定义魔法方法__len__()和__getitem__()
(2) 如果希望定制的容器可变,需要定义__len__()和__getitem__()和__setitem__()和__delitem__()
魔法方法详解:
http://bbs.fishc.com/forum.php?mod=viewthread&tid=48793&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
练习:
编写一个不可改变的自定义列表,要求记录列表中每个元素被访问的次数。
class CountList:
def __init__(self, *args): #*args, 参数数量可变
self.values = [x for x in args]
self.count = {}.fromkeys(range(len(self.values)), 0)
def __len__(self):
return len(self.values)
def __getitem__(self, key):
self.count[key] += 1
return self.values[key]
运行:
>>> c1 = CountList(1, 3, 5, 7, 9)
>>> c2 = CountList(2, 4, 6, 7, 10)
>>> c1[1] #c1[1] == 3被访问1次
3
>>> c2[1]
4
>>> c1[1] + c2[1] #c1[1] == 3被访问2次
7
>>> c1.count
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
>>> c1[1] #c1[1] == 3被访问3次
3
>>> c1.count
{0: 0, 1: 3, 2: 0, 3: 0, 4: 0}
迭代器 iter-next
iter
iter() 内置方法, 功能:返回一个迭代器对象
__iter__() 魔法方法
next
next() 内置方法
__next__() 魔法方法
for循环迭代器:
>>> links = {'百度':'http://www.baidu.com', \
'谷歌':'http://www.google.com', \
'搜狗':'http://www.sougou.com', \
'腾讯':'http://www.qq.com'}
>>> for each in links:
print("%s -> %s" % (each, links[each]))
谷歌 -> http://www.google.com
搜狗 -> http://www.sougou.com
腾讯 -> http://www.qq.com
百度 -> http://www.baidu.com
iter迭代器:
>>> string = 'yuan.jiang'
>>> it = iter(string)
>>> while True:
try:
each = next(it)
except StopIteration:
break;
print(each, end=' ')
运行:
y u a n . j i a n g
斐波那契数列迭代器
>>> class Fibs: #斐波那契数列
def __init__(self, n=10): #加一个参数n控制迭代范围
self.a = 0
self.b = 1
self.n = n
def __iter__(self):
return self #本身就是一个迭代器
def __next__(self):
self.a, self.b = self.b, self.a+self.b
if self.a > self.n:
raise StopIteration
return self.a
>>> fibs = Fibs()
>>> for each in fibs:
print(each, end=' ')
1 1 2 3 5 8
>>> fibs = Fibs(100)
>>> for each in fibs:
print(each, end=' ')
1 1 2 3 5 8 13 21 34 55 89
生成器 yield
(1) 生成器是一种特殊的迭代器,兼容next()内置方法
(2) 生成器模仿了协同程序
协同程序:可以运行的对立函数调用,函数可以暂停或挂起,并再需要的时候从程序离开的地方继续活着重新开始。
举例:
>>> def MyGen():
print('生成器被执行!')
yield 1
yield 2
>>> myg = MyGen()
>>> next(myg)
生成器被执行!
1
>>> next(myg)
2
>>> next(myg)
StopIteration
>>> for i in MyGen(): #for循环自动检测迭代器的StopIteration异常
print(i)
生成器被执行!
1
2
>>> def fibs():
a = 0
b = 1
while True:
a, b = b, a+b
yield a
>>> for each in fibs():
if each > 100:
break
print(each, end=' ')
1 1 2 3 5 8 13 21 34 55 89
列表推导式
>>> a = [i for i in range(100) if not (i % 2) and (i % 3)] #列表推导式
>>> a
[2, 4, 8, 10, 14, 16, 20, 22, 26, 28, 32, 34, 38, 40, 44, 46, 50, 52, 56, 58, 62, 64, 68, 70, 74, 76, 80, 82, 86, 88, 92, 94, 98]
>>> b = {i:i % 2 == 0 for i in range(10)} #字典推导式(例子:小于10以内的偶数)
>>> b
{0: True, 1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False}
>>> c = {i for i in [1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 3, 2, 1]} #集合推导式(元素不重复)
>>> c
{1, 2, 3, 4, 5, 6, 7, 8}
#没有字符串推导式,引号内的强制解释为字符串
>>> e = (i for i in range(10)) #没有元组推导式,()小括号生成的是生成器推导式
>>> e
at 0x00000261E200A7D8>
>>> next(e)
0
>>> next(e)
1
>>> for each in e:
print(each, end=' ')
2 3 4 5 6 7 8 9
>>> sum(i for i in range(100) if i % 2)
2500
生成器扩展阅读:
http://bbs.fishc.com/forum.php?mod=viewthread&tid=56023&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
21丶模块 module
容器 -> 数据的封装
函数 -> 语句的封装
类 -> 方法和属性的封装
模块 -> 程序的封装,其实就是.py的python程序
(1) import导入的.py模块文件必须放在与python.exe同一目录下,即可正确导入。
(2) 导入方法有三种:
① import 模块名
② from 模块名 import 函数名1, 函数名2, ... #不建议这样用,可能会覆盖系统函数
③ import 模块名 as 新名字
举例:
在python下新建test_module文件夹:C:\python\test_module
C:\python\test_module\TempeatureConversion.py
C:\python\test_module\calc.py
#TempeatureConversion.py
def c2f(cel):
fah = cel * 1.8 + 32
return fah
def f2c(fah):
cel = round((fah - 32) / 1.8, 1)
return cel
#calc.py
import TemperatureConversion as tc
print('32摄氏度 = %.1f华氏度' % tc.c2f(32))
print('99华氏度 = %.1f摄氏度' % tc.f2c(99))
运行calc.py:
=================== RESTART: C:\python\test_module\calc.py ===================
32摄氏度 = 89.6华氏度
99华氏度 = 37.2摄氏度
>>>
__name__
if __name__ = '__main__': #决定是.py文件中的代码是当前程序运行,还是导入到其他程序中作为模块使用而运行
作用:限制为自身.py程序运行才执行的代码区域
搜索路径 path
(1) 最佳存放模块的目录:C:\\python\\lib\\site-packages
>>> import sys
>>> sys.path
['', 'C:\\python\\Lib\\idlelib', 'C:\\python\\python35.zip', 'C:\\python\\DLLs', 'C:\\python\\lib', 'C:\\python', 'C:\\python\\lib\\site-packages']
>>> sys.path.append('C:\\python\\test_module') #自定义的模块目录可以append进去
>>> sys.path
['', 'C:\\python\\Lib\\idlelib', 'C:\\python\\python35.zip', 'C:\\python\\DLLs', 'C:\\python\\lib', 'C:\\python', 'C:\\python\\lib\\site-packages', 'C:\\python\\test_module']
>>> import TemperatureConversion as temp
>>> temp.c2f(32)
89.6
包 package
(1) python目录下创建一个文件夹,用于存放相关的模块,文件夹的名字即包(package)的名字
(2) 在文件夹中创建一个 __init__.py 的模块文件,内容可以为空
举例:
C:\python\test_module\calc.py
C:\python\test_module\M1\TemperatureConversion.py #M1文件夹名,即为包名
C:\python\test_module\M1\__init__.py #告诉python运行时将其解释为包
#calc.py中修改为:包名.模块名
import M1.TemperatureConversion as tc
print('32摄氏度 = %.1f华氏度' % tc.c2f(32))
print('99华氏度 = %.1f摄氏度' % tc.f2c(99))
自带电池:python标准库
(1) 电池:python-IDLE 帮助文档 F1
(2) 来自全球开发者贡献的python模块:https://pypi.python.org/pypi
#也可以自己写模块发布上去。
(3) PEP:python增强建议书,规范与定义python各种加强和延伸功能的技术规格,即参考标准
(4) PEP规范内容历史:http://www.python.org/dev/peps
(5) IDLE中模块信息查看:
>>> import timeit
>>> print(timeit.__doc__) #帮助文档
>>> dir(timeit) #内置方法
>>> timeit.__all__ #__all__属性是可供外界调用的类或接口函数
>>> timeit.__file__ #__file__属性是显示模块源代码在本地的位置(学习高手的代码)
>>> help(timeit) #帮助文档
timeit 模块详解
地址:http://bbs.fishc.com/thread-55593-1-1.html
22丶python实例:网络爬虫
python访问网络: urllib (是个包模块)
URL一般格式:
protocol://hostname[:port]/path/[;parameters][?query]#fragment
URL三部分组成:
(1) 协议:http, https, ftp, file, ed2k...
(2) 域名/IP地址:如http默认端口号80
(3) 资源具体地址:如目录或文件名
查看帮助文档后发现urllib包有4个模块:
urllib.request #for opening and reading URLs
urllib.error #containing the exceptions raised by urllib.request
urllib.parse #for parsing URLs
urllib.robotparser #for parsing robots.txt files
尝鲜:
>>> import urllib.request
>>> response = urllib.request.urlopen('http://www.fishc.com')
>>> html = response.read()
>>> print(html)
b'\xef...\r\n