Day04-python基础函数
一.函数的对象:函数是第一类对象,即函数可以当作数据传递
1.可以被引用
示例:
def foo(): print('from foo') func=foo print(foo) # <function foo at 0x0000000000A1E048> print(func) # <function foo at 0x0000000000A1E048> 和上面的内存地址一样 func() # from foo 可以被直接引用
2.可以当作参数传递
示例:
def foo(): print('from foo') def bar(func): print(func) foo() bar(foo)
3.返回值可以是函数
def foo(): print('from foo') return foo v = foo() print(v) def foo(): print('from foo') def bar(func): return func v = bar(foo) print(v) v()
4.可以当作容器类型的元素
示例:
def foo(): print('from foo') dic = {'fuck':foo} print(dic['fuck']) dic['fuck']()
def select (sql): print('===========>select') def update (sql): print('===========>update') def delete (sql): print('==========>delete') def insert (sql): print('==========>insert') fun_dic = { 'select':select, 'updata':update, } def main(): while True: sql = input('sql>').strip() if not sql:continue l = sql.split() cmd = l[0] if cmd in fun_dic: fun_dic[cmd](l) main()
二.函数的嵌套
1.函数嵌套的调用
def my_max(x,y): res = x if x > y else y return res def max1(x,y,z,h): res1=my_max(x,y) res2=my_max(res1,z) res3=my_max(res2,h) return res3
print(max1(10,55,45,99))
2.函数嵌套的定义
def foo(): print('from foo') def foo1(): print('from foo1') def foo2(): print('from foo2') foo1() foo() foo1()# 报错
三.名称空间和作用域
1.名称空间:存放名字的地方,以及三种名称空间详解
1.1.内置名称空间:(随着python解释器的启动而产生)
print(sum) # <built-in function sum> (内置函数的内存地址) print(max) # <built-in function max> print(min) # <built-in function min>
查看内置名称
import builtins for i in dir(builtins): print(i)
1.2 全局名称空间:文件的执行会产生全局名称空间,指的是文件级别定义的名字都会放入该空间
x = 1 if x ==1: y=2 import time name = 'jim' def func(): pass class foo: pass #以上全是全局定义的名字
1.3 局部名称空间:调用函数时会产生局部名称空间,只在函数调用时临时绑定,调用结束时解绑
x =1000 def func(): x = 1 def f1(): pass f1()
2.作用域分为两种:
2.1全局作用域:内置名称空间,全局名称空间
2.2局部作用域:局部名称空间
名字的查找顺序:局部名称空间====》全局名称空间=====》内置名称空间
x = 1 def func(): x = 2 print(x) func() # 输出结果 2 如果把x = 2注释掉,先在自己的局部里面找,局部里面没有,就会在全局里面查找
def foo():
sum = 123
print(sum)
foo()# 输出结果123 ,如果把sum=123注释掉就先会在自己局部里面找,局部里面没有sum,就会到全局名称空间里面查找,全局没有机会在内置里面查找
查看全局作用域内的名字:gloables()
查看局部作用域内的名字:locals()
# x = 100 # def my_max(): # x = 1 # print(globals()) # print(locals())
在全局的范围查看全局的局部,仍然是全局。
def foo(y): x= 1 print(locals()) # 输出结果:{'x': 1, 'y': 1} print(globals()) # 在局部的范围查看局部的全部,就是全局。 foo(1)
全局作用域:全局有效,在任何位置都能被访问到,除非del删除掉,否则会一直活到文件执行完毕失效
局部作用域的名字:局部有效,只能在局部范围调用,只有在函数调用时才有效,调用结束失效
四.闭包函数:(定义在内部函数包含对外部作用域而非全局作用域的引用,该内部函数就成为闭包函数)
def f1(): x= 1 def f2(): print(x) return f2 f=f1() print(f) f()
闭包函数的应用:(爬网站页面的信息)
from urllib.request import urlopen res = urlopen('http://www.baidu.com').read() print(res.decode('utf-8')) # 没有使用闭包函数
from urllib.request import urlopen def index(url): def get(): return urlopen(url).read() return get baidu=index('http://www.baidu.com') # print(baidu().decode('utf-8')) print(baidu.__closure__[0].cell_contents) # 查看闭包函数外面包的是什么
五.装饰器:(修饰被人的工具,修饰添加功能,工具指的是函数)
装饰器本身可以是任何可调用对象,被装饰的是也可以是任意可调用对象
为什么要用装饰器:
1.开放封闭原则:对修改是封闭的对扩展是开放的
2.装饰器就是为了在不修改被装饰对象的源代码以及调用方式的前提下,为其添加功能
示例:
import time def timmer(funk): def warpper(): starttime=time.time() funk() stoptime=time.time() print('run time is %s'%(stoptime-starttime)) return warpper @timmer def index(): time.sleep(3) print('welcome to index') index()
装饰器应用在多个函数里面
import time def timmer(funk): def warpper(*args,**kwargs): starttime=time.time() res=funk(*args,**kwargs) stoptime=time.time() print('run time is %s'%(stoptime-starttime)) return res return warpper @timmer def index(): time.sleep(3) print('welcome to index') return 11 res=index() print(res) @timmer def foo(name): time.sleep(1) print('from foo') res1=foo('jim') print(res1)
实现用户登录之前需要认证功能才能进入
login_user={'user':None,'status':False} def auth(func): def wrapper(*args,**kwargs): if login_user['user'] and login_user['status']: res=func(*args,**kwargs) return res else: name=input('>>>') pwd=input('>>>') if name=='jim'and pwd=='123': login_user['user']='jim' login_user['status']=True print('认证通过') func(*args,**kwargs) else: print('认证失败') return wrapper @auth def index(): print('welcome to index page') @auth def home(name): print('welcome to home page') index() home('jim')
有参装饰器
login_user={'user':None,'status':False} def auth(driver='file'): def auth1(func): def wrapper(*args,**kwargs): if driver=='file': if login_user['user'] and login_user['status']: res=func(*args,**kwargs) return res else: name=input('>>>') pwd=input('>>>') if name=='jim'and pwd=='123': login_user['user']='jim' login_user['status']=True print('==========>file的认证') print('认证通过') func(*args,**kwargs) else: print('认证失败') elif driver=='ldap': print('===========>ldap的认证') return func(*args,**kwargs) elif driver=='mysql': print('===========>mysql的认证') return wrapper return auth1 @auth('file') def index(): print('welcome to index page') @auth('ldap') def home(name): print('welcome to home page') index() home('jim')
附加多个装饰器
import time def timmer(funk): def warpper(*args,**kwargs): starttime=time.time() res=funk(*args,**kwargs) stoptime=time.time() print('run time is %s'%(stoptime-starttime)) return res return warpper login_user={'user':None,'status':False} def auth(driver='file'): def auth1(func): def wrapper(*args,**kwargs): if driver=='file': if login_user['user'] and login_user['status']: res=func(*args,**kwargs) return res else: name=input('>>>') pwd=input('>>>') if name=='jim'and pwd=='123': login_user['user']='jim' login_user['status']=True print('==========>file的认证') print('认证通过') func(*args,**kwargs) else: print('认证失败') elif driver=='ldap': print('===========>ldap的认证') return func(*args,**kwargs) elif driver=='mysql': print('===========>mysql的认证') return wrapper return auth1 @timmer @auth('file') def index(): print('welcome to index page') @auth('ldap') def home(name): print('welcome to home page') index() home('jim')
六.迭代器
迭代的概念:重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值
while True: # 只满足重复,因而不是迭代 print('========>')
以下才为迭代:
l = [1,2,3] count = 0 while count < len(l): print('======>',l[count]) count += 1
为什么要有迭代器:对于没有索引的数据类型,必须提供一种不依赖索引的迭代方式
可迭代的对象:
[].__iter__() ''.__iter__() (0,1).__iter__() {'a':1,'b':2}.__iter__() {1,2,3}.__iter__()
迭代器: 执行_iter_()方法,得到的结果就是迭代器
i= [1,2,3].__iter__() print(i) # <list_iterator object at 0x000000000110A550> print(i.__next__()) print(i.__next__()) print(i.__next__()) print(i.__next__())# 抛出异常 stopiteration 表示已经取完,没有可取的值了
i= {'a':1,'b':2,'c':3}.__iter__() print(i.__next__()) print(i.__next__()) print(i.__next__())
dic = {'a':1,'b':2,'c':3} i = dic.__iter__() while True: try: key=i.__next__() print(dic[key]) except StopIteration: break # try 和 except 是处理异常报错的命令
s = 'hello' print(s.__len__()) print(len(s)) # s._len_等同于len(s)
s = {1,2,3,4} i=iter(s) print(next(i)) print(next(i)) print(next(i)) print(next(i))
如何判断一个对象是可迭代的对象,还是迭代器对象
以下是可迭代的对象
f = open('file','r',encoding='utf-8') from collections import Iterable,Iterator print(isinstance('abc',Iterable)) print(isinstance([],Iterable)) print(isinstance((),Iterable)) print(isinstance({'a':1,},Iterable)) print(isinstance({1,2,3},Iterable)) print(isinstance(f,Iterable))
以上只有文件是迭代器对象,其他都是可迭代的对象,如果可迭代对象加上_iter_就是迭代器对象
可迭代对象只有__iter__方法,执行该方法得到的是迭代器对象
迭代协议:对象有__next__ 对象有__iter__对于迭代器对象来说,执行__iter__方法得到的结果仍然是他本身
for 循环 遵循的就是迭代器协议,它会把in后面的对象,执行__itre__方法把它变成迭代器,一次for循环为next一次,for循环会自动处理异常报错
迭代器的优点和缺点
优点:1.提供了一种不依赖下标的迭代方式 2.就迭代器本身来说,更节省内存
缺点:迭代器不如序列类型取值灵活,是一次性的,只能完后取值,不能倒退 2.无法获取迭代器对象的长度
七.生成器函数:(只要函数体包含yield关键字,该函数就是生成器函数)
1.yield的语句形式
def foo(): return 1 return 2 res1=foo() res2=foo() print(res1) # 返回值 1 print(res2) # 返回值 1 # 函数执行到return之后,return只执行一次,函数就会终止。
def foo(): print('one') yield 1 print('two') yield 2 print('three') yield 3 print('fouth') f=foo() print(f)# <generator object foo at 0x000000000059EE08> yield会把函数变成迭代器(生成器) print(next(f))# 触发迭代器f的执行,进而触发函数的执行 print(next(f)) print(next(f)) for i in f: # f是迭代器就可以用for循环输出其内容了 print(i)
生成器示例
def counter(n): print('start...') i=0 while i < n: yield i i+=1 print('end......') f = counter(5) for i in f: print(i)
yield的功能:
1.相当于为函数封装好__iter__和__next__
2.return只返回一次值,函数就终止了,而yield能返回多次值,每次返回都会将函数暂停,下次next会从上一次暂停的文职继续执行
yider示例模拟管道传值,
import time def tail(file): with open('file',encoding='utf-8')as f: f.seek(0,2) while True: line=f.readline().strip() if line: yield line else: time.sleep(0.5) def grep(pattern,lines): for line in lines: if pattern in line: yield line g=grep('python',tail('file')) for i in g: print(i)
2.yield的表达式的形式(协程函数)
2.1表达式形式的生成器,在最开始执行的时候必须传一个空值,使其达到初始化的位置,之后才可以send值给yield
传空值初始化的两种方法:1.next(生成器)2.生成器.send('None')
def eater(name): print('%s ready to eat'%name) while True: food=yield print('%s start to eat %s'%(name,food)) g=eater('jim') next(g) # 等同于 g.send('None') g.send('麻辣香锅')# 可以传参数给yield,如果第一就直接传非None的值就会报错,提示开始必须传非None的值
使用装饰器给上面的例子加上初始化的功能
def foo(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) next(res) return res return wrapper @foo def eater(name): print('%s ready to eat'%name) food_list=[] while True: food=yield food_list food_list.append(food) print('%s start to eat %s'%(name,food)) g=eater('jim') print(g.send('香辣烤鱼')) print(g.send('麻辣香锅'))
x=yield
#g.send(值),先把值传给yield,由yield赋值给变量x
# 然后再往下执行,直到再次碰到yield,然后把yield后的返回值返回
yield表达式形式的示例(使用yield表达式形式模拟 grep -rl 'python' /root的功能)
import os def init(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) next(res) return res return wrapper @init def search(targer): while True: search_path=yield g=os.walk(search_path) for par_dir,_,files in g: for file in files: file_abs_path=r"%s\%s"%(par_dir,file) targer.send(file_abs_path) @init def opener(target): while True: file_abs_path=yield with open(file_abs_path,encoding='utf-8') as f: target.send((file_abs_path,f)) @init def cat(target): while True: file_abs_path,f=yield for line in f: tag=target.send((file_abs_path,line)) if tag: break @init def grep(target,pattern): tag=False while True: file_abs_path,line=yield tag tag=False if pattern in line: tag=True target.send(file_abs_path) @init def printer(): while True: file_abs_path=yield print(file_abs_path) if __name__ == '__main__': pattern=input('请输入您要检索的关键字:') x=input(r'请输入您要检索的路径:') g=search(opener(cat(grep(printer(), pattern)))) g.send(x)
上面的示例是一种面向过程的程序设计。
面向过程的程序设计:是一种流水线式的编程思路,是机械式
优点:
程序的结构清晰,可以把复杂的问题简单
缺点:
1 扩展性差
应用场景:
1 linux内核,git,httpd
八.匿名函数
匿名函数的语法:lambda 变量 :返回值
f=lambda x,y:x+y # x y 为参数 :后面是返回值 给匿名函数赋值就变成普通函数了 print(f) print(f(1,2))
# 输出结果:
<function <lambda> at 0x00000000006AD6A8>
3
匿名函数与max、min、zip、sorted结合使用方法
salaries={
'egon':3000,
'alex':100000000,
'wupeiqi':10000,
'yuanhao':2000
}
#不使用匿名函数的方法:
def foo(x): return salaries[x] print(max(salaries,key=foo))
# 使用匿名函数的实现方法 salaries={ 'egon':3000, 'alex':100000000, 'wupeiqi':10000, 'yuanhao':2000 } print(max(salaries,key=lambda x:salaries[x]))#求出字典里面valuse值最大的key值 print(min(salaries,key=lambda x:salaries[x]))#求出字典里面valuse值最小的key值 print(sorted(salaries,key=lambda x:salaries[x]))#默认的排序结果是从小到大 print(sorted(salaries,key=lambda x:salaries[x],reverse=True))#加上reverse=True,就变成从大到小
# 输出结果:
alex
yuanhao
['yuanhao', 'egon', 'wupeiqi', 'alex']
['alex', 'wupeiqi', 'egon', 'yuanhao']
九.内置函数
1.abs
print(abs(-1)) # 将负数转化为正数
2.all
print(all([1,2,3]))# for循环可迭代对象的值,进行bool值的判断,如果都为true,返回true,有一个为false,就是false。 print(all([])) # 可迭代对象为空,返回也是True
3.any
print(any([1,0,2,3]))# #for循环可迭代对象的值,进行bool值的判断,如果有一个为true,返回true print(any([]))# 可迭代对象为空时,返回false
4.bin 十进制转二进制
print(bin(3)) print(hex(17))# 十进制转十六进制 print(oct(9)) #十进制转八进制
5.bool
print(bool(0))
6.callable # 判断可调用对象
def foo(): pass print(callable(foo))
7.chr 根据ascii码表吧数字转换成对应的字符 ord 根据ascii码表吧字符转换成对应的数字
print(chr(68)) print(ord('D'))
8.工厂函数
dict
int
str
set
list
9.查看一个对象下面的属性
l = [] print(dir(l))
10.divmod 求商和余数,以元组形式显示
print(divmod(10,3))
11.eval 将字符串中的内容提取出来进行操作
cmd = 'print("123")' eval(cmd) with open('file','w',encoding='utf-8')as f: f.write(str({'name':'jim','pwd':'123'})) with open('file','r',encoding='utf-8')as f: dic=f.read() print(type(dic)) dic=eval(dic)# 将文件当中的字符串形式的字典,转换成字典的类型 print(type(dic))
12.frnzeenset 不可变集合关键字
s = frozenset({1,2}) # 这样就不可以增加了
13.foemat 有三种实现方法
li = '我叫:{0},性别:{1},年龄:{2}' new_li = li.format('成飞','男',18) print(new_li) # 输出内容:我叫:成飞,性别:男,年龄:18 li = '我叫:{name},性别:{gender},年龄:{age}' new_li = li.format(name='成飞',gender='男',age=18) print(new_li) # 输出内容:我叫:成飞,性别:男,年龄:18 li = '我叫:{name},性别:{gender},年龄:{age}' new_li = li.format_map({'name':'chengfei','gender':'nan','age':18}) print(new_li) # 输出内容:我叫:成飞,性别:男,年龄:18
14.hash得到哈希值
print(hash('hsjfjka'))
15.id 判断id号
x = 1 y = x print(id(x),id(y)) 判断的是id号 a = 1 b = 1 print(a==b) # 判断的是对应的值
16.pow 前面两个值是求第一个数的几次方,三个值是前面两个值的平方和第三个值的余数
print(pow(10,2,3))
17.reversed 翻转
l = [1,2,3,4] print(reversed(l)) # 得到的是个迭代器 for i in reversed(l): print(i)
18.round 为前面的数保留几位小数,以一个参数是数,第二参数为保留几位小数
print(round(3.1415926,4)) # 3.1416 会四舍五入
19.slice 切片
l = ['a','b','c','d','e'] print(l[1:4:2]) s=slice(1,4,2) print(l[s])
20.vars() # 空参数等于locals()
21.zip 拉链功能
s = 'hello' l = [1,2,3,4,5] z=zip(s,l) print(z)# 得到的z是个迭代器 for i in z: print(i)
22 _import__
m=__import__('time')# 以字符串的形式导入模块
23.map
l=['jim','tom','bob'] res=map(lambda x:x+'_sb',l) nums_l=[2,9,11,24] nums_res=map(lambda x:x**2,nums_l) print(list(res)) print(list(nums_res))
# 输出结果
['jim_sb', 'tom_sb', 'bob_sb']
[4, 81, 121, 576]
24.reduce
from functools import reduce l=[1,2,3,4,5] print(reduce(lambda x,y:x+y,l))# 求和 print(reduce(lambda x,y:x*y,l)) print(reduce(lambda x,y:x/y,l)) print(reduce(lambda x,y:x-y,l))
# 输出结果:
15
120
0.008333333333333333
-13
25.filter 过滤
l=['jim_en','tom_en','bob_en','feier'] res=filter(lambda x:x.endswith('en'),l) print(list(res))
十.递归调用(递归调用:在函数调用过程中,直接或间接地调用了函数本身,这就是函数的递归调用)
1.简单的递归调用
1.
def f1(): print('from f1') f1() f1()# 重复调用,重复递归下去
2.
def f1():
print('from f1')
f2()
def f2():
f1()
f1()# 重复调用,重复递归下去
默认python不会让无限递归下去的,出现之后就会报错终止掉无限递归
查看Python默认可以递归多少次
import sys # 插入sys模块 print(sys.getrecursionlimit()) #查看Python默认可以递归多少次 sys.setrecursionlimit(10000) # 修改递归的次数 print(sys.getrecursionlimit())
2.递归调用示例:
def age(n): if n == 1: return 18 return age(n-1)+2 print(age(5))
# 输出结果: 26
递归分两个步骤:递推和回溯
递归效率低,需要在进入下一次递归时保留当前的状态
解决方法是尾递归,即在函数的最后一步(而非最后一行)调用自己
但是python又没有尾递归,且对递归层级做了限制
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
3.递归调用示例
l=[1,2,10,22,30,31,33,40,55,67,79,86,99,125,265] def search(find_num,seq): if len(seq) ==0: print('%s not in list'%find_num) return mid_index=len(seq)//2 mid_num=seq[mid_index] # print(seq,mid_num) if find_num > mid_num: seq=seq[mid_index+1:] search(find_num,seq) elif find_num < mid_num: seq=seq[:mid_index] search(find_num,seq) else: print('find it %s'%find_num) search(79,l)
# 输出结果:find it 79