首页 > 代码库 > Python自动化开发课堂笔记【Day04】 - Python基础(函数)
Python自动化开发课堂笔记【Day04】 - Python基础(函数)
函数对象
函数是第一类对象,即函数可以当作数据传递。具体用法分成以下四类:
1. 可以被引用
1 def foo(): 2 print(‘from foo‘) 3 func=foo 4 print(foo) ---> <function foo at 0x00386C48> --> foo函数在内存中地址 5 print(func) ---> <function foo at 0x00386C48> 6 foo() ---> from foo 7 func() ---> from foo
2. 可以当作参数传递
1 def foo(): 2 print(‘from foo‘) 3 def bar(func): 4 print(func) ---> <function foo at 0x00306DF8> --> func函数在内存中地址 5 func() ---> from foo 6 bar(foo)
3. 返回值可以是函数
1 def foo(): 2 print(‘from foo‘) 3 def bar(func): 4 return func ---> 作为返回值 5 f=bar(foo) 6 print(f) ---> <function foo at 0x002E6DF8> 7 f() ---> from foo
4. 可以当作容器类型的元素
1 def foo(): 2 print(‘from foo‘) 3 dic={‘func‘:foo} ---> 在字典中作为键值存在 4 print(dic[‘func‘]) ---> <function foo at 0x00556C48> 5 dic[‘func‘]() ---> from foo
5. 应用实例
SQL语句操作判定
1 def select(sql): 2 print(‘========>select‘) 3 def insert(sql): 4 print(‘========>add‘) 5 def delete(sql): 6 print(‘========>delete‘) 7 def update(sql): 8 print(‘========>update‘) 9 func_dic={‘select‘:select, ‘update‘:update, ‘insert‘:insert, ‘delete‘:delete} 10 def main(): 11 while True: 12 sql = input(‘>>: ‘).strip() 13 if not sql:continue 14 l = sql.split() 15 cmd=l[0] ---> 读取SQL语句首单词 16 if cmd in func_dic: 17 func_dic[cmd](l) ---> 当作容器类型的元素 18 main()
简易姓名查询数据库
1 def init(database): 2 database[‘first‘] = {‘Jia‘:{‘Jia Xiao Liang‘}} 3 database[‘middle‘] = {‘Xiao‘:{‘Jia Xiao Liang‘}} 4 database[‘last‘] = {‘Liang‘:{‘Jia Xiao Liang‘}} 5 6 def lookup(database, lable, name): 7 return database[lable].get(name) 8 9 def store(database, full_name): 10 names = full_name.split(‘ ‘) 11 if len(names) == 2: 12 names.insert(1,‘ ‘) 13 lables = ‘first‘,‘middle‘,‘last‘ 14 for lable, name in zip(lables,names): 15 people = lookup(database, lable, name) 16 print(people) 17 if people: 18 database[lable][name].add(full_name) 19 else: 20 database[lable][name] = {full_name} 21 22 if __name__ == ‘__main__‘: 23 storage = dict() 24 print(type(storage)) 25 init(storage) 26 while True: 27 print(‘Store:‘,storage) 28 name = input(‘>>>‘).strip() 29 store(storage,name)
函数嵌套
1. 函数的嵌套调用
1 def max2(x,y): 2 return x if x > y else y 3 def max4(a,b,c,d): 4 res1=max2(a,b) 5 res2=max2(res1,c) 6 res3=max2(res2,d) 7 return res3 8 print(max4(10,99,31,22))
2. 函数的嵌套定义
1 def f1(): 2 def f2(): 3 print(‘from f2‘) 4 def f3(): 5 print(‘from f3‘) 6 f3() 7 f2() 8 f1()
命名空间
1. 三种命名空间
1. 内置名称空间:随着Python解释器的启动而产生
1 print(sum) ---> <built-in function sum> 2 print(max) ---> <built-in function sum> 3 print(min) ---> <built-in function sum> 4 import builtins 5 for i in dir(builtins): 6 print(i) ---> 打印出所有内置函数
2. 全局名称空间:文件的执行会产生全局名称空间,指的是文件级别定义的名字都会放入该空间
1 x=1 2 def func(): 3 money=2000 ---> 局部名称空间中的变量 4 x=2 5 print(‘func x = ‘, x) 6 print(x) 7 print(func) 8 func() 9 # print(money) ---> 报错,money是函数中定义的变量,属于局部名称空间
3. 局部名称空间:函数被调用时会产生局部名称空间,只是在函数调用时临时绑定,调用结束后绑定自动解除(可参考上段代码)
作用域
1. 全局作用域:
a.)内置命名空间,全局命名空间
b.)查看全局作用域内的名字方法globals()
c.)全局有效,在任何位置都能访问到,除非del删除,否则会一直存活到文件执行完毕
2. 局部作用域
a.)局部命名空间
b.)查看局部作用域内的名字方法locals()
c.)局部有效,只能在局部范围内调用,只在函数被调用时有效,调用结束后自动失效
变量名字的查找顺序:局部命名空间 ---> 全局命名空间 ---> 内置命名空间
1 x=1 ---> 属于全局作用域,内部函数也可以调用 2 def func(): 3 x=2 ---> 函数内变量属于局部作用域,函数外部不可调用 4 print(‘local.x = ‘,x) ---> x = 2 5 sum=123123 6 print(‘local.sum = ‘,sum) ---> sum = 123123 7 print(globals()) ---> {‘__doc__‘: None, ‘__cached__‘: None, ‘__package__‘: None, ‘func‘: <function func at 0x00456C48>, ‘__loader__‘: <_frozen_importlib_external.SourceFileLoader object at 0x00415AB0>, ‘__spec__‘: None, ‘__file__‘: ‘C:/Users/ajiax/PycharmProjects/Python17/Day04/fortest.py‘, ‘__builtins__‘: <module ‘builtins‘ (built-in)>, ‘x‘: 1, ‘__name__‘: ‘__main__‘} 8 print(locals()) ---> {‘x‘: 2, ‘sum‘: 123123} 9 print(globals() is locals()) ---> False 10 func() 11 print(‘global.x = ‘,x) 12 print(globals()) ---> {‘__doc__‘: None, ‘__cached__‘: None, ‘__package__‘: None, ‘func‘: <function func at 0x00456C48>, ‘__loader__‘: <_frozen_importlib_external.SourceFileLoader object at 0x00415AB0>, ‘__spec__‘: None, ‘__file__‘: ‘C:/Users/ajiax/PycharmProjects/Python17/Day04/fortest.py‘, ‘__builtins__‘: <module ‘builtins‘ (built-in)>, ‘x‘: 1, ‘__name__‘: ‘__main__‘} 13 print(locals()) ---> {‘__doc__‘: None, ‘__cached__‘: None, ‘__package__‘: None, ‘func‘: <function func at 0x00456C48>, ‘__loader__‘: <_frozen_importlib_external.SourceFileLoader object at 0x00415AB0>, ‘__spec__‘: None, ‘__file__‘: ‘C:/Users/ajiax/PycharmProjects/Python17/Day04/fortest.py‘, ‘__builtins__‘: <module ‘builtins‘ (built-in)>, ‘x‘: 1, ‘__name__‘: ‘__main__‘} 14 print(globals() is locals()) ---> True
闭包函数
定义:1. 定义在函数内部
2. 包含对外部作用域而非全局作用域的引用 ,形象点可以说闭包函数是由外部作用域而非全局作用域包裹在里面的函数,它可以使用其外部作用域的变量,但是无法使用更外一层即全局作用域的变量
下划线部分可以理解为一个有外部作用域形成的包裹,并将函数f2()包裹在里面,从而形成闭包函数
1 x = 11 ---> 全局作用域变量,闭包函数无法调用 2 def f1(): 3 x = 1 ---> 外部作用域的变量,闭包函数可以调用 4 def f2(): ---> 闭包函数 5 print(x) 6 return f2 7 f=f1() 8 print(f) ---> <function f1.<locals>.f2 at 0x002D6C48> 9 f() ---> 1 ---> 很明显结果是由闭包函数f2()调用其外部作用域的变量x的结果,而非全局变量的x
闭包函数应用
惰性计算,爬取网页内容
1 from urllib.request import urlopen 2 3 def index(url): 4 def get(): 5 return urlopen(url).read().decode(‘utf-8‘) ---> 将从网页上爬取下来的内容由字节形式转化为urf-8 6 return get 7 web = index(input(‘>>>‘)) ---> 输入需要爬取的网页地址 8 print(web()) ---> 打印爬取到的网页内容
print(web.__closure__[0].cell_contents) ---> 将闭包函数引用的外部命名空间的变量显示出来,多个变量以元组的形式存在
1 x=11 2 y=22 3 def f1(): 4 x=1 5 y=2 6 def f2(): 7 print(‘x = %s and y = %s‘ % (x,y)) 8 return f2 9 f=f1() 10 f() ---> x = 1 and y = 2 11 print(f.__closure__[0].cell_contents,f.__closure__[1].cell_contents) ---> 1 2 12 print(f.__closure__) ---> (<cell at 0x00245AF0: int object at 0x66115910>, <cell at 0x00245B50: int object at 0x66115920>)
装饰器
定义:修饰其他函数的工具,修饰添加功能,工具指的是函数,装饰器本身可以是任何可调用对象,被装饰的对象也可以是任意可调用的对象
为什么使用装饰器:
1. 开放封闭原则:对修改是封闭的,对扩展是开放的
2. 装饰器是为了在不修改被装饰对象的源代码及其调用方式的前提下,为其添加更多的功能
无参数装饰器的简单实现
1 import time 2 def timmer(func): 3 def wrapper(): 4 start_time=time.time() 5 func() 6 stop_time=time.time() 7 print(‘run time is %s‘ %(stop_time-start_time)) 8 return wrapper 9 @timmer #index=timmer(index)将他正下方的函数的函数名作为参数传给timer函数,固定只有一个参数,让后再讲timer函数的返回值再重新绑定给index函数 10 def index(): 11 time.sleep(3) 12 print(‘welcome to index‘) 13 index() #实际上已经是wrapper() ---> 已经不是原来的index()函数,指向的内存地址为wrapper函数的内存地址
多参数装饰器的简单实现
1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 res = func(*args,**kwargs) 6 stop_time=time.time() 7 print(‘run time is %s‘ %(stop_time-start_time)) 8 return res 9 return wrapper 10 @timer #index=timmer(index)将他正下方的函数作为参数传入 11 def index(name,age): 12 time.sleep(3) 13 print(‘welcome to index‘) 14 return name,age 15 res = index(‘Albert‘,30) #wrapper() 16 print(res)
多层装饰器嵌套
1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 print(‘====>timmer.wrapper‘) 5 start_time=time.time() 6 res=func(*args,**kwargs) #auth_wrapper 7 stop_time=time.time() 8 print(‘run time is %s‘ %(stop_time-start_time)) 9 return res 10 return wrapper 11 12 login_user = {‘name‘:None,‘status‘:False} 13 def out_auth(driver = ‘file‘): 14 def auth(func): 15 def wrapper(*args,**kwargs): 16 print(‘====>auth.wrapper‘) 17 if driver == ‘file‘: 18 if login_user[‘name‘] and login_user[‘status‘]: 19 res = func(*args,**kwargs) 20 return res 21 else: 22 name = input(‘>>>‘) 23 psw = input(‘>>>‘) 24 if name == ‘Albert‘ and psw ==‘123‘: 25 login_user[‘name‘] = ‘Albert‘ 26 login_user[‘status‘] = True 27 print(‘\033[45mlogin successful\033[0m‘) 28 res = func(*args,**kwargs) 29 return res 30 else: 31 print(‘\033[45mlogin failed\033[0m‘) 32 elif driver == ‘ldap‘: 33 print(‘===========LDAP‘) 34 elif driver == ‘mysql‘: 35 print(‘===========MYSQL‘) 36 return func(*args,**kwargs) 37 else: 38 print(‘===========N/A‘) 39 return wrapper 40 return auth 41 @timer #auth====>index=auth(index)===>index=auth_wrapper 42 @out_auth(driver=‘file‘)#@auth====>index=auth(index)===>index=auth_wrapper 43 def index(): 44 print(‘Welcome to index‘) 45 @out_auth(driver=‘mysql‘) 46 def home(name): 47 print(‘%s welcome to homepage‘ % name) 48 49 index() 50 home(‘Albert‘)
迭代器
1. 迭代的概念:重复+上一次迭代的结果为下一次迭代的初始值
迭代器的优点和缺点
优点:
1.提供了一种不依赖下标的迭代方式
2.就跌迭代器本身来说,更节省内存
缺点:
1. 无法获取迭代器对象的长度
2. 不如序列类型取值灵活,是一次性的,只能往后取值,不能往前退
1 只满足重复,因而不是迭代 2 while True: 3 print(‘====>‘) 4 5 下面才为迭代 6 l = [1, 2, 3] 7 count = 0 8 while count < len(l): 9 print(‘====>‘, l[count]) 10 count += 1 11 12 l = (1, 2, 3) 13 count = 0 14 while count < len(l): 15 print(‘====>‘, l[count]) 16 count += 1 17 18 s=‘hello‘ 19 count = 0 20 while count < len(s): 21 print(‘====>‘, s[count]) 22 count += 1
2. 为什么要有迭代器?
对于没有索引的数据类型,比如字典和集合,必须提供一种不依赖索引的迭代方式
可迭代的对象:凡是内置__iter__方法的,都是可迭代的对象
[1,2].__iter__()
‘hello‘.__iter__()
(1,2).__iter__()
{‘a‘:1,‘b‘:2}.__iter__()
{1,2,3}.__iter__()
3. 如何解决迭代器排除异常的问题?
1 dic={‘a‘:1,‘b‘:2,‘c‘:3} 2 i=dic.__iter__() 3 while True: 4 try: 5 key=i.__next__() 6 print(dic[key]) 7 except StopIteration: 8 break
4. 如何判断一个对象是可迭代的对象,还是迭代器对象?
1 from collections import Iterable,Iterator 2 3 ‘abc‘.__iter__() # 字符串类型 4 ().__iter__() # 元组类型 5 [].__iter__() # 列表类型 6 {‘a‘:1}.__iter__() # 字典类型 7 {1,2}.__iter__() # 集合类型 8 9 f=open(‘a.txt‘,‘w‘) # 文件类型 10 f.__iter__()
5. 下列数据类型都是可迭代的对象
1 print(isinstance(‘abc‘,Iterable)) #True 2 print(isinstance([],Iterable)) # True 3 print(isinstance((),Iterable)) # True 4 print(isinstance({‘a‘:1},Iterable)) # True 5 print(isinstance({1,2},Iterable)) # True 6 print(isinstance(f,Iterable)) # True
6.只有文件是迭代器对象
1 print(isinstance(‘abc‘,Iterator)) # False 2 print(isinstance([],Iterator)) # False 3 print(isinstance((),Iterator)) # False 4 print(isinstance({‘a‘:1},Iterator)) # False 5 print(isinstance({1,2},Iterator)) # False 6 print(isinstance(f,Iterator)) # True
7. 可迭代对象:只有__iter__方法,执行该方法得到的迭代器对象
迭代协议:
对象有__next__
对象有__iter__,对于迭代器对象来说,执行__iter__方法,得到的结果仍然是它本身
1 f1=f.__iter__() 2 print(f) 3 print(f1) 4 print(f is f1) # 对于本身就是迭代器的对象来说,执行__iter__方法,得到的结果仍然是它本身
8. 迭代器工作原理解析
1 dic={‘name‘:‘egon‘,‘age‘:18,‘height‘:‘180‘} 2 print(dic.items()) 3 for k,v in dic.items(): 4 print(k,v) 5 i=iter(dic) 6 while True: 7 try: 8 k=next(i) 9 print(k) 10 except StopIteration: 11 break 12 上边为for循环的基本工作原理 13 14 只要是for循环语句就先会将dic变成一个迭代器,然后通过next方法迭代内部元素 15 for k in dic: #i=iter(dic) k=next(i) 16 print(k) 17 print(dic[k]) 18 for循环不同于while循环,for循环本身就是迭代循环,迭代结束之后自动捕捉异常结束
生成器
1.生成器函数:只要函数体包含yield关键字,该函数就是生成器函数
生成器就是迭代器
yield的功能:
1.相当于为函数封装好__iter__和__next__
2.return只能返回一次值,函数就终止了,而yield能返回多次值,每次返回都会将函数暂停,下一次next会从上一次暂停的位置继续执行
3.yield也可以一次返回多个值,以元组的形式返回
1 使用return的执行效果 2 def foo(): # return只能执行一次,函数就会终止,2,3,4不会显示出来 3 return 1 4 return 2 5 return 3 6 return 4 7 res1=foo() 8 print(res1) 9 res2=foo() 10 print(res2) 11 12 使用yield的执行效果 13 def foo(): 14 print(‘first‘) 15 yield 1 16 print(‘second‘) 17 yield 2 18 print(‘third‘) 19 yield 3 20 print(‘fourth‘) 21 yield 4 22 print(‘fifth‘) 23 24 g=foo() # g其实就是个迭代器,yield将函数变成了迭代器 25 for i in g: 26 print(i) 27 print(g) 28 print(next(g)) #触发迭代器g的执行,进而触发函数的执行 29 print(next(g)) # 迭代器停靠在yield 2 30 print(next(g)) # 迭代器停靠在yield 3 31 print(next(g)) # 迭代器停靠在yield 4 32 print(next(g))
2. 生成器练习一
1 def counter(n): 2 print(‘start...‘) 3 i=0 4 while i < n: 5 yield i 6 i+=1 7 print(‘end...‘) 8 g=counter(5) 9 print(g) 10 print(next(g)) 11 print(next(g)) 12 print(next(g)) 13 print(next(g)) 14 print(next(g)) 15 print(next(g)) # 报出异常
3. 生成器练习二
1 yield实例化使用:模拟管道符功能的实现 2 tail -f a.txt | grep ‘python‘ 3 4 import time 5 def tail(filepath): 6 with open(filepath,encoding=‘utf-8‘) as f: 7 f.seek(0,2) # 直接跳到文件末尾读取文件 8 while True: 9 line=f.readline().strip() 10 if line: 11 yield line 12 else: 13 time.sleep(0.2) 14 15 def grep(pattern,lines): 16 for line in lines: #触发tail函数中的生成器的执行 17 if pattern in line: 18 yield line 19 20 g=grep(‘python‘,tail(‘a.txt‘)) 21 print(g) 22 for i in g: #触发grep函数中的生成器的执行 23 print(i)
内置函数
1 print(abs(-1)) 2 print(all([1,2,3])) # 如果每个元素的布尔值都为True,则all的返回值为True 3 print(all([0,2,3])) # False 4 print(all(‘‘)) # 如果all中的迭代对象为空,也为True 5 6 print(any([0,None,‘‘,1])) # 只要有一个为True,则返回值为True 7 print(any([0,None,‘‘])) # 如果都为False的情况下返回False 8 print(any([])) # 如果any中可迭代对象为空,则返回False 9 10 print(bin(3)) # 将十进制数字转化为二进制 11 print(hex(17)) # 将十进制数字转化为十六进制 12 print(oct(9)) # 将十进制数字转化为八进制 13 14 0 None 空 ---> bool值为False,其余都为True 15 16 callable() 17 def func(): 18 pass 19 print(callable(func)) # 判断是不是可调用对象 20 21 print(chr(68)) # 将括号中数字按照ASCII码表转化为相应的表中字符 22 print(ord(‘D‘)) # 将括号中字符按照ASCII码表转化为相应的表中数字 23 24 res=complex(1+2j) # 复数形式,分为实部和虚部 25 print(res.real) 26 print(res.imag) 27 28 工厂函数(批量产生特定类型的实例) 29 dict 30 int 31 str 32 set 33 list 34 l=[] ---> #l=list([]) 35 list([1,2,3]) 36 list([‘a‘]) 37 list([‘b‘]) 38 39 l=[] 40 print(dir(l)) # 查看一个对象下面的属性 41 print(help(l)) # 查看一个对象的帮助信息 42 43 print(divmod(1000,30)) # 得掉商和余数,通常用于分页显示 44 45 x=range(10) # 不是迭代器,但是一个可迭代对象 46 enumerate([1,2,3]).__next__() # 是迭代器 47 48 cmd=‘print("你瞅啥")‘ 49 eval(cmd) # 将字符串中的命令提取出来执行 50 dic="{‘a‘:1,‘b‘:2}" 51 d=eval(dic) 52 print(type(d),d[‘a‘]) 53 54 with open(‘user.db‘,‘w‘,encoding=‘utf-8‘) as f: 55 user_dic={‘name‘:‘egon‘,‘password‘:‘123‘} 56 f.write(str(user_dic)) 57 58 with open(‘user.db‘,‘r‘,encoding=‘utf-8‘) as f: 59 dic=f.read() 60 print(dic,type(dic)) 61 dic=eval(dic) 62 print(dic[‘name‘]) 63 64 s={1,2} #s=set({1,2}) # 定义可变集合 65 s.add(3) 66 print(s) 67 s=frozenset({1,2}) # 定义不可变集合 68 69 70 哈希: 71 1. 只要校验的内容一致,那hash得到结果永远一样 72 2. 不可逆 73 3. 只要采用的哈希算法一样,那无论被校验的内容有多长,hash的到的结果长度都一样 74 print(hash(‘asdfasdfsadf‘)) 75 print(hash(‘asdfasdfsadf‘)) 76 77 x=1 78 y=x 79 print(id(x),id(y)) 80 print(x is y) # 判断的是身份 81 a=1 82 b=1 83 print(a == b) # 判断的是值 84 85 print(max([1,2,3,4])) 86 print(pow(10,2,3)) 87 88 l=[‘a‘,4,2,3] 89 for i in reversed(l): # 反转列表 90 print(i) 91 print(list(reversed(l))) 92 93 i=reversed(l) 94 for x in i: 95 print(x) 96 print(list(i)) # 列表为空,为什么 97 98 print(round(3.141542653589127134,4)) # 四舍五入取小数点后几位 99 100 l=[‘a‘,‘b‘,‘c‘,‘d‘,‘e‘] 101 print(l[1:4:2]) 102 s=slice(1,4,2) # 切片用,并且可以重复利用 103 print(l[s]) 104 105 vars() # 如果没有参数相当于locals() 106 107 s=‘hello‘ 108 l=[1,2,3,4,5] 109 z=zip(s,l) # 拉链函数 110 print(z) 111 for i in z: 112 print(i) 113 114 import time 115 m=__import__(‘time‘) # 以字符串的形式导入模块 116 m.sleep(3000)
Python自动化开发课堂笔记【Day04】 - Python基础(函数)