一、函数对象
函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性。
那到底什么是第一类对象(First-Class Object)呢?
在 Python 中万物皆为对象,函数也不例外,函数作为对象可以赋值给一个变量、可以作为元素添加到集合对象中、可作为参数值传递给其它函数,还可以当做函数的返回值,这些特性就是第一类对象所特有的。
1.函数身为一个对象,拥有对象模型的三个通用属性:id、类型、和值。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 def foo(): 4 print('from foo') 5 foo() 6 7 print(id(foo)) 8 print(type(foo)) 9 print(foo)
输出
from foo 4406808360 <class 'function'> <function foo at 0x106aa8f28>
2.函数可以被引用,即函数可以赋值给一个变量
还可以把该函数赋值给更多的变量,唯一变化的是该函数对象的引用数不断地增加,本质上这些变量最终指向的都是同一个函数对象。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 def foo(): 4 print('from foo') 5 6 foo() 7 func=foo #引用,赋值 8 print(foo) 9 print(func) 10 func()
输出
from foo <function foo at 0x10eed8f28> <function foo at 0x10eed8f28> from foo
3.函数可以当做参数传递
def foo(): print('from foo') def bar(func): print(func) func() bar(foo)
输出
<function foo at 0x1047eff28> from foo
4.函数可以作返回值
函数接受一个或多个函数作为输入或者函数输出(返回)的值是函数时,我们称这样的函数为高阶函数
def foo(): print('from foo') def bar(func): return func f=bar(foo) print(f) f()
输出
<function foo at 0x107f29f28> from foo
5.函数可以当作容器类型的元素
容器对象(list、dict、set等)中可以存放任何对象,包括整数、字符串,函数也可以作存放到容器对象中
def foo(): print('from foo') dic={'func':foo} foo() print(dic['func']) dic['func']()
输出
from foo <function foo at 0x10997ef28> from foo
6.函数还可以嵌套
函数嵌套的定义
def f1(): def f2(): print('from f2') def f3(): print('from f3') f3() f2() f1()
输出
from f2 from f3
二、命名空间与作用域
命名空间是名字和对象的映射,就像是字典,key是变量名,value是变量的值
1.命名空间的定义
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 #全局命名空间 def func(): money=2000 #非全局 x=2 print('func') print(x) print(func) func()
- 3.局部名称空间:调用函数时会产生局部名称空间,只在函数调用时临时绑定,调用结束解绑定
x=10000 #全局 def func(): x=1 #局部 def f1(): pass
3.作用域
命名空间的可见性就是作用域
- 1. 全局作用域:内置名称空间,全局名称空间
- 2. 局部作用域:局部名称空间
名字的查找顺序:局部名称空间---》全局名层空间---》内置名称空间
查看全局作用域内的名字:gloabls()
查看局部作用域内的名字:locals()
全局作用域的名字:全局有效,在任何位置都能被访问到,除非del删掉,否则会一直存活到文件执行完毕
局部作用域的名字:局部有效,只能在局部范围调用,只在函数调用时才有效,调用结束就失效
x=1000 def func(y): x=2 print(locals()) print(globals()) func(1)
输出
{'y': 1, 'x': 2} {'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10c436c88>, '__package__': None, '__cached__': None, '__file__': '/Users/hexin/PycharmProjects/py3/day4/2.py', 'func': <function func at 0x10c3c9f28>, '__builtins__': <module 'builtins' (built-in)>, '__spec__': None, '__doc__': None, 'time': <module 'time' (built-in)>, '__name__': '__main__', 'x': 1000}
四、闭包函数
简单来说,一个闭包就是你调用了一个函数A,这个函数A返回了一个函数B给你。这个返回的函数B就叫做闭包。
闭包函数须满足以下条件:
1. 定义在内部函数;
2. 包含对外部作用域而非全局作用域的引用;
例
def f1(): x = 1 def f2(): print(x) return f2 f=f1() print(f) x=100 f() print(x)
输出
<function f1.<locals>.f2 at 0x107714400> 1 100
闭包应用
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'))
输出
五、装饰器
1.定义
装饰器:修饰别人的工具,修饰添加功能,工具指的是函数
装饰器本身可以是任何可调用对象,被装饰的对象也可以是任意可调用对象
2.为什么要用装饰器?
开放封闭原则:对修改是封闭的,对扩展是开放的
装饰器就是为了在不修改被装饰对象的源代码以及调用方式的前提下,为其添加新功能
3.装饰器的实现
装饰器的功能是将被装饰的函数当作参数传递给与装饰器对应的函数(名称相同的函数),并返回包装后的被装饰的函数”
直接看示意图,其中 a 为与装饰器 @a 对应的函数, b 为装饰器修饰的函数,装饰器@a的作用是:
简而言之:@a 就是将 b 传递给 a(),并返回新的 b = a(b)
例如
1 def a(name):#与装饰器对应的函数 2 name() 3 4 @a#装饰器 b = a(b) 5 def b():#被装饰函数 6 print('zjl')
输出
zjl
解析过程是这样子的:
1.python 解释器发现@a,就去调用与其对应的函数( a 函数)
2.a 函数调用前要指定一个参数,传入的就是@a下面修饰的函数,也就是 b()
3.a() 函数执行,调用 b(),b() 打印“zjl”
5.装饰器的应用
1 import time 2 3 def timmer(func): 4 def wrapper(): 5 start_time=time.time() 6 func() #index() 7 stop_time=time.time() 8 print('run time is %s' %(stop_time-start_time)) 9 return wrapper 10 11 12 @timmer #index=timmer(index) 13 def index(): 14 time.sleep(1) 15 print('welcome to index') 16 17 index()
输出
welcome to index run time is 1.005241870880127
例子
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 == 'zjl' and password == '123': login_user['user']='hexin' login_user['status']=True print('