LF 第三章
三元运算
三元运算又称三目运算,是简单的条件语句的简写,如:
val = i if 条件成立 else 2
name = 'alex' if 3>5 else 'ben' #ben
Python文件处理
f = open("大.txt",mode = "r",encoding='utf-8') data = f.read() print(data) f.close()
注意点:
1.注意编码格式,文件的编码,否则转换出错
2.如果不知道文件编码,则可以用rb 直接从硬盘以二进制模式读取存入内存
f = open("大.txt",mode = "rb") data = f.read() print(data) f.close()
这种方式只有一种用处,给机器看
网络传输 rb模式
3.我再打开时,不知道编码,但我想看内容
有个模块 chardet
安装第三方工具包
pip3 install chardet
import chardet # 导入检测包 f = open('大.txt',mode='rb') # 以二进制rb读取文件 data = f.read() print(chardet.detect(data)) # 分析文件,进行预测文件编码 print(data.decode('gbk'))# 分析后将文件以GBK格式解码读取 #{'encoding': 'ISO-8859-1', 'confidence': 0.73, 'language': ''} 大叫好哈哈哈
关于文件处理 另外文章讲解
函数
为什么使用函数
1.代码重复过多
2.如果日后需要修改,则全部需要改,维护性非常差
解决方法:只要将重复代码提取,放在公共地方,起个名字,以后谁要用这段代码,就通过名字调用就可以了
定义:
函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需要调用函数名即可
def sayhi(): print("hello") sayhi()
特性:
减少代码重复
程序变得可扩展
程序变得易维护
形参变量:
只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此形参只有在函数内部有效,函数调用结束返回主调用函数后则不在使用形参变量
实参:
可以是常亮,变量,表达式,函数等。无论实参是何种类型的量,在进行函数调用时,他们都必须有确定的值,以便把这些值传送给形参,因此应预先用赋值,输入等办法使参数获得确定值
def calc(x,y)#形参 res = x**y return res a,b = 3,4 c = calc(a,b)#实参 print("c")
默认参数
def stu(name,age,course,country="cn"):#country 就是默认参数 print(name,age,country,course) stu("张三",22,linux)
默认参数位置要放在顺序参数之后
关键参数
正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需要制定参数名即可(制定了参数名的参数就叫关键参数),有一个要求就是:关键参数必须放在位置参数之后(以位置顺序确定对应关系的参数)
#函数声明: def stu(name,age,course="PY",country="CN"): print("----注册学生信息----") print("姓名:",name) print("age:",age) print("国籍:",country) print("课程:",course) #调用: stu("王尼玛",course='PY',age=22,country="jp")#第二个,第三个第四个就是关键参数
不可以这样
stu('jack',course="py",22,country='jp') stu("ben",22,age=23,country='jp')
非固定参数 *args **kwargs
1.以元组形式的非固定参数
#报警,给一个人发 def send_alert(msg,user): pass #如果公司发展,给10个人发,那么需要调用多次 send_alert("Stop",'alex') send_alert("Stop",'alex1') send_alert("Stop",'alex2') #如果这样需要修改大量代码,该怎么做呢 #user前面嫁个* #第一个参数给了msg,后面所有参数都打包发给*user 原来user是个字符串,现在是个元组
所以以后可以这样写:
#报警发送 del send_alert(msg,*users): for u in users: print("send to ",u) #报警给多人 send_alert('STOP!!!','alex','abc','ben','ken')
如果形参中出现了*,传递的参数就可以不在是固定个数,而是一个所有参数给打包成一个元组
主流一般都是*args
传参的时候两种,
#方式1 sent_alert('STOP','alex','bben','cero') #方式2 sent_alert('STOP',*['alex','bben','cero']) #两种方式效果是一样的
几个注意点:
1.如果方式2,参数前面不加*直接传给*user,会出现一个问题,*会打包一次,则users接收到的是
(['alex','bben','cero'])这样一个元组。为了避免这样情况,需要在传参时前面加一个*,这样user接受到的是(‘alex','bben','cero')
2.带*的非固定参数一般放在最后 因为*user会接受所有
send_alert(msg,*users,age): pass send_alert('abc','ben','alex',22) #这样是错的,*users接受了后面三个,运行报错age没有值 send_alert('abc','ben','alex',age=22) #这样是不报错的,运用关键参数指定赋值
2.以关键字形式的非固定参数:
def func(name,*args,**kwargs): print(name,ages,kwargs) func ('alex',22,'tesla',addr='山东',num=123123) #**kwargs接收的是关键字参数(未定义的关键字参数) d={'nanjing':27149} func('alex',d) #>>会输出 nanjing ({'nanjing':27149}){} 想要传入字典 需要如下操作 func('alex',**d) #>>peiqi (){'nanjing':27149}
函数返回值
def stu_register(name,age,course): print(name,age,course) return name #函数执行到return 则下面的不执行 print(1) ##### #return name,age 返回一个元组('peiqi',29) 因为函数返回只能返回一个值
#也可以直接返回一个列表 [name,age]
全局变量和局部变量
name = 'black' def change_name(): name = 'yellow' print(name) print(name) #输出 yellow # black #内部是局部变量,外部是全局变量 两个name名字一样但完全不是一个值 #通过id(name)就知道两个变量指向的内存地址不同
#注意函数内printname 如果有局部变量,则print打印的是函数内的name,否则调用外面的全局变量
#注意,里面可以调用外面,但外面不能调用里面
局部变量就是指定义在函数里的变量 只能在局部生效,函数一旦执行完毕 里面生成的所有局部变量全部销毁
定义在函数外部一级代码的变量,叫全局变量,全局能用
在函数内部,可以引用全局变量,如果全局和局部有一个同名变量,那函数查找顺序是由内而外的
如果在函数内修改全局变量 name = 'abc' 其实是声明了一个局部变量
如果执意要修改全局变量,则需要调用方法
name = 'girl' def change_name(): global name name = 'boy' pring("在函数中局部变量name的值:",name) print("全局变量name的值:",name) >>>在函数中局部变量name的值:boy >>>全局变量name的值:boy #两个内存地址是一样的,即global name 在函数里面修改局部变量 #如果函数中调换了global name和name会报错。所以想要引用全局就要把global放上面,即 先要声明要修改某全局变量,再去修改
在实际的开发过程中一般情况下不建议使用global
函数里修改列表数据
names = ['alex','blg','peiq'] def change_name(): del names[2] print(names) change_name() print(names)
['alex', 'blg']
['alex', 'blg']
发现可以修改
原因很简单,列表是引用,元素占用单独的内存地址,列表的内存地址不能改,但是内部单独是可以修改的
字典,列表 集合 类 对象 内部是不能改的 元组内有列表 是可以改的
字符串 数字 true false 不能改
执意要改 就是global
嵌套函数
def func1(): print('alex') def func2(): print('eric')
func1()
>>>>alex
func1()执行后,只打印alex
原因:函数如果定义完成之后,没有人通过他的名字调用它,那么他永远不会执行
def func1(): print('alex') def func2(): print('eric') func2() func1() >>>>alex >>>>eric
-----
1.函数内部可以再次定义函数
2.只要函数定义了,不管在外还是内,要想执行,需要被调用
age = 19 def func1(): age = 73 print(age) def func2(): age = 84 print(age) func2() func1()
>>>73
>>>84
函数内部自己找变量名,找不到再往外找
但是如果代码是这样
age = 19 def func1(): age = 73 print(age) def func2(): print(age) func2() func1()
这里注意,由内往外找,是一层一层往外找,func2()里面的age也是局部变量
接下来
age = 19 def func1(): def func2(): print(age) age = 73 func2() func1()
>>>73
这里比较简单,函数从上到下运行,碰到函数但是不执行,执行func2()时候,age = 73被赋值,所以func2中age=73
接下来
age = 19 def func1(): def func2(): print(age) func2() age = 73 func1() #报错
报错是因为,printage时候,找不到是哪个age,自己体会,不放在func2下面
接下来刺激的
age = 19 #极少用到 def func1(): global age def func2(): print(age) func2() age = 73 func1() >>>19
执行为啥是19 因为在函数func1中,global了age,相当于在此处 age = 19,那么在下面调用func2时候,会往外找,即19
接下来age = 73 ,那样全局变量就变成了73,那么如果在外面加一个打印那就是73
作用域
在python中,函数就是一个作用域 局部变量放置在其作用域中
注意:在这段代码定义完成后,作用域已经生成,作用域链向上查找
但是在别的语言里,比如java c# 不同
age = 77 def func1(): age = 18 money = 1999 print('alex') def func2(): age = 88 print('eric')
接下来看
age = 18 def func1(): age = 73 def func2(): print(age) return func2 val = func1() val()
执行后 ,结果是73,这里就有作用域了,函数无论不论在哪被调用,都会回到原来的作用域中
总结 1.函数名可以当做返回值
2.代码写完之后,作用域已经生成,不论函数名传递到哪里 ,只要执行,回到最开始的地方
3.Pythion中函数就是一个作用域(与java c#不同)局部变量防止在其作用域中
匿名函数
定义一个函数不用名字?
def calc(x,y): return x*y lambda x,y:x*y # 声明一个匿名函数 #普通函数调用通过名字() #匿名函数如何调用? func = lambda x,y:x*y print(func(3,4)) #lambda匿名函数是不支持ifelse等复杂的逻辑语句,只能简单的逻辑判断 #最多最多支持三元运算 func = lambda x,y:x*y if x<y else x/y #匿名函数的主要作用:就是跟其他方法搭配使用 data = list(range(10)) print(data) #自乘 #老办法是: # for index,i in enumerate(data): # data[index]=i*i # print(data) #单独的方法 map def f2(n): return n*n print(list(map(f2,data))) #或者 print(list(map(lambda x:x*x,data))) #这里的lambda跟其他方法调用使用,即用完一次就不用了,为了简单方便 #1。节省代码量 #2,。看着高级
高阶函数
变量可以指定函数,
函数的参数能接受变量,那么一个函数就可以接受另一个函数作为参数,这种函数就称为高阶函数
def cala(x): return xxx n = 10 cala(10) #如果传一个函数当参数进去 只要传函数,就是高阶函数 def func(x,y): return x+y def cala(x): return x() n = func cala(func)
返回
def func(x,y): return abs,x,y res = func2(3,-10) #返回一个元组 print(res[0](res[1]+res[2])) #只要你返回值里面有另一个函数,那他也是一个高阶函数
总结:给一个函数传另一个函数作为参数,或者一个函数返回另一个参数作为返回值,那么这个函数就是高阶函数
递归
递归就是函数执行过程中调用了自己
def recoursion(n): print(n) recoursion(n+1) recoursion(1) #会报错 超过了最大限制 #python有个最大递归层次限制 sys.getrecursionlimit() 默认是1000 #修改限制:sys.setrecursionlimit(9999)
Python为什么要限制递归次数?
简单地说:每次新的递归,前一个函数仍在执行之中,内存会约占约多,如果无限运行系统很快就会撑爆了
为了避免出现这种情况,所以进行了限制
专业的说:在计算机中,函数的调用时通过栈(手枪弹夹来理解,弹夹就是栈,子弹就是栈帧)来调用的,但是python中不存在这种数据结构。由于函数没有停止,栈内就会很快被填满,就会出现栈溢出,无法存入数据,程序会崩溃。
每执行一次,加一层栈帧,函数销毁则减一层。
递归的作用
需求 10/2 一直除到0为止
def func(x): v=int(x/2) print(v,end=' ') if v == 0: return "done" func(v) func(10)
如果
def func(x): v=int(x/2) print(v) if v == 0: return "done" func(v) print(v) func(10) >>>5 2 1 0 1 2 5
递归特点
1.必须有结束条件
2.每一次进入更深一层递归时,问题规模相比上次递归都应有所减少
3.递归执行效率不高,递归层次够多会导致栈溢出
递归的作用
斐波那契数列之类
求阶乘
任何大于1的自然数n阶乘表示方法:
n!=1x2x3x4x5x6x..xn
或n!=nx(n-1)!
def func(n): if n == 1: return 1 return n*func(n-1) print(func(10))
>>>3628800
尾递归优化
def cal(n): print(n) return cal(n+1) cal(1) #优化思路 每一层return 后,下一层是直接返回,不再用上一层。那为什么上一层还要在占用内存 #以上就是尾递归,但是python不支持 还是会生成多个栈 知道这回事
内置函数
abs() #取绝对值 dict() #把一个数据转为字典 help() #帮助 min() # 取出列表最小值 (int) max() #取出最大值 (int) all() #如果列表所有值都是True或者空列表[],那么all返回true bool() #判断是不是True (0是False 其他是True) #对于一个列表,直接判断都是False any() #列表里任意值是True,返回True dir() #打印当前程序存在的所有变量 hex() #转成16进制 slice() #切片 slice(start,stop[,step]) 先规定切片规则方便后面用,没啥用 divmod() #(10,3)>>(3,1)得到两个数的结果,在返回余数 // sorted() #排序 对于一个字典d,需要排序 一般需要排序的话,首先转成列表d.items() ,不按key排序,用sorted(d.items(),key=lambda x:x[1])排序,按照value从小到大排序 acsii() #没什么用转成unicode一堆二进制 bin()#转成二进制
eval() #按解释器规则字符串转代码 f = '1+3/2' eval(f) #eval('print('hello')) >>hello #eval()能处理的只能是单行代码 exec() #与eval()一样,但是他能执行多行代码 #最大区别 eval有返回值,exce没有返回值 ord() #输出acsii 对应位置 'a'>>97 chr #输出acsii >>字符串 chr(97) >>'a' sum() #列表值求和
bytearray() #字符串不可修改 s= 'abcd' s[0]='x' 报错 #但是可以通过修改bytes s.encode('utf-8') s = bytearray(s) s[0] = 65 s.decode() >>Abcd #这里是原内存地址修改,不是重新开辟新内存地址。 #大字节修改,先变成bytes类型,再修改 map(f,list) #map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回。 filter(f,list) #过滤的意思,把符合条件的值过滤出来 #filter(lambda x:x>3,[1,2,3,4,5,6]) >>[4,5,6] map filter reduce 三剑客reduce 2.0有 在python3里 import functools reduce(f,list,x) # functools.reduce(lambda x,y:x+y,[1,2,3,4,5,6],3)!???????????????? print() #1.end='' 以''断 默认是\n #2.sep = '-' :print('abc','bcd',sep='-')>>abc-bcd #3.print可以直接把数据打印进文件里 #msg = 'abcde' #f = open('lala.txt','w') #print(msg,'aaaaa',sep='`',end = '',file = f) tuple() #变成元组 callable() #判断是否可以调用 #def f(): pass #callable(f)>>>True #判断一个变量是否是函数,可以用这个方法判断。 wars() #当前所有变量打印出来,跟dir有区别,dir只会打印变量名,wars打印变量名和值 locals() #一般在函数内运行,打印函数的局部变量。永远只打印 局部变量 globals() #不管在哪运行,打印所有全局变量 repr(集合) #打印显示字符串?????????????????????????? zip() # a = [1,2,3,4] b=['a','b','c'] 想把两个列表 一一对应整合成一个列表 对应成为元组,放在一个列表里??????? # list(zip(a,b) >>> [(1,'a'),(2,'b'),(3,'c')] 一一对应没有就丢弃 reversed() #和sorted()类似,默认反转??????????????? complex(3,5) #(3+5j)??????? round() #round(1.234434)>>1 round(1.234434,2)>1.23 保留几个小数 复习下hash() 集合 set() #把一个列表变成一个集合 set([3,3,4])>>{3,3,4}
几个小栗子:
1、现在有两个列表,list1 = ['key1','key2','key3']和list2 = ['1','2','3'],把他们转为这样的字典:{'key1':'1','key2':'2','key3':'3'} >>>list1 = ['key1','key2','key3'] >>>list2 = ['1','2','3'] >>>dict(zip(list1,list2)) {'key1':'1','key2':'2','key3':'3'} 2、将嵌套列表转为字典,有两种方法, >>>new_list= [['key1','value1'],['key2','value2'],['key3','value3']] >>>dict(list) {'key3': 'value3', 'key2': 'value2', 'key1': 'value1'} 或者这样: >>>new_list= [['key1','value1'],['key2','value2'],['key3','value3']] >>>new_dict = {} >>> for i in new_list: ... new_dict[i[0]] = i[1] #字典赋值,左边为key,右边为value ... >>> new_dict {'key3': 'value3', 'key2': 'value2', 'key1': 'value1'}