Python编程-函数进阶
一、函数对象
函数是第一类对象,即函数可以当作数据传递
1 可以被引用
2 可以当作参数传递
3 返回值可以是函数
4 可以当作容器类型的元素
def foo():
print('from foo')
func=foo #将函数赋值给func
print(foo) #打印函数,将返回函数在内存中的地址
print(func) #此时func = foo
func() #加上大括号才能引用函数
运行结果:
<function foo at 0x00000000007E00D0>
<function foo at 0x00000000007E00D0>
from foo
def foo():
print('from foo')
def bar(foo): #给函数bar一个参数foo
print(foo) #打印foo,其实就是打印foo函数在内存中的地址
foo() #引用foo函数
bar(foo)
运行结果:
<function foo at 0x00000000006D00D0>
from foo
def foo():
print('from foo')
def bar(foo):
return foo #返回值是foo函数在内存中的地址
f=bar(foo)
print(f) #取bar函数的返回值
f()
运行结果:
<function foo at 0x0000000000D700D0>
from foo
def foo():
print('from foo')
dic={'func':foo}
print(dic['func']) #打印字典key名为func的值foo,也就是foo函数在内存中的地址
dic['func']() #调用foo函数
运行结果:
<function foo at 0x00000000007C00D0>
from foo
应用
def select(sql):
print('========>select')
def insert(sql):
print('========>add')
def delete(sql):
print('=======>delete')
def update(sql):
print('-=---->update')
func_dic={
'select':select,
'update':update,
'insert':insert,
'delete':delete
}
def main():
while True:
sql = input('>>: ').strip()
if not sql:continue
l = sql.split()
cmd=l[0]
if cmd in func_dic:
func_dic[cmd](l)
main()
def main():
sql = input('>>: ')
l = sql.split()
print(l)
if l[0] == 'select':
select(l)
elif l[0] == 'insert':
insert(l)
elif l[0] == 'delete':
delete(l)
elif l[0] == 'update':
update(l)
二、函数的嵌套
1.函数的嵌套调用
def max2(x,y): #取最大值
return x if x > y else y
def max4(a,b,c,d):
res1=max2(a,b) #两两比较,取最大值
res2=max2(res1,c)
res3=max2(res2,d)
return res3
print(max4(10,99,31,22))
运行结果:
99
name = "Alex"
def change_name(): #先调用这层
name = "Alex2"
def change_name2(): #再调用这层
name = "Alex3"
print("第3层打印", name)
change_name2() # 调用内层函数
print("第2层打印", name)
change_name()
print("最外层打印", name) #最后到这层
运行结果:
第3层打印 Alex3
第2层打印 Alex2
最外层打印 Alex
2.函数的嵌套定义
注意:定义函数在运行程序时不会执行,仅判断语法是否有错误
def f1():
def f2():
print('from f2')
def f3():
print('from f3')
f3()
f2()
f1()
运行结果:
from f2
from f3
三、名称空间与作用域
1.定义名字的方法
import time
name='egon'
def func():
pass
class Foo:
pass
2.三种名称空间
(1)内置名称空间
随着python解释器的启动而产生,內建函数属于内置名称空间内
print(sum)
print(max)
print(min)
print(max([1,2,3]))
import builtins
for i in dir(builtins): #查看內建函数
print(i)
(2)全局名称空间
文件的执行会产生全局名称空间,指的是文件级别定义的名字都会放入该空间
x=1
if x ==1 :
y=2
import time
name='egon'
def func():
pass
class Foo:
pass
x=1
def func():
money=2000
x=2
print('func')
print(x)
print(func)
func()
print(money) #money属于func函数内的局部命名空间
func()
print(x)
报错信息:
Traceback (most recent call last):
1
File "E:/s17/day04/名称空间与作用域.py", line 59, in <module>
print(money)
<function func at 0x00000000007B00D0>
NameError: name 'money' is not defined
func
(3)局部名称空间
调用函数时会产生局部名称空间,只在函数调用时临时绑定,调用结束解绑定
x=10000 #全局
def func():
x=1 #局部
def f1():
pass
3.作用域
(1)全局作用域:内置名称空间,全局名层空间
(2)局部作用:局部名称空间
名字的查找顺序:局部名称空间---》全局名层空间---》内置名称空间
x=1
def func():
x=2
print(x)
sum=123123
print(sum)
func()
运行结果:
2
123123
def func():
x=2
func()
print(x) #此时调用不到x
报错信息:
Traceback (most recent call last):
File "E:/s17/day04/名称空间与作用域.py", line 94, in <module>
print(x)
NameError: name 'x' is not defined
查看全局作用域内的名字:gloabls()
查看局局作用域内的名字:locals()
x=1000
def func():
x=2
print(globals())
print(locals())
print(globals() is locals())
运行结果:
{'func': <function func at 0x00000000007D00D0>, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000000626DA0>, '__spec__': None, 'x': 1000, '__cached__': None, '__doc__': '\n作用域:\n 1. 全局作用域:内置名称空间,全局名层空间\n 2. 局部作用:局部名称空间\n', '__builtins__': <module 'builtins' (built-in)>, '__package__': None, '__file__': 'E:/s17/day04/名称空间与作用域.py', '__name__': '__main__'}
{'func': <function func at 0x00000000007D00D0>, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000000626DA0>, '__spec__': None, 'x': 1000, '__cached__': None, '__doc__': '\n作用域:\n 1. 全局作用域:内置名称空间,全局名层空间\n 2. 局部作用:局部名称空间\n', '__builtins__': <module 'builtins' (built-in)>, '__package__': None, '__file__': 'E:/s17/day04/名称空间与作用域.py', '__name__': '__main__'}
True
x=1000
def func(y):
x=2
print(locals())
print(globals())
func(1)
运行结果:
{'y': 1, 'x': 2}
{'__file__': 'E:/s17/day04/名称空间与作用域.py', '__doc__': '\n作用域:\n 1. 全局作用域:内置名称空间,全局名层空间\n 2. 局部作用:局部名称空间\n', '__package__': None, 'func': <function func at 0x00000000007E00D0>, '__name__': '__main__', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000000646DA0>, '__builtins__': <module 'builtins' (built-in)>, 'x': 1000, '__cached__': None, '__spec__': None}
全局作用域:全局有效,在任何位置都能被访问到,除非del删掉,否则会一直存活到文件执行完毕
局部作用域的名字:局部有效,只能在局部范围调用,只在函数调用时才有效,调用结束就失效
x=1
def f1():
print(x)
def foo():
print(x)
def f(x):
# x=4
def f2():
# x=3
def f3():
# x=2
print(x)
f3()
f2()
f(4)
运行结果:
4
四、闭包
- 定义在内部函数
- 包含对外部作用域而非全局作用域的引用,该内部函数就成为闭包函数
def f1():
x = 1
def f2():
print(x)
return f2
f=f1()
print(f)
x=100000000000000000000000000
f()
运行结果:
<function f1.<locals>.f2 at 0x00000000006B01E0>
1
闭包应用:惰性计算
抓取网页
from urllib.request import urlopen
def index(url):
def get():
return urlopen(url).read()
return get
oldboy=index('http://crm.oldboyedu.com')
print(oldboy().decode('utf-8'))
print(oldboy.__closure__[0].cell_contents)
res=urlopen('http://crm.oldboyedu.com').read()
print(res.decode('utf-8'))
x=1
y=2
def f1():
x=1
y=2
def f2():
print(x,y)
return f2
f=f1()
print(f.__closure__[0].cell_contents)
运行结果:
1
五、装饰器
装饰器:修饰别人的工具,修饰添加功能,工具指的是函数
装饰器本身可以是任何可调用对象,被装饰的对象也可以是任意可调用对象
为什么要用装饰器:
- 开放封闭原则:对修改是封闭的,对扩展是开放的
- 装饰器就是为了在不修改被装饰对象的源代码以及调用方式的前提下,为期添加新功能
在修改代码时,为了不对源代码产生影响而使用装饰器
import time
def timmer(func): #增加执行时间计算
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return wrapper
@timmer #对源代码进行装饰,index=timmer(index)
def index():
time.sleep(3)
print('welcome to index')
f=timmer(index)
print(f)
f() #wrapper()---->index()
index=timmer(index) #index==wrapper
index() #wrapper()----->
流程分析
import time
def timmer(func):
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
return wrapper
@timmer #装饰器 index=timmer(index)
def index():
time.sleep(3)
print('welcome to index')
return 1
@timmer
def foo(name):
time.sleep(1)
print('from foo')
res=index() #wrapper()
print(res)
res1=foo('egon') #res1=wrapper('egon')
print(res1)
运行结果:
welcome to index
run time is 3.012805223464966
1
from foo
run time is 1.0140018463134766
None
应用
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('>>: ')
password=input('>>: ')
if name == 'egon' and password == '123':
login_user['user']='egon'
login_user['status']=True
print('\033[45mlogin successful\033[0m')
res=func(*args,**kwargs)
return res
else:
print('\033[45mlogin err\033[0m')
return wrapper
@auth
def index():
print('welcome to index page')
@auth
def home(name):
print('%s welcome to home page' %name)
index()
home('egon')
有参装饰器
import time
def timmer(func):
def wrapper(*args,**kwargs):
print('====>timmer.wrapper')
start_time=time.time()
res=func(*args,**kwargs) #auth_wrapper
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
return wrapper
login_user={'user':None,'status':False}
def auth(driver='file'):
def auth2(func):
def wrapper(*args,**kwargs):
print('=======>auth.wrapper')
time.sleep(5)
if driver == 'file':
if login_user['user'] and login_user['status']:
res=func(*args,**kwargs)
return res
else:
name=input('>>: ')
password=input('>>: ')
if name == 'egon' and password == '123':
login_user['user']='egon'
login_user['status']=True
print('\033[45mlogin successful\033[0m')
res=func(*args,**kwargs)
return res
else:
print('\033[45mlogin err\033[0m')
elif driver == 'ldap':
print('==========ldap的认证')
elif driver == 'mysql':
print('==========mysql的认证')
return func(*args,**kwargs)
else:
print('=========未知的认证来源')
return wrapper
return auth2
@auth('file') #@auth2====>index=auth2(index)===>index=auth_wrapper
@timmer #index=timmer(auth_wrapper) #index=timmer_wrapper
def index():
time.sleep(3)
print('welcome to index page')
@auth(driver='mysql')
def home(name):
print('%s welcome to home page' %name)
index() #timmer_wrapper()
home('egon') #wrapper('egon')
六、迭代器
迭代的概念:重复+上一次迭代的结果为下一次迭代的初始值,重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件
特点:
- 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
- 不能随机访问集合中的某个值 ,只能从头到尾依次访问
- 访问到一半时不能往回退
- 便于循环比较大的数据集合,节省内存
while True: #只满足重复,因而不是迭代
print('====>')
真正的迭代如下:
l = [1, 2, 3]
count = 0
while count < len(l):
print('====>', l[count])
count += 1
l = (1, 2, 3)
count = 0
while count < len(l):
print('====>', l[count])
count += 1
s='hello'
count = 0
while count < len(s):
print('====>', s[count])
count += 1
为什么要有迭代器?对于没有索引的数据类型,必须提供一种不依赖索引的迭代方式
可迭代的对象:内置__iter__方法的,都是可迭代的对象
[1,2].__iter__()
'hello'.__iter__()
(1,2).__iter__()
{'a':1,'b':2}.__iter__()
{1,2,3}.__iter__()
迭代器:执行__iter__方法,得到的结果就是迭代器,迭代器对象有__next__方法
i=[1,2,3].__iter__()
print(i)
print(i.__next__())
print(i.__next__())
print(i.__next__())
print(i.__next__()) #抛出异常:StopIteration
dic={'a':1,'b':2,'c':3}
i=dic.__iter__()
while True:
try:
key=i.__next__()
print(dic[key])
except StopIteration:
break
如何判断一个对象是可迭代的对象,还是迭代器对象
from collections import Iterable,Iterator
'abc'.iter()
().iter()
[].iter()
{'a':1}.iter()
{1,2}.iter()
f=open('a.txt','w')
f.iter()
下列数据类型都是可迭代的对象,只有文件是迭代器对象
print(isinstance('abc',Iterable))
print(isinstance([],Iterable))
print(isinstance((),Iterable))
print(isinstance({'a':1},Iterable))
print(isinstance({1,2},Iterable))
print(isinstance(f,Iterable))
可迭代对象:只有__iter__方法,执行该方法得到的迭代器对象
迭代协议:
- 对象有__next__
- 对象有__iter__,对于迭代器对象来说,执行__iter__方法,得到的结果仍然是它本身
迭代器的优点和缺点
优点:
- 提供了一种不依赖下标的迭代方式
- 就跌迭代器本身来说,更节省内存
缺点:
- 无法获取迭代器对象的长度
- 不如序列类型取值灵活,是一次性的,只能往后取值,不能往前退
七、生成器
生成器函数:只要函数体包含yield关键字,该函数就是生成器函数
生成器就是迭代器
一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator);如果函数中包含yield语法,那这个函数就会变成生成器;
def func():
yield 1
yield 2
yield 3
yield 4
上述代码中:func是函数称为生成器,当执行此函数func()时会得到一个迭代器。
运行结果:
>>> temp = func()
>>> temp.__next__()
1
>>> temp.__next__()
2
>>> temp.__next__()
3
>>> temp.__next__()
4
>>> temp.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
def foo():
print('first')
yield 1
print('second')
yield 2
print('third')
yield 3
print('fourth')
yield 4
print('fifth')
g=foo()
for i in g:
print(i)
print(next(g)) #触发迭代器g的执行,进而触发函数的执行
运行结果:
first
1
second
2
third
3
fourth
4
fifth
yield的功能:
- 相当于为函数封装好__iter__和__next__
- return只能返回一次值,函数就终止了,而yield能返回多次值,每次返回都会将函数暂停,下一次next会从上一次暂停的位置继续执行
应用:tail -f a.txt | grep 'python'
import time
def tail(filepath):
with open(filepath,encoding='utf-8') as f:
f.seek(0,2)
while True:
line=f.readline().strip()
if line:
yield line
else:
time.sleep(0.2)
t=tail('a.txt')
for line in t:
print(line)
def grep(pattern,lines):
for line in lines:
if pattern in line:
yield line
g=grep('python',tail('a.txt'))
print(g)
for i in g:
print(i)
八、递归
在函数内部,可以调用其他函数。如果在调用一个函数的过程中直接或间接调用自身本身
def calc(n):
print(n)
if int(n/2) ==0:
return n
return calc(int(n/2))
calc(10)
运行结果:
10
5
2
1
应用:递归问路
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
import time
person_list=['alex','wupeiqi','yuanhao','linhaifeng']
def ask_way(person_list):
print('-'*60)
if len(person_list) == 0:
return '没人知道'
person=person_list.pop(0)
if person == 'linhaifeng':
return '%s说:我知道,老男孩就在沙河汇德商厦,下地铁就是' %person
print('hi 美男[%s],敢问路在何方' %person)
print('%s回答道:我不知道,但念你慧眼识猪,你等着,我帮你问问%s...' %(person,person_list))
time.sleep(3)
res=ask_way(person_list)
# print('%s问的结果是: %res' %(person,res))
return res
res=ask_way(person_list)
print(res)
递归特性:
必须有一个明确的结束条件
每次进入更深一层递归时,问题规模相比上次递归都应有所减少
递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
九、内置函数
内置参数详解 https://docs.python.org/3/library/functions.html?highlight=built#ascii
Python编程-函数进阶的更多相关文章
- Python编程-函数进阶二
一.生成器补充 1.什么是生成器? 可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象. 2.生成器分类 (1) ...
- 【转】Python之函数进阶
[转]Python之函数进阶 本节内容 上一篇中介绍了Python中函数的定义.函数的调用.函数的参数以及变量的作用域等内容,现在来说下函数的一些高级特性: 递归函数 嵌套函数与闭包 匿名函数 高阶函 ...
- Python之函数进阶
本节内容 上一篇中介绍了Python中函数的定义.函数的调用.函数的参数以及变量的作用域等内容,现在来说下函数的一些高级特性: 递归函数 嵌套函数与闭包 匿名函数 高阶函数 内置函数 总结 一.递归函 ...
- 《Python》 函数进阶和名称空间作用域
函数进阶: 一.动态参数:*args **kwargs *args是元祖形式,接收除去键值对以外的所有参数 # args可以换成任意变量名,约定俗成用args **kwargs接收的只是键值对的参数 ...
- 10.Python初窥门径(函数进阶)
Python(函数进阶) 一.函数的传参(接上期) 形参角度(一共四种,后两种) 动态参数(万能参数)* # 定义一个函数时,*所有的位置参数聚合到一个元组中 def func(*args): # * ...
- python开发函数进阶:生成器表达式&各种推导式
一,生成器表达式 #生成器表达式比列表解析更省内存,因为惰性运算 #!/usr/bin/env python #_*_coding:utf-8_*_ new_2 = (i*i for i in ran ...
- day09 python之函数进阶
楔子 假如有一个函数,实现返回两个数中的较大值: def my_max(x,y): m = x if x>y else y return mbigger = my_max(10,20)print ...
- Python入门-函数进阶
昨天我们简单的了解了函数的定义,调用,以及传参,其实还有一个更重要的传参:动态传参,让我们继续昨天没有说完的,以及今天我要分享的东西. 一.动态传参 之前我们说过了传参,如果我们需要给一个函数传参,而 ...
- python学习——函数进阶
首先来看下面这个函数. def func(x,y): bigger = x if x > y else y return bigger ret = func(10,20) print(ret) ...
随机推荐
- Linux 文件管理(C语言库函数三)
找到当前目录 char *getcwd(char * buf,size_t size) getcwd函数把当前工作目录的绝对路径名复制到buf中,size指示buf的大小 如果buf不够大,不能装下整 ...
- 设计模式之备忘录模式(Memento)
备忘录模式(Memento) 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. Originator(发起人):负责创建一个备忘录 ...
- POJ 1848 Tree
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 3506 Accepted: 1204 Description ...
- APP https抓包
一.软件准备 charles 安卓模拟器(windows系统用逍遥模拟器,mac os 用夜神安卓模拟器) Xposed的apk安装包(安装到模拟器上),地址:http://repo.xposed.i ...
- CodeIgniter框架——知识要点汇总
NO1.学习要点: 一.CodeIgniter 框架的简介 二.CodeIgniter 框架的安装 三.CodeIgniter 框架的目录结构分析 四.CodeIgniter 框架是如何工作的? 五. ...
- 【BZOJ3209】花神的数论题 数位DP
[BZOJ3209]花神的数论题 Description 背景众所周知,花神多年来凭借无边的神力狂虐各大 OJ.OI.CF.TC …… 当然也包括 CH 啦.描述话说花神这天又来讲课了.课后照例有超级 ...
- SharePoint 2013 安装.net framework 4.5已经存在更高版本的解决方案
请参考: https://support.microsoft.com/en-us/help/3087184/sharepoint-2013-or-project-server-2013-setup-e ...
- form表单提交中文乱码(前台中文到JAVA后台乱码)问题及解决
form表单提交中文乱码(前台中文到JAVA后台乱码)问题及解决 一.问题: 页面输入框中的中文内容,在后台乱码,导致搜索功能失效:(详细可以见后面的重现) 二.原因: 浏览器对于数据的默认编码格式为 ...
- Maven + Jetty 部署锁文件解决办法
用Maven + Jetty 在Eclipse环境启动后,改静态文件的时候出现如下提示 就表示文件被锁住了. 解决办法如下: <plugin> <groupId>org.ecl ...
- cmake编译选项
1 需求 现在已经有一个cmake工程,我想要添加-O0 -g,生成gdb的调试信息和不进行代码优化. 也就是说,我该怎样修改CFLAGS和CPPFLAGS? 2 在project后面添加 set(C ...