首页 > Python基础教程 >
-
python基础总结(3)
生成器
生成器:python社区把生成器与迭代器看成同一种,生成器的本质就是迭代器。唯一的区别是:生成器是我们自己用python代码构建的数据结构,迭代器都是python提供的,或者转化的。
获取生成器的方法:
- 生成器函数
- 生成器表达式
- python内部提供的。
生成器函数获取生成器,yield:
def func():
print(1)
print(3)
yield 5
print(func) #<function func at 0x000001A3CCA04438> 仍然是一个函数
ret = func()
print(ret) #<generator object func at 0x000002471A631D48>
#generator object#生成器对象
#一个next对一个yield的返回值,如果再次调用yield就会接着上次的next.
def func():
for i in range(1000000):
yield i
ret = func()
for i in range(5):
print(next(ret))
for i in range(10):
print(next(ret))
#0, 2,3,4,5,6,7,8,9,10,11,12,13,14
yield与return
return:一个函数中只能存在一个return结束函数的调用,并且给函数的执行者返回值。
yield:只要函数中有yield那么它就是生成器函数,生成器函数中可以存在多个yield,一个next对一个yield的返回值,yield不会结束函数的调用,但return会结束函数的调用。
yield from(3.4版本以后),将数据变成一个迭代器返回,生成器函数可以直接用for循环
def func():
l1 = [1,2,3]
yield from l1 #将这个列表变成了一个迭代器返回
for i in func():
print(i) #1 2 3
生成器表达式,生成器表达式:与列表推导式的写法几乎一样,生成器也有循环模式和筛选模式,只是将[]变为()。但比列表推导式更节省空间。
l1 = (i for i in range(10))
print(l1)
#<generator object <genexpr> at 0x000001BB028F8CC8>
print(next(l1)) #0
for i in l1: #可直接用for循环,因为for循环本身就是将可迭代对象变为迭代器再循环。
print(i)
list可以将生成器中的所有元素添加到列表中
def func(*args):
for i in args:
for j in i:
yield i
print(list(func('asdf',(1,2,3))))
#简化上述函数:
def func(*args):
for i in args:
yield from i #优化了内层循环,提高了运行效率。
递归函数
递归报错:RecursionError
官方文档递归最大深度为1000层,为了节省内存空间,不让用户无限开辟内存空间。但实际上不是1000层。
递归的实现效率比不用递归的实现效率低。
count = 0
def func():
global count
count += 1
print(count)
func()
print('***') #不会被执行。
func()
循环和递归的关系:递归比循环更消耗内存。
递归的最大深度可以自己设置:
import sys
sys.setrecursionlimit(100000)
count = 0
def func():
global count
count += 1
print(count)
func()
func()
但并不会无限制按照设置的参数的开辟内存空间,达到一定限度后会自行停止,而这个限度与电脑有关。
设置条件,让递归函数停下来。
def main(n):
print('进入第%d层梦境'%n)
if n == 3:
print('到达潜意识区,原来我最爱的人是你!开始醒来')
else:
main(n+1)
print('从第%d层梦境醒来'%n)
main(1)
并不是函数中有return
,return
的结果就一定能够在调用函数的外层接受到
def func(count):
count+=1
if count == 5:return 5
func(count)
print(func(1)) #None
def func(count):
count+=1
if count == 5:return 5
return func(count) #调用后用return
print(func(1))
递:一直往深处走,归:从深处返回。
例题:
1.计算阶乘。
def func(n):
return n*func(n-1) if n>1 else 1
print(func())
2.os模块,查看一个文件夹下的所有文件,不能用walk。
import os
def show_file(path):
name_list = os.listdir(path)
print(name_list)
for name in name_list:
abs_path = os.path.join(path,name)
if os.path.isfile(abs_path):
print(abs_path)
elif os.path.isdir(abs_path):
show_file(abs_path)
show_file('D:\WorkSpace\Python')
3.os模块,计算一个文件加下所有文件的大小。
import os
def dir_size(path):
size = 0
name_lst = os.listdir(path)
for name in name_lst:
abs_path = os.path.join(path, name)
if os.path.isdir(abs_path):
ret = dir_size(abs_path)
size += ret
elif os.path.isfile(abs_path):
size+=os.path.getsize(abs_path)
return size
print(dir_size('D:\WorkSpace\Python')/(1024*1024))
3.计算斐波那契数列,找第100个数。
def func(n):
x = n-1
return func(n-1) +func(n-2) if x>1 else 1
print(func(100)) #非常浪费时间,在递归时尽量避免多次调用函数。
def fib(n,a=1,b=1):
if n-1<1:
return b
else:
a,b=b,a+b
return fib(n-1,a,b)
print(fib(100))
#采用while循环
def fib(n):
a,b = 1,1
while n>2:
a,b = b,a+b
n -= 1
return b
print(fib(100))
#采用生成器:
def fib():
a = 1
yield a
b = 1
yield b
while True:
a,b = b,a+b
yield b
import time
for i in fib():
print(i)
time.sleep(0.01)
4.三级菜单。
menu = {
'北京': {
'海淀': {
'五道口': {
'soho': {},
'网易': {},
'google': {}
},
'中关村': {
'爱奇艺': {},
'汽车之家': {},
'youku': {},
},
'上地': {
'百度': {},
},
},
'昌平': {
'沙河': {
'北航': {},
},
'天通苑': {},
'回龙观': {},
},
'朝阳': {},
'东城': {},
},
'上海': {
'闵行': {
"人民广场": {
'炸鸡店': {}
}
},
'闸北': {
'火车战': {
'携程': {}
}
},
'浦东': {},
},
'山东': {},
}
def threeLM(dic):
while True:
for k in dic:print(k)
key = input('input>>').strip()
if key == 'b' or key == 'q':return key
elif key in dic.keys() and dic[key]:
ret = threeLM(dic[key])
if ret == 'q': return 'q'
threeLM(menu)
内置函数
python提供了68个内置函数:abs() enumerate() filter() max() min() open() range() print() len() list() dict() str() float() reversed() set() sum() tuple() type() zip() dir() classmethod() delattr() getattr() issubclass() isinstance() object() property() setattr() staticmethod() super() all() any() bytes() callable() chr() complex() divmod() eval() exec() format() frozenset() globals() hash() help() id() input() int() locals() next() oct() ord() pow() repr() round()
eval():剥去字符串的外衣(引号),运算里面的代码,有返回值。工作时最好不用,容易中病毒。
s1 = '1+1'
print(s1) #1+1
print(eval(s1),type(eval(s1))) #2 <class 'int'>
exec():与eval()几乎一样,但是它是处理代码流的。工作时最好不用,容易中病毒。
msg = """
for i in range(5):
print(i)"""
exec(msg) #0,1,2,3,4
hash:获取一个对象(可哈希对象:int,str,bool,tuple)的哈希值。哈希值:加密算法之间需要哈希值,与哈希算法有关。
print(hash('12'))
help():打印/获取一个对象的使用方法。
print(help(str))
print(help(str.upper))
callable():判断一个对象是否可调用,真为True,假为False。
l1 = [1,2]
def func():
pass
print(callable(l1)) #False
print(callable(func)) #True
int():将字符串类型转换为int类型;取整(舍尾法)
float():将int和str转换为float。
list():将一个可迭代对象转换成列表
tuple():将一个可迭代对象转换成元组
dict():通过相应的方式创建字典。
abs():返回绝对值
sum():求和
reversed():将一个序列翻转,返回翻转序列的迭代器。可用于字符串。与列表的方法l1 .reverse()
区分.
complex:创建一个值为real+imag*j的复数;转换一个str或int为复数,如果第一个参数为str则不需要传递第二个参数。(复数:complex)
print(complex('1')) #(1+0j)
bin:将十进制数转换为二进制字符串并返回。
oct:将十进制数转换为八进制字符串并返回。
hex:将十进制数转换为十六进制字符串并返回。
divmod:计算除数与被除数的结果,返回一个包含商和余数的元祖(a//b,a%b)
round:保留浮点数的位数,默认保留整数。
pow:求x**y的次幂,并可以对所求结果对第三个参数取余
print(pow(2,2)) #2**2 4
print(pow(2,2,3)) #(2**2)%3 1
bytes:用于不同编码之间的转换。
s1 = '你好'
bs1 = s1.encode('utf-8')
print(bs1)
#b'\xe4\xbd\xa0\xe5\xa5\xbd'
s2 = bs1.decode('utf-8')
print(s1)
#你好
s3 = '你好'
bs2 = bytes(s3,encoding='utf-8')
print(bs2)
#b'\xe4\xbd\xa0\xe5\xa5\xbd'
bs3 = str(bs2,encoding='utf-8')
print(bs3)
#你好
ord():输入字符找该字符编码的位置。(如果在ASCII码中就用ASCII码,否则用Unicode)
chr():输入位置数字找出其对应的字符。(如果在ASCII码中就用ASCII码,否则用Unicode)
repr():返回一个对象的string形式。(str带有引号的形式),在格式化输出时常用(%r)。
s1 = 'python'
print('i love %r'%(s1)) #i love 'python'
print():源码分析:print(self, *args, sep=' ', end='\n', file=None,flush=False):
file: 默认是输出到屏幕,如果设置为文件句柄,输出到文件
sep: 打印多个值之间的分隔符,默认为空格
end: 每一次打印的结尾,默认为换行符
flush: 立即把内容输出到流文件,不作缓存
print(1,2,3) #1 2 3
print(1,2,3,sep='@') # 1@2@3
print(1,2,3,end='') #不换行
all():可迭代对象中,全为True才是True。
any():可迭代对象中,有一True即为True。
zip(): 拉链方法;函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元祖组成的内容,如果各个迭代器的元素个数不一致,则按照长度最短的返回。
lst1 = [1,2,3]
lst2 = ['a','b','c','d']
lst3 = (11,12,13,14,15)
for i in zip(lst1,lst2,lst3):
print(i)
#(1, 'a', 11) (2, 'b', 12) (3, 'c', 13)
min():求最小值,可以与函数结合(key:自动将可迭代对象中的每个元素按照顺序传入key对应的函数中,然后以返回值比较大小,key=一定是函数名,不能加(),。min/max默认会按照字典的键去比较大小,但可以自己规定。
#以绝对值的方式取最小值
l1 = [1,2,-1,-5,3]
def func(s):
return abs(s)
print(min(l1,key=func)) #1
#也可以直接使用匿名函数:
print(min(l1,key=lambda s:abs(s))) #1
dic = {'a':3,'b':2,'c':1}
min(dic) #a 默认以键排序,返回键
#以值比较:
print(min(dic,key=lambda s:dic[s])) #c 以值排序,返回键(返回的是循环的元素,而不是经函数转换后比较的值。
max():求最大值,可以与函数结合,同min()。
sorted():排序函数;语法: sorted(iterable,key=None,reverse=False)。key: 排序规则(排序函数),返回列表。在sorted内部会将可迭代对象中的每一个元素传递给这个函数的参数.根据函数运算的结果进行排序reverse: 是否是倒叙,True:倒叙;False:正序
lst = [1,3,2,5,4]
lst2 = sorted(lst)
print(lst) # 原列表不会改变
print(lst2) # 返回的新列表是经过排序的
lst3 = sorted(lst,reverse=True)
print(lst3) # 倒叙
#字典使用sorted排序
dic = {1: 'a',3: 'c',2: 'b'}
print(sorted(dic)) #[1,2,3] 字典排序返回的就是排序后的key
#和函数组合使用
# 定义一个列表,然后根据一元素的长度排序
lst = ['1','111','11','1111']
# 计算字符串的长度
def func(s):
return len(s)
print(sorted(lst,key=func)) #['1','11','111','1111']
lst = [{'id': 1,'name': 'a','age': 18},
{'id': 2,'name': 'b','age': 17},
{'id': 3,'name': '3','age': 16},]
# 按照年龄对学生信息进行排序
print(sorted(lst,key=lambda e: e['age']))
filter():筛选过滤,返回一个迭代器(可与列表推导式的筛选模式进行对比);语法: filter(function,iterable),function: 用来筛选的函数,在filter中会自动的把iterable中的元素传递给function,然后根据function返回的True或者False来判断是否保留此项数据
lst = [{'id':1,'name':'a','age':18},
{'id':2,'name':'b','age':17},
{'id':3,'name':'c','age':16},]
ls = filter(lambda e:e['age'] > 16,lst)
print(list(ls))
#[{'id': 1, 'name': 'alex', 'age': 18},{'id': 1, 'name': 'wusir', 'age': 17}]
map():映射函数,返回一个迭代器(可与列表推导式的循环模式对比);语法: map(function,iterable) 可以对可迭代对象中的每一个元素进映射,分别取执行function。
#例1;计算列表中每个元素的平方,返回新列表
lst = [1,2,3,4,5]
print(map(lambda s:s*s,lst)) #<map object at 0x000002B2A4F04B88>
print(list(map(lambda s:s*s,lst)))
#例2;计算两个列表中相同位置的数据的和
lst1 = [1, 2, 3, 4, 5]
lst2 = [2, 4, 6, 8, 10]
print(list(map(lambda x, y: x+y, lst1, lst2)))
reduce():reduce(函数名,可迭代对象) # 这两个参数必须都要有,缺一个不行,在Python2.x版本中recude是直接 import就可以的, Python3.x版本中需要从functools这个包中导入。
from functools import reduce
def func(x,y):
return x + y
ret = reduce(func,[1,2,3])
print(ret) # 结果 6
#reduce的作用是先把列表中的前俩个元素取出计算出一个值然后临时保存着,接下来用这个临时保存的值和列表中第三个元素进行计算,求出一个新的值将最开始临时保存的值覆盖掉,然后在用这个新的临时值和列表中第四个元素计算.依次类推。注意:我们放进去的可迭代对象没有更改
#现在有[1,2,3,4]想让列表中的数变成1234
l = reduce(lambda x,y:x*10+y,[1,2,3,4])
print(l)
闭包、装饰器
全局变量,数据不安全。使用局部变量,保证数据的安全。当内层函数对外层函数非全局变量的引用(使用)时,就会形成闭包。被引用的非全局变量也称作自由变量,这个自由变量会与内层函数产生一个绑定关系,令自由变量不会再内存中消失。闭包现象只能存在函数的嵌套中。
判断一个函数有没有自由变量:
def func1():
l1= []
def func2(num):
l1.append(num)
return l1
return func2
a = func1()
# 函数名.__code__.co_freevars 查看函数的自由变量
print(a.__code__.co_freevars) # ('l1',)
# 函数名.__code__.co_varnames 查看函数的局部变量
print(a.__code__.co_varnames) # ('num',)
# 函数名.__closure__ 获取具体的自由变量对象,也就是cell对象。
print(a.__closure__)
#(<cell at 0x000001EE151AC738: list object at 0x000001EE135851C8>,)
# cell_contents 自由变量具体的值
print(a.__closure__[0].cell_contents) # []
装饰器:完全遵循开放封闭原则,即在不改变原函数的代码以及调用方式的前提下,为其增加新的功能。(装饰器的本质是闭包)python提出了一个‘语法糖’的概念。在编写了装饰器后,需要将装饰器代码放在所有代码的前方。当要对装饰器函数调用时,在要装饰函数的前方使用@+装饰器函数名
标准版的装饰器(不带参数):
def wrapper(f):
def inner(*arg,**kargs):
'''添加额外的功能:执行被装饰函数之前的操作'''
ret = f(*arg,**kargs)
'''添加额外的功能:执行被装饰函数之后的操作'''
return ret
return inner
#装饰器的调用
@wrapper
def func():
pass
带参数的装饰器
闭包原理,内部函数能够使用外部函数的参数。
def logger(*arg,**kargs): #参数可以自己设定
def wrapper(f):
def inner(*arg,**kargs):
'''添加额外的功能:执行被装饰函数之前的操作,并可以使用传进来的path参数'''
ret = f(*arg,**kargs)
'''添加额外的功能:执行被装饰函数之后的操作,并可以使用传进来的path参数'''
return ret
return inner
return wrapper
@loger('传参') #wrapper = loger(),func=wrapper(func())
def func():
pass
自定义模块
模块的本质就.py文件,封装语句的最小单位。模块的分类:内置模块(200种左右)、第三方模块(6000多种)、自定义模块。当python脚本/模块运行时,python解释器会自动将一些模块、函数加载到内存。可用import sys print(sys.modules)
查看
自定义模块:
-
编写自定义模块开头最好用多行注释说明模块内容。
-
模块中出现的变量、函数定义、类等称为模块的成员。
-
模块(.py文件)的运行方式:
- 脚本方式:直接用解释器执行。
- 模块方式(导入方式):被其他的模块导入,为导入它的模块提供资源(变量、函数定义、类定义等)。
-
模块被其他模块导入时,会将模块中的所有代码加载到内存,其中的可执行语句被会立即执行。因此为了方便调试和使用,可用
__name__
属性。将print(__name__)
编写在模块中时,以脚本方式运行打印的是字符串__main__
,以被导入的方式运行时,会打印出模块名。因此模块应包含if __name__=='__main__':
以用来判断是脚本方式运行还是导入方式,此时当模块被导入时可执行语句不会直接运行。def func(): ...... def main(): pass if __name__=='__main__': main()
导入模块的方式:
-
import xxx
或import xxx,yyy,....
导入一个模块或导入多个模块。经常将import os,sys
这两个模块放在一块导入。可以使用别名(alias,缩写为as)导入:import xxx as z
导入xxx模块重命名为z。当运行至此导入模块方法代码时会在内存全局命称空间中开辟以模块名命名的新的名称空间,并将模块中的所有成员加载至命称空间中。被导入的每个模块都有独立的命称空间。
-
from xxx import y
或from xxx import a,b,c,......
:从某个模块中导入指定的成员或导入多个成员。from xxx import yyy as z
导入xxx模块将成员名重命名为z。当运行至此导入模块方法代码时会在脚本的全局命称空间中创建导入的成员的变量,因此不用使用
模块名.成员名
调用,但用此方法可能会导致命名冲突,后者将前者覆盖。导入后内存全局命称空间中开辟以模块名命名的新的名称空间,变量的内存地址的指向关系仍然不会改变,每个模块仍都有独立的命称空间。 -
from xxx import *