简介
本文主要对运用的python语言知识进行归纳和回顾使用,不定期更新,主要是对语言特性、数据类型、语句块、函数、类、模块、错误、线程、进程等内容的积累
python2/python3
核心类差异
python3对unicode字符原生支持
python2中使用ascil码作为默认编码方式导致string有两种类型str和uniclde
python3只支持unicode的string
python2 python3 表现 转换 作用 str bytes 字节 encode 存储 unicode str 字符 decode 显示 import导入方式
python3采用绝对路径方式import,若需要导入同一目录的文件必须使用绝对路径, 否则只能用相关导入的方式,python2采用的相对路径,容易混淆
类
python3只有新式类没有老式类。新式类申明要求继承object,必须用新式类应用多重继承
缩进
python3使用更加严格的缩进,不被允许tab和space共存,一个tab只能找另外的tab替代,共存报错
TabError:inconsistent use of tabs and space in indentation
废弃类差异
print语句被Python3废弃,统一使用print函数
exec语句被python3废弃,统一使用exec函数
execfile语句被Python3废弃,推荐使用exec(open(“./filename”).read())
不相等操作符”<>”被Python3废弃,统一使用”!=”
long整数类型被Python3废弃,统一使用int
xrange函数被Python3废弃,统一使用range,Python3中range的机制也进行修改并提高了大数据集生成效率
Python3中这些方法再不再返回list对象:dictionary关联的keys()、values()、items(),zip(),map(),filter(),但是可以通过list强行转换:
mydict={"a":1,"b":2,"c":3}
mydict.keys() #<built-in method keys of dict object at 0x000000000040B4C8>
list(mydict.keys()) #['a', 'c', 'b']迭代器iterator的next()函数被Python3废弃,统一使用next(iterator)
raw_input函数被Python3废弃,统一使用input函数
字典变量的has_key函数被Python废弃,统一使用in关键词
file函数被Python3废弃,统一使用open来处理文件,可以通过io.IOBase检查文件类型
apply函数被Python3废弃
异常StandardError 被Python3废弃,统一使用Exception
修改类差异
浮点数除法操作符“/”和“//”的区别
“ / ”
:Python2:若为两个整形数进行运算,结果为整形,但若两个数中有一个为浮点数,则结果为浮点数;
Python3:为真除法,运算结果不再根据参加运算的数的类型。
“//”
:Python2:返回小于除法运算结果的最大整数;从类型上讲,与”/“运算符返回类型逻辑一致。
Python3:和Python2运算结果一样。
异常抛出和捕捉机制区别
Python2
raise IOError, "file error" #抛出异常
except NameError, err: #捕捉异常Python3
raise IOError("file error") #抛出异常
except NameError as err: #捕捉异常for循环中变量值区别
Python2,for循环会修改外部相同名称变量的值
i = 1
print ('comprehension: ', [i for i in range(5)])
print ('after: i =', i ) #i=4Python3,for循环不会修改外部相同名称变量的值
i = 1
print ('comprehension: ', [i for i in range(5)])
print ('after: i =', i ) #i=1round函数返回值区别
Python2,round函数返回float类型值
isinstance(round(15.5),int)
#FalsePython3,round函数返回int类型值
isinstance(round(15.5),float)
#False比较操作符区别
Python2中任意两个对象都可以比较
11 < 'test'
#TruePython3中只有同一数据类型的对象可以比较
11 < 'test'
# TypeError: unorderable types: int() < str()
工具安装问题
windows环境
1.Python2 无法安装mysqlclient。Python3 无法安装MySQL-python、 flup、functools32、Gooey、Pywin32、 webencodings。
2.matplotlib在python3环境中安装报错:
The following required packages can not be built:freetype, png
。需要手动下载安装源码包安装解决。3.scipy在Python3环境中安装报错,
numpy.distutils.system_info.NotFoundError
,需要自己手工下载对应的安装包,依赖numpy,pandas必须严格根据python版本、操作系统、64位与否。4.运行matplotlib后发现基础包numpy+mkl安装失败,需要自己下载,国内暂无下载源
centos环境下
1.Python2无法安装mysql-python和mysqlclient包,报错:
EnvironmentError: mysql_config not found
,解决方案是安装mysql-devel包解决。2.使用matplotlib报错:
no module named _tkinter
,安装Tkinter、tk-devel、tc-devel解决。pywin32也无法在centos环境下安装。
python3内核
提升性能
- 使用多进程,充分利用机器的多核性能
- 对于性能影响较大的部分代码,可以使用C或C++编写
- 对于IO阻塞造成的性能影响,可以使用IO多路复用来解决
- 尽量使用Python的内建函数
- 尽量使用局部变量
内存管理与垃圾回收机制
Python的内存管理机制及调优手段
内存管理机制:引用计数、垃圾回收、内存池
引用计数:
引用计数是一种非常高效的内存管理手段, 当一个 Python 对象被引用时其引用计数增加1, 当其不再被一个变量引用时则计数减 1. 当引用计数等于0时对象被删除。
垃圾回收 :
引用计数
引用计数也是一种垃圾收集机制,而且也是一种最直观,最简单的垃圾收集技术。当 Python 的某个对象的引用计数降为 0 时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了。比如某个新建对象,它被分配给某个引用,对象的引用计数变为 1。如果引用被删除,对象的引用计数为 0,那么该对象就可以被垃圾回收。不过如果出现循环引用的话,引用计数机制就不再起有效的作用了
标记清除
如果两个对象的引用计数都为 1,但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被回收的,也就是说,它们的引用计数虽然表现为非 0,但实际上有效的引用计数为 0。所以先将循环引用摘掉,就会得出这两个对象的有效计数。
分代回收
从前面“标记-清除”这样的垃圾收集机制来看,这种垃圾收集机制所带来的额外操作实际上与系统中总的内存块的数量是相关的,当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾回收带来的额外操作就越少;反之,当需回收的内存块越少时,垃圾检测就将比垃圾回收带来更少的额外操作。
举个例子:
当某些内存块 M 经过了 3 次垃圾收集的清洗之后还存活时,我们就将内存块 M 划到一个集合 A 中去,而新分配的内存都划分到集合 B 中去。当垃圾收集开始工作时,大多数情况都只对集合 B 进行垃圾回收,而对集合 A 进行垃圾回收要隔相当长一段时间后才进行,这就使得垃圾收集机制需要处理的内存少了,效率自然就提高了。在这个过程中,集合 B 中的某些内存块由于存活时间长而会被转移到集合 A 中,当然,集合 A 中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。内存池:
Python 的内存机制呈现金字塔形状,-1,-2 层主要有操作系统进行操作;
第 0 层是 C 中的 malloc,free 等内存分配和释放函数进行操作;
第1 层和第 2 层是内存池,有 Python 的接口函数 PyMem_Malloc 函数实现,当对象小于 256K 时有该层直接分配内存;
第3层是最上层,也就是我们对 Python 对象的直接操作;
Python 在运行期间会大量地执行 malloc 和 free 的操作,频繁地在用户态和核心态之间进行切换,这将严重影响 Python 的执行效率。为了加速Python 的执行效率,Python 引入了一个内存池机制,用于管理对小块内存的申请和释放。Python 内部默认的小块内存与大块内存的分界点定在 256 个字节,当申请的内存小于 256 字节时,PyObject_Malloc会在内存池中申请内存;当申请的内存大于 256 字节时,PyObject_Malloc 的行为将蜕化为 malloc 的行为。当然,通过修改 Python 源代码,我们可以改变这个默认值,从而改变 Python 的默认内存管理行为。
调优手段(了解)
1.手动垃圾回收
2.调高垃圾回收阈值
3.避免循环引用(手动解循环引用和使用弱引用)
内存泄露
指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并
非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了
对该段内存的控制,因而造成了内存的浪费。导致程序运行速度减慢甚至系统崩溃
等严重后果。
有 del() 函数的对象间的循环引用是导致内存泄漏的主凶
不使用一个对象时使用:del object 来删除一个对象的引用计数就可以有效防
止内存泄漏问题。
通过Python 扩展模块 gc 来查看不能回收的对象的详细信息。
可以通过 sys.getrefcount(obj) 来获取对象的引用计数,并根据返回值是否
为 0 来判断是否内存泄漏。
类型和变量
常用内置对象
对象类型 | 类型名称 | 示例 | 简要说明 |
---|---|---|---|
数字 | int、float | 1、3.14 | 数字大小没有限制,内置支持复数及其运算 |
字符串 | str | ‘hello’、”python”、’‘’world’’’、r’abc’、R’bcd’ | 使用单引号、双引号、三引号作为界定符,以字母r和R引导表示原生字符串 |
列表 | list | [1,2,3]、[‘a’,’b’] | 元素可为任意类型 |
字典 | dict | {“aa”:”11”} | 元素形式为:键:值 |
元组 | tuple | (2,-2,1)、(3,) | 不可变的列表,如果只有一个元素,后面的逗号不能省略 |
布尔 | bool | True、False | 逻辑值 |
空类型 | NoneType | None | 空值 |
异常 | ValueError、TypeError… | python内置异常,对应不同类型的异常 |
占位符
type | 说明 |
---|---|
d i u | 十进制整数 |
o | 八进制整数 |
x X | 十六进制整数(x的话数字里字母为小写,X为大写) |
e E | 科学技数法 |
f F | 浮点数(默认保留6位小数) |
g G | 自动选择最优表示法(整数、浮点数、科学技数) |
c | 单个字符或整数转化为字符 |
s | 用str()转化为字符串 |
r | 用repr()转化为字符串 |
a | 用ascii()转化为字符串 |
变量
变量命名
变量中不能有空格以及标点符号 大小写敏感 数字不出现在开头 内置关键字不会出现在其中(查询关键:导入keyword包,print(keyword.kwlist)) 符合常识并有意义
对象
python 中一切皆对象
内存地址(身份id) 类型(type) 值(实际值)
运算符和表达式
运算符说明
运算符 功能说明 + 算数加法,列表、元组、字符串合并与连接,正号 - 算数减法,集合差集,相反数 * 算数乘法,序列重复 / 真除法 // 整除,若其中包含实数,结果也为实数 % 余数,字符串格式化 ** 幂运算 < > <= >= != == 值比较符,集合的包含关系比较 python 运算符与功能
or: 逻辑或
and:逻辑与
not:逻辑非
in:成员测试
is:对象测试,即判断是否为同一对象或内存地址是否相同二进制位运算符:如果为十进制会将其先转化为二进制进行下述运算
| :位或
^ : 位异或
& :位与
<< : 左位移
>> : 右位移
~ :位求反
函数
函数基本定义
- 申明 函数命名规则与变量一样
- 函数需要调用后才会运行,并函数可重复调用
- 函数内部申明的变量在外部无法使用,即函数作用域
- 全局变量:在函数外部定义的变量,可以拿到函数内部使用,只需要在需要使用该变量的函数内部将该变量变为全局变量:global 变量名
- 变量的传递:将需要传递的变量放入函数头()中,传递多个参数时,用, 隔开,在调用函数时需要注意一一对应其变量值,即 参数:可随意改变的值
- 函数返回值:return 返回变量 ,调用函数则会返回return的结果,,其函数中若没有return 会在结尾自动加一个,存在输出语句则也会输出
- 自定义函数/内置函数
- return: 返回的为函数时,会暂停运行并调用相关函数,直到返回值为确定值,则继续运行该函数
- 递归函数:函数调用函数本身
函数相关
1.1 * 2 * 3 * 4 * 5 * 。。。n =
步骤: 1. 停止条件:n = 1
2. 分解条件(规律): 若 n = 5 (确认一个后面的数,往前推)
5 * num_sum(4)
4 * num_sum(3)
3 * num_sum(2)
2 * num_sum(1) --> num_sum(1)==1
5 * 4 * 3 * 2 * 1def num_sum(n):
if n == 1: #添加停止条件
return n
else:
return n * num_sum(n - 1) #递归函数,分解条件
print(num_sum(5))斐波拉契数:1 1 2 3 5 8 …
步骤:
1.停止条件:n = 1或者 n = 2 即 num_qq(1) = 1 num_qq(2) = 1 (即最小元子确认) 2.循环条件:若 n = 5 : bile(n) + bile(n-1) bile(5) / \ bile(4) + bile(3) / \ bile(3)+ bile(2) / \ 1 bile(2)+bile(1) 1 1
def num_qq(n):
if n == 1 or n == 2: #添加停止条件
return 1
else:
return num_qq(n - 1) + num_qq(n - 2)
#递归函数分解条件,反推 或者正推 数值太大会卡顿
汉诺塔
递归函数:解题思路,将n==1的写出来 即将底层的结果写出来,然后
将自己知道的过程或者下一步写出来,将下一步的如2 当成ndef is_equeue(n,start, mid, end):
if n == 1:
print("{} to {}".format(start,end))
#一个的时候移动步骤
else:
is_equeue(n -1,start,end,mid)
#两个时候的移动步骤,当成n 2-1
is_equeue(1,start,mid,end)
is_equeue(n-1,mid,start,end)
is_equeue(3,'a','b','c')二分法查找
def find(i, l):
num = len(l) // 2
if len(l) == 0:
print("0")
elif i > l[num]:
find(i,l[(num + 1): ])
#可以不再判断这个中间值 直接+1
elif i < l[num]:
find(i,l[ :num])
else:
print("1")
find(13,[1,2,3,4,5,6,7,8,9])查找并定位
def find(l,num,start,end):
mid_index = (end + start) // 2
if start > end:
print("列表中不存在%d"%num)
else:
if l[mid_index] > num:
return find(l,num,1,mid_index -1)
elif l[mid_index] < num:
return find(l,num,mid_index + 1,end)
elif l[mid_index] == num:
print("%d 的位置为:%d"%(num,mid_index))
l = [1,2,3,4,5,6,7,8,9,12,23,45]
find_i = len(l)
find(l,3,0,find_i)一等函数,和变量一样,可传递和赋值
def fun1():
print(2112)
a = fun1 #当成变量进行赋值
b = a
b() #此时才是运行函数高阶函数 接受函数作为参数的函数 详见pysort.py
sorted 排序,
fruits=['strawberry','fig','apple','cherry'
,'raspberry','banana']
list2 = sorted(fruits,key=len) #根据len产生的返回值进行排序
print(list2)
def first_num(list1):
return list1[0]
list4 = sorted(fruits,key=first_num)
print(list4)
lamda 无法复用,简单结构可以使用
list5 = sorted(fruits,key=lambda list_1: list_1[0])
print(list5)
语句块
if 判断语句
只接受True/False,只运行判断为真的语句快。
语句快中pass会不执行这一块语句
可以在判断语句中先赋值,再在语句外调用该值
if else:
if elif else: 满足其中一个条件则执行该条件后直接跳出语句块
基础判断举例
该成员是否是会员
is_plus = True #是否是会员 # 基础判断
if is_plus:
print("恭喜你,会员大大 ")
elif not is_plus:
print("垃圾小号")
else:
print("请充钱")
print("用薪创造快乐")折扣计算
buy_sum = float(input("购买后金额为:")) #折扣计算
if buy_sum < 0:
print("非法操作")
else:
if buy_sum > 400:
buy_sum = buy_sum * 0.85
else:
buy_sum = buy_sum * 0.95
print("实际支付金额:%.2f" % buy_sum)分数等级判断
score = float(input("分数: ")) #输入分数并判断其等级
if score > 100 or score < 0:
print("无法判断")
elif score >= 90:
print("等级为: A")
else:
print("等级为: F")
循环语句
while:
若判断条件为真,循环运行其中的语句块,若为假,运行语句块外语句 注意:每次循环都会执行一次while进行判断
break:停止循环
continu:结束本次循环继续下一次循环
while循环举例
- 成绩录入
num = 1
score = 0
while True:
n = input("请输入第{}科成绩: ".format(num))
n = int(n)
if n > 100 or n < 0:
n = input("输入错误,请重新输入第{0}科成绩".format(num)) #print("输入错误,请重新输入") continue
n = int(n) #使用continu可以结束本次循环
score = score + n
if num >=5:
print("总成绩为:{0},平均成绩为:{1}".format(score,
score/num))
break
num += 1
九九乘法表
利用while循环进行,声明变量需要清晰表达所表达的内容
倒九九乘法表
i = 1
while i <= 9:
j = 9
xx =""
while j >= i:
xx += ("{0:d} * {1:d} = {2:2d} | ".format(i,j,i * j))
j -= 1
print(xx)
i += 1图形数字输出
在做类似多个循环嵌套时,可以将循环拆分开一步一步分拆成单个变量循环,最后嵌套在一起。对于本题,整个:先输出空格,再输出数字
1
2 3
4 5 6
7 8 9 0space_num = n - 1
i = 1
n = 4
while space_num >= 0:
string = (" "*space_num)
j = 0
while (n - space_num) > j:
string += str(i % 10) + " "
i += 1
j += 1
print(string)
space_num -= 1
lines = 6
start_num = 6
j = lines
while j > 0:
space_num = lines - start_num
print(" " * space_num + "*" * start_num)
start_num -= 1
j -= 1
n = 7
mid = n // 2 + 1 #中间那一排
i = 1
while n > 0:
space_num = abs(mid-i) #3
base_num = mid-space_num #1
star_num = base_num*2-1
print(' '*space_num + "*"*star_num)
i += 1
n -= 1
*****
***
*
***
*****
n = 5 # 中间一行的行数
a = n #3
j = 2 * n + 1 #7 一共7行
while j > 0: #循环7次
space_num = n - abs(a) # 初始化
j -= 1 #j控制循环
line_num = abs(2 * a) + 1 # * 数
a -= 1 # a递减 3 2 1 0 -1 -2 -3
print(" "* (space_num) + "*" *line_num )
def is_peime(num):
#判断是否为质数
i = 2
flag = True
while num > i:
#循环条件
if not num % i:
#质数判断,若为真(不是质数)则执行判断语句
flag = False
break
#符合该条件则直接跳出循环
i += 1
return flag
num1 = int(input("请输入一个大于1的整数: "))
#输出所有符合条件的质数
while num1 > 0:
if is_peime(num1):
#调用质数函数
print(num1)
num1 -= 1
# 1、从键盘输入10个数,求出最大数
num = 1
max_num = int(input("请依次输入第{}个数:".format(num)))
#初始化最大值,防止输入的数为负数,若比较大小都需要初始化比较值。
while num < 10:
num += 1
num1 = int(input("请依次输入第{}个数:".format(num)))
if num1 > max_num:
#若max_num=0,出现负数比较则直接会使max_num=0
max_num = num1
print(max_num)
数据结构
列表
数据结构:组织并存取数据
list:有序的集合,列表 ,是一种数据结构
申明方式
list1 = ['a',2,3,[1,2,3,4,[1,2,3]],'abcde']
将字符串转化为列表
list2 = list("a,b")
print(list2)
下标取值,下标取首不取尾,与数组相似取值方式
print(list1[3][4][1])
print(list1[0:3])
最后一个元素取法
print(list1[-1])
print(list1[len(list1)-1])
#列表不能为空使用的len语句是计算的该列表中有多少个元素
print(len(list1[3]))
元素更改
print(list1[1])
list1[1] = "b"
#元素修改
print(list1[1])
list1.append('f')
#尾部增加元素 其内置函数中没有return 所以print(list1.append())
返回值为none
list1.insert(1,'b')
#在下标1处添加元素 返回值为none
print(list1.insert(1,'3'))
x = list1.pop(1)
#删除下标所在位置的元素,若无下标,则将尾部元素删除,返回值为删除的元素
list1.remove('a')
#找到该元素并移除 返回为none
range(start_num,end_num,间隔):有序的一组数字list2 = [1,'hello', 'world','c','d',[1,2,3,[1,2],5]]
#打印输出列表所有元素
for i in list2:
#for循环会将列表中存在的字符串也分开打印,例如'asd',for后为'a','s','d'
if not type(i) == list:
#判断类别
print(i)
else:
for j in i:
print(j)
def for_list(list1):
#使用函数打印所有列表中的元素
for i in list1:
if type(i) == list:
for_list(i)
else:
print(i)
for_list([1,2,3,[1,2,[1,2,[12,34,['aasas','asadadf']]]]])列表切分
list3 = [1,2,3,4,5]
print(list3[1:3])
#切分1-2下标元素 长度为下标差容器序列(容器)和编排序列(真正的数据)
list1 --> 容器(列表,元祖等) [1,2,3,4,5],[True,False] --> 编排序列
传统生成方式
list1 = []
for i in range(10):
list1.append(i)
列表生成式:将一个编排序列放入列表中
list1 = [i for i in range(10)]
#性能更高
list2 = [i for i in 'asdfghjk']
print(list1)
print(list2)
list3 = [(i, j) for i in list1 for j in list2]
#注意:(i,j)
print(list3)
l1 = ['spades', 'diamonda','clubs','hearts']
l2 = ['A',2,3,4,5,6,7,8,9,'j','q','k',10]
list4 = [((i,j)) for i in l2 for j in l1]
#注意循环次序
i = 0
l2 = list()
while i < (len(list4)):
if "k" in list4[i]:
l2 += list4[i:i+1]
i += 1
print(l2)切片 取左不取右 前闭后开
list1= [i for i in range(1,11,1)]
print(list1)
xx = list1[2:4] #2,3 便于计算切片的数量:4-2
yy = list1[1:] #list1[1:len(list1)]
zz = list1[:3] #不包括3之前的
print(xx)
l1 = list1[-1]
l2 = list1[-1:]
print(l1)
print(l2) #两者区分,一个取值一个切片仍是列表
# print(id(list1))
# print(id(list1[2:5]))
# print(id(list1[3:4]))
# print(id(xx))
# print(id(yy))引用规则:python中变量是引用而不是赋值
a = [1,2,3]
b = a
#直接将a的地址给了b,未重新开空间 对两个变量进行操作时,都是对同
一个地址中存储的数据操作
a.append(4)
print(a)
print(id(a))
print(b)
print(id(b))Python函数调用的时候参数的传递方式是值传递还是引用传递
Python的参数传递有:位置参数、默认参数、可变参数、关键字参数。
函数的传值到底是值传递还是引用传递,要分情况:
不可变参数用值传递:
像整数和字符串这样的不可变对象,是通过拷贝进行传递的,因为你无论如何都不可能在原处改变不可变对象
可变参数是引用传递的:
比如像列表,字典这样的对象是通过引用传递、和C语言里面的用指针传递数组很相似,可变对象能在函数内部改变。
对缺省参数的理解
缺省参数指在调用函数的时候没有传入参数的情况下,调用默认的参数,在调用函数的同时赋值时,所传入的参数会替代默认参数。
*args
是不定长参数,他可以表示输入参数是不确定的,可以是任意多个。**kwargs
是关键字参数,赋值的时候是以键 = 值的方式,参数是可以任意多对在定义函数的时候不确定会有多少参数会传入时,就可以使用两个参数。为什么函数名字可以当做参数用
Python中一切皆对象,函数名是函数在内存中的空间,也是一个对象。
字典: 键值对 key - value
申明
dict1 = {'a':1,'b':2,'c':3} #其中的每一个键值对都与下标无关,即与位置无关
dict2 = {'b':2,'a':1,'c':3}
print(dict1)
print(dict1['a'])dict内置方法
dict3 = {'b':2,'a':1,'c':3,'d':dict1}
print(dict3.keys()) #打印所有的键
print(list(dict3.keys()))
print(list(dict3.values())) #打印所有的值
print(list(dict3.items())) #打印所有的键和值
print(dict3.get('a','aa'))
#判断其是否存在该键值,有则返回对应的值,(键,值)
print(dict3.setdefault('hello','w'))
#不存在该键值则更新字典,将其加入
print(dict3)
dict4 = {'f':134}
dict4.update(dict2) #把dict2中的键值对更新到dict4中
print(dict4)
dict1.pop('a') #将dict1中的键'a'对应的键值对删除
print(dict1)
del dict1['b'] #删除该键值对
print(dict1)
dict11 = dict.fromkeys(dict1)
#新建一个与dict1有相同键的字典,其值为none
print(dict11)
#键值对添加修改
dict2['world'] = 'e' #无则添加该键值
print(dict2)
dict2['c'] = 'f' #有则修改该键对应的值
print(dict2)优化斐波拉契
dict1 = {}
def fib(n):
if n == 1 or n == 2:
return 1
else:
if dict1.get(n-1,''):
x1 = dict1.get(n-1)
else:
x1 = fib(n-1)
dict1[n-1] = x1
if dict1.get(n-2,''):
x2 = dict1.get(n-2)
else:
x2 = fib(n-2)
dict1[n-2] = x2
return x1 + x2
print(fib(5))
元祖tuple 不可修改的列表
可拆包
不可变 (针对某些元素)
用于轻量级数据中
tup1 = ('asdf','s')
tup4 = ('d',) #但元素加,
tup2,tup3 = ('aa','bb') #可以拆包
print(tup3)
print(tup2)
tuple取值:
1,下标取值
2。拆包
d = {'a':1,'b':2,'c':3}
for tup1,tup2 in d.items(): #若不需要tup1则可以写成 _ , tup2
print(tup2)
for _,v in d.items():
print(v)
l2 = [(k,v) for k,v in d.items()] #变成列表
set:集合
元素不重合
可做集合运算 &(交集) |(并集) -(差集)
s = set('2235462346')
s1 = ({1,2,3,3,4,5,2,3,4})
#自动去掉重复的元素,不能嵌套list,dict.
#里面的元素必须是可hash的
print(s)
print(s1)
list1 = [1,2,3,4,5,2,3,4,2,2]
浅复制
a = [1,2,3,4,5]
b = a[:]
#此时b重新指向另一个地址 但如果其中内嵌容器,则只会对数值改变,
容器仍指向原地址
l1 = [1,[22,33],(11,22,[33,44])]
l2 = list(l1)
#新的列表创建。但内嵌列表和元祖的指向地址未改变
l3 = l1[:]
#新列表创建,内嵌容器仍指向原地址
print(l1 == l2)
print(l1 is l2)
l1[1].append(1111111)
l1[2][2].append(2333)
#改变的为元祖中的内嵌列表,其仍可进行添加
l1[0] = 9
#改变的是列表中的数值,其L1发生改变,对L2和L3无影响
print(l1)
print(l2)
print(l3)
l1 = [2,[44,55],(44,55,[3,1])]
l2 = list(l1)
l1.append(100)
l1[1].remove(44)
l2[1] += [11,22]
l2[2] += (2,3)
#生成新的tuple但其内嵌的列表地址未改变,相当于浅复制
面向对象
面向对象:先有类(抽象)才有对象(具体)
class:
可继承 class Mylist(list): 括号里为其它的对象等 :可多继承,层层继承,本次继承拥有被继承以及上面所有继承父类的init时,需要使用supper().init()
可重写:可以在继承的类中重写其中的方法或功能(多态)
可扩展:继承中可以增加新的方法或功能
import random
#类的申明方式
class Car: #在这个下面可以有无数函数 命名:首字母必须大写
def __init__(self):
#面向对象中的所有东西可共享(通过self挂载,再通过self调用,只用于类)
init中为确定的功能
self.coloer = 'red'
self.ppai = 'jili'
self.kuandu = 1900
print('对象初始化')
self.x = random.randint(0,100)
def test(self):
print(self.coloer)
self.laba()
return self.ppai
def laba(self):
self.changd = 8000
def de_self(self):
print(self.x) #挂载在self上,每次调用地址不同
print(id(self.x))
xx = random.randint(0,100)
#依附于class上,相当于函数变量,每次调用地址相同
print(xx)
print(id(xx))
def de1_self(self):
self.de_self()
# car1 = Car()
类的实例化(对象) 会直接调用类中的__init__(初始化)函数
(魔法函数都以__名称__为命名格式)初始化
# car2 = Car()
可实例化多次
# # print(car1.test())
调用功能函数
# # print(car1.coloer)
调用self的属性
# car1.laba()
属于类里除__init__函数之外的self需要先运行其类中对应的函数,
才能挂载在self上,对象才能继续调用
# print(car1.changdu)
self
self:相当于挂载器,可以将类中的各个属性通过其挂载,再使用,属于对象,可以在类中互相传递,每个self都有一个独立的空间
car1 = Car()
car1.de_self()
car1.de1_self()
# import random
# class Student:
# def __init__(self):
# self.cla_num = random.randint(1,5)
# self.cla_stunum = random.randint(1,50)
#
#
# def cla_girls(self):
# stunum = self.cla_stunum
# self.girls = random.randint(1,stunum)
# print("女生人数:%d"%self.girls)
#
# def cla_boysnum(self):
# cla_boyssnum = self.cla_stunum - self.girls
# print("男生人数:%d"%cla_boyssnum)
# student1 = Student
# student1.cla_girls()
# student1.cla_boysnum()
私有属性
class Room:
def __init__(self,name_num): #初始化时,可以加入参数
self.__password = 111 #在前面+__后 该属性变成私有,只能在内部调用
self.__card = 111111
self.n = name_num
def card_get(self): #可以通过函数传出,但可以修改成其它值
return self.__card / 2
def get_password(self):
return '12365'
xx = Room('aaaa') #参数值传入并初始化
print(xx.card_get())
print(xx.get_password())
#每一个类中都存在默认函数:如__str__(魔法函数,会自动调用)
内置函数调用装饰器
class Person:
def __init__(self,name,age,id):
self.__age = age
#私有属性:进行运行时无法查看(被保护),可隐藏真实数据
self.__name = name
self.id = id
def age(self):
return self.__age//2
def set_age(self,age):
#判断输入的参数是否符合规则,符合就修改该参数
if age < 50:
self.__age = age
else:
self.__age = 50
return self.__age
# 可以直接使用函数名调用的内置装饰器
def name(self):
return self.__name
def id_c(self):
print(self.id)
p = Person('xxx',50,12)
print(p.age()) #只能通过函数调用该属性,并且函数能改原数据
print(p.name) #不需要加()即可调用该函数
p.id = 14 #可修改类中的参数。
p.id_c()
p.set_age(30) #判断参数规则并修改该参数
print(p.age())
slots
class DataBaset:
#在设置属性时会直接调用,控制其对象只能存在的属性
__slots__ = ('__password','__database_name','__name')
def __init__(self):
self.__name = ''
self.__password = ''
self.__database_name = ''
def name(self):
return self.__name
#将函数变成属性 若有相关联的setting则需要对setting中的语句再执行该变量
def password(self):
return "{}".format('*' * len(self.__password))
def set_name(self,name):
iswasp = True
while iswasp == True:
if type(len(name)) == str:
print("非字符串")
iswasp = False
elif len(name) < 6:
print('账户名错误')
iswasp = False
elif 48 <= ord(name[0])<= 57:
print("首字母为数字")
iswasp = False
else:
self.__name = name
break
#在变成属性的函数赋值时会调用此setting函数
def password(self,password):
if type(password) != str:
print('错误')
return
if len(password) < 8:
print('长度不够')
return
self.__password = password
mysql = DataBaset()
注意点
mysql.name = 'aaaaaa'
#未修改类中的任何,只是单纯定义(直接在类中设置控制函数就可)
在使用property后 如果需要直接使用赋值语法修改被保护的,可在相关判断条件下使用
@判断名(需要与函数名一样).setter
mysql.password = 'aaa'
print(mysql.password)
错误类
异常类 :报告错误 –> 中断 运行
#只会监听特殊类型的错误
try:
xx = [qxaas]
#监听与 NameError 相关的错误,监听所有报错只需要监听其父类(Exception)即可
except NameError:
print('cuo wu')
# class TestError(Exception): #exception属于报错的父类,继承即可
自定义报错
class TestError(Exception): #自定义一个报错
pass
def rujiao(age):
if age < 30:
print(age)
else:
raise TestError('xiajibaluanxie')
#报错目标 :中止程序,并输出错误提示
# try:
#出现报错并继续运行后面的代码
# rujiao(333)
# except TestError:
# print("xxx")
#若输入pass 则会直接跳过并不会报错
#
# print('xxxxxxxxxx')
l = [1,2,3,4]
try:
#出现报错并继续运行后面的代码
l[7]
#出现错误则直接报错,不会执行下面的语句快
rujiao(60)
#打印错误提示 (as后接错误提示) 可以重复抓取不同的错误,显示抓取的只有一种
except TestError as errortype:
print(errortype)
except IndexError:
print("下标错误")
except AttributeError:
print('无法赋值')
else:
#上述若未发现错误,就执行else中语句
print('++++++++')
finally:
#若上述未出现错误或中断:至少会执行该命令
print('-------')
print('xxxxxxxxxx')
模块
模块的引用与创建
test1.py
小技巧,程序自动识别当前执行的python文件名 __file__
def a_test():
return 'a.py'
def test(): #return 为空 调用会多一个返回值空,以及执行该函数打印出aaaa
print("aaaaa")
if __name__ == "__main__": #该命令下的不会被引用执行
print("不可被引用的命令test1")
print('可以被调用的test1')
test2.py
from module.test1 import a_test,test #引用来自module包下test1.py中的a_test函数,
module包必须含有_init_.py文件
def b_test():
return 'b.py'
print(a_test()) #输出test1中的a_test函数运行结果
print(test())
test3.py
import module.test1 #引用目标文件名 -- 会先执行import下的文件
import module.a_test
print(module.test1.a_test()) #直接调用该文件下的为a_test的函数,并打印输出
若有其它文件调用该文件下函数,会执行该文件下的命令,解决方案见test1.py
print(module.test1.test()) #会先执行module下test1中的所有,
再执行函数test若无return会返回空
print(module.a_test.get_path()) #调用的执行目标文件所在路径,
而不是该命令所在文件的路径
引用内置库
import os #引进os模块,详见a_test.py
import time
time.sleep(2) #程序暂停2秒
time.time()#时间戳
datetime.time() #运行时间
import random
random.randint(0,10) #伪随机
random.random() #随机浮点数
引用第三方库
安装外部库:pycharm -- preferences -- project interpreter -- + -- '选择库' -- install
相当于执行了:pip3 install requests(浏览网页)
import requests
r = requests.get('https://www.baidu.com')
print(r.text)
建立自己的库
在需要的文件夹下建立一个init.py文件,或者系统自动生成,该文件夹会成为一个库
from module import test1
test1.test()
文件读取
r w a -->读 写(会覆盖文件中的内容) 追加写(末尾添加)读写文件性能会很低,
因为文件存在磁盘,需要转到CPU运行
w = open('open.txt','r') #每次都只能操作一个方法
w.write('测试写')
w.close() #文件操作后需要关闭,文件描述符有关
r.readlines():一行一行读
r = open('open.txt','r') #读取文档中所有内容(字节读取)
read_txt = ''
while True:
x = r.read(1) #一个字节一个字节读取
if len(x) == 0:
break
read_txt += x
r.close()
print(read_txt)
r = open('open.txt','r') #读取文档中的所有内容(行读取)
read_txt = ''
while True:
x = r.readlines()
if len(x) == 0:
break
print(x)
r.close()
#无需关闭文件的方法:
with open('open.txt','r') as r: #在其中的文件操作代码运行后会自动关掉
read_txt = ''
while True:
x = r.readlines()
if len(x) == 0:
break
print(x)
os/shtuil模块常用命令
os模块
path函数os模块中的
abspath
:找出当前运行函数的绝对路径os.mkdir
:不能递归创建目录os.path.join
:相当于”+/“,如果是windos则是”+“os.makedirs
: 可递归创建文件os.path.abspath
:显示同层文件的绝对路径os.path.dirname
:显示同层文件上层目录os.rmdir
:删除空文件shutil模块
shutil rmtree
:强制删除文件shutil move
:移动文件shutil copy
:shutil copytree
:
文件路径的查找
import os
import shutil #更高级一点的库
def get_path():
xx = os.path.abspath(__file__) #__file__相当于当前所在文件名
return xx一直找上层路径直到项目路径
c_path = os.path.abspath(__file__)
module_path = os.path.dirname(c_path)
pycode_path = os.path.dirname(module_path)
print(os.path.dirname(pycode_path))
相当于下面代码
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
print(BASE_DIR)
os.mkdir(BASE_DIR+'/b_test')创建或删除文件/文件夹
xx = os.path.join(BASE_DIR,'text1','text2')
#在BASE_DIR的路径下创建text1并在该文件下再创建text2
os.mkdir(xx) #不能递归创建
os.makedirs(xx) #可递归创建文件
os.makedirs(xx,exist_ok=True)
#若有该文件名存在则不会再报错
os.rmdir(os.path.join(BASE_DIR,'b_test'))
#只能删除空目录
shutil.rmtree(os.path.join(BASE_DIR,'text1'))
#使用shutil库函数删除文件夹(包括非空文件夹)文件/文件夹的移动,以及文件夹遍历
将位于BASE_PATH路径下的a_text移动到b_text下
os.mkdir(os.path.join(BASE_DIR,'a_text'))
os.mkdir(os.path.join(BASE_DIR,'b_text'))
shutil.move(os.path.join(BASE_DIR,'a_text'),
os.path.join(BASE_DIR,'b_text'))
拷贝文件到一个新文件中 操作的是文件
shutil.copy('test1.py','test4.py')
拷贝文件夹到新文件夹中,操作的是文件夹
shutil.copytree(os.path.join(BASE_DIR,'module'),
os.path.join(BASE_DIR,'module2'))
遍历文件夹
yy = os.listdir(BASE_DIR+'/module')
print(yy)遍历文件夹
深度遍历文件夹
import os
import shutil
def deep_first(dir):
dir_lists = os.listdir(dir)
if len(dir_lists) == 0:
return
for d in dir_lists:
print(d)
deep_first(os.path.join(dir,d))
deep_first('test')广度遍历文件夹
import os
import shutil
def brand_first(dir):
buckets = []
buckets.append(dir)
while len(buckets) > 0:
tmp = buckets.pop(0)
print(tmp)
files = os.listdir(tmp) #listdir中容易乱序,需要排序
files.sort()
for i in files:
buckets.append(os.path.join(tmp,i))
brand_first('test')