一、函数对象
函数(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)
View Code
输出
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()
View Code
输出
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)
输出
View Code
- 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=1000def 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 urlopendef index(url): def get(): return urlopen(url).read() return get oldboy=index('http://crm.oldboyedu.com') print(oldboy().decode('utf-8'))
输出
View Code
五、装饰器
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')
View Code
输出
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()
View Code
输出
welcome to indexrun 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('3[45mlogin successful3[0m')
res=func(*args,**kwargs)
return res
else:
print('3[45mlogin err3[0m')
return wrapper
@auth #index=auth(index)
def index():
print('welcome to index page')
@auth #home=auth(home)
def home(name):
print('%s welcome to home page' %name)
index()
home('zjl')
输出
请输入用户名: zjl请输入密码: 123login err 请输入用户名: zjl 请输入密码: 123 login successful hexin welcome to home page
补充:
装饰器的基本框架:
def timer(func): def wrapper(): func() return wrapper
带参数
def timer(func): def wrapper(*args,**kwargs): func(*args,**kwargs) return wrapper
六、可迭代对象和迭代器
1.迭代的概念
上一次输出的结果为下一次输入的初始值,重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值
注:循环不是迭代
while True: #只满足重复,因而不是迭代 print('====>')
2.可迭代的对象
内置__iter__方法的,都是可迭代的对象。
list是可迭代对象,dict是可迭代对象,set也是可迭代对象。
[1,2].__iter__()'hello'.__iter__()(1,2).__iter__() {'a':1,'b':2}.__iter__() {1,2,3}.__iter__()
例如:
x = [1, 2, 3]y = iter(x)z = iter(x) print(next(y)) print(next(y)) print(next(z)) print(type(x)) print(type(y))
输出
121 <class 'list'> <class 'list_iterator'>
这里x
是一个可迭代对象,y
和z
是两个独立的迭代器,迭代器内部持有一个状态,该状态用于记录当前迭代所在的位置,以方便下次迭代的时候获取正确的元素。
迭代器有一种具体的迭代器类型,比如list_iterator
,set_iterator
。可迭代对象实现了__iter__
方法,该方法返回一个迭代器对象。
3.迭代器
- 1.为什么要有迭代器?
对于没有索引的数据类型,必须提供一种不依赖索引的迭代方式。
- 2.迭代器定义:
迭代器:可迭代对象执行__iter__方法,得到的结果就是迭代器,迭代器对象有__next__方法
它是一个带状态的对象,他能在你调用next()
方法的时候返回容器中的下一个值,任何实现了__iter__
和__next__()
方法的对象都是迭代器,__iter__
返回迭代器自身,__next__
返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常
- 3.迭代器的实现
例:
i=[1,2,3].__iter__() print(i) #迭代器print(i.__next__()) print(i.__next__()) print(i.__next__()) #print(i.__next__()) #抛出异常:StopIteration
输出
<list_iterator object at 0x1019c3eb8>12 3
每次调用next()
方法的时候做两件事:
- 为下一次调用
next()
方法修改状态 - 为当前这次调用生成返回结果
迭代器就像一个懒加载的工厂,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。
- 4.如何判断迭代器对象和可迭代对象
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))
#判断是否为迭代器,只有文件是
print(isinstance('abc',Iterator))
print(isinstance([],Iterator))
print(isinstance((),Iterator))
print(isinstance({'a':1},Iterator))
print(isinstance({1,2},Iterator))
print(isinstance(f,Iterator))
输出
TrueTrueTrue True True True False False False False False True
可迭代对象:只有__iter__方法,执行该方法得到的迭代器对象
迭代器:有__iter__
和__next__()
方法
注:对于迭代器对象来说,执行__iter__方法,得到的结果仍然是它本身
- 5.迭代器的优点和缺点
优点:
1.提供了一种不依赖下标的迭代方式
2.就跌迭代器本身来说,更节省内存
缺点:
1. 无法获取迭代器对象的长度
2. 不如序列类型取值灵活,是一次性的,只能往后取值,不能往前退
七、内置函数
简单来说就是python3本身就自带的函数。
- abs(x)
abs()返回一个数字的绝对值。如果给出复数,返回值就是该复数的模
print(abs(-1100))
输出:1100
- all()
如果iterable的所有元素不为0、''、False或者iterable为空,all(iterable)返回True,否则返回False;
print(all(['a', 'b', 'c', 'd'])) #列表list,元素都不为空或0
print(all(['a', 'b', '', 'd'])) #列表list,存在一个为空的元素
print(all([0,1,2,3])) #列表list,存在一个为0的元素
print(all(('a', 'b', 'c', 'd'))) #元组tuple,元素都不为空或0
print(all(('a', 'b', '', 'd'))) #元组tuple,存在一个为空的元素
print(all((0,1,2,3))) #元组tuple,存在一个为0的元素
print(all([])) # 空列表
print(all(())) # 空元组
TrueFalseFalse True False False True True
注意:空元组、空列表返回值为True,这里要特别注意
- any()
如果所有元素中有一个值非0、''或False,那么结果就为True,当iterable所有的值都是0、''或False时,那么结果为False,
print(any(['a', 'b', 'c', 'd'])) #列表list,元素都不为空或0print(any(['a', 'b', '', 'd'])) #列表list,存在一个为空的元素print(any([0,1,2,3])) #列表list,存在一个为0的元素 print(any(('a', 'b', 'c', 'd'))) #元组tuple,元素都不为空或0 print(any(('a', 'b', '', 'd'))) #元组tuple,存在一个为空的元素 print(any((0,1,2,3))) #元组tuple,存在一个为0的元素 print(any([])) # 空列表 print(any(())) # 空元组
TrueTrueTrue True True True False False
- ascii()
调用对象的__repr__()方法,获得该方法的返回值.
print(ascii([1,2,3,1,22,123])) #[1, 2, 3, 1, 22, 123]
- bin()
三个函数功能为:将十进制数分别转换为2进制。
print(bin(10)) #0b1010
- bool()
测试一个对象是True还是False.
print(bool([])) #False
- bytes()
将一个字符串转换成字节类型
s="apple"v=bytes(s,encoding="utf-8")print(v) #b'apple'
- callable(object)
callable()函数用于测试对象是否可调用,如果可以则返回1(真);否则返回0(假)。可调用对象包括函数、方法、代码对象、类和已经定义了 调用 方法的类实例。
a = '123'print(callable(a)) #False
- chr(i)
chr()函数返回ASCII码对应的字符串。
print(chr(65)) #A
- complex(real[,imaginary])
complex()函数可把字符串或数字转换为复数。
print(complex(2,1)) #(2+1j)
- delattr()
删除对象的属性
- dict()
创建数据字典
print(dict()) #{}
- dir()
不带参数时返回当前范围内的变量,方法和定义的类型列表,带参数时返回参数的属性,方法列表
print(dir())
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'time']
- divmod(x,y)
divmod(x,y)函数完成除法运算,返回商和余数。
print(divmod(10,3)) #(3, 1)
- enumerate()
返回一个可以枚举的对象,该对象的next()方法将返回一个元组
s = ["a","b","c"]for i ,v in enumerate(s,1): print(i,v)
1 a2 b3 c
- eval()
将字符串str当成有效的表达式来求值并返回计算结果
s = "1 + 3 +5"print(eval(s)) #9
- exec()
执行字符串或complie方法编译过的字符串,没有返回值
- float(x)
float()函数把一个数字或字符串转换成浮点数。
print(float("12")) #12.0
- format()
格式化输出字符串
print("i am {0},age{1}".format("tom",18))
i am tom,age18
- frozenset()
创建一个不可修改的集合
set
和
frozenset
最本质的区别是前者是可变的,后者是不可变的。当集合对象会被改变时(例如删除,添加元素),只能使用
set
,
一般来说使用fronzet的地方都可以使用
set
。
参数iterable:可迭代对象。
- globals()
返回一个描述当前全局变量的字典
a = "apple"print(globals())
{'__package__': None, '__file__': '/Users/hexin/PycharmProjects/py3/day4/2.py', '__name__': '__main__', 'a': 'apple', 'time': <module 'time' (built-in)>, '__cached__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10bd73c88>, '__builtins__': <module 'builtins' (built-in)>, '__spec__': None, '__doc__': None}
- hash()
哈希值hash
(
object
)注意:可哈希的即不可变数据类型,不可哈希即可变数据类型
如果对象
object
为哈希表类型,返回对象
object
的哈希值。哈希值为整数,在字典查找中,哈希值用于快递比价字典的键。
两个数值如果相等,则哈希值也相等。
- help()
返回对象的帮助文档
调用内建的帮助系统,如果不包含参数,交互式帮助系统将在控制台启动。如果参数为字串,则可以是模块,类,方法等名称,并且帮助页面将会在控制台打印。参数也可以为任意对象
- hex(x)
hex()函数可把整数转换成十六进制数。
print(hex(12)) #0xc
- id()
返回对象的内存地址
a = "apple"print(id(a)) #4562197840
- input()
获取用户输入内容
- int(x[,base])
int()函数把数字和字符串转换成一个整数,base为可选的基数。
- iter()
返回一个iterator对象。
- len()函数返回字符串和序列的长度。
print(len('aa')) #2
- list(x)
list()函数可将序列对象转换成列表。
print(list("hello world"))
['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
- locals()
打印当前可用的局部变量的字典
- max(x[,y,z...])
max()函数返回给定参数的最大值,参数可以为序列。
print(max(1,2,3,4)) #4
- min(x[,y,z...])
min()函数返回给定参数的最小值,参数可以为序列。
print(min(1,2,3,4)) #1
- next()
返回一个可迭代数据结构(如列表)中的下一项
- object()
获取一个新的,无特性(geatureless)对象。
Object
是所有类的基类。它提供的方法将在所有的类型实例中共享。
- oct(x)
oct()函数可把给出的整数转换成八进制数。
print(oct(12)) #0o14
- ord(x)
ord()函数返回一个字符串参数的ASCII码或Unicode值。
print(ord("a")) #97
- open()
打开文件open
(filename [, mode [, bufsize]])
打开一个文件,返回一个
file
对象。 如果文件无法打开,将处罚IOError异常
- pow(x,y[,z])
pow()函数返回以x为底,y为指数的幂。如果给出z值,该函数就计算x的y次幂值被z取模的值。
print(pow(2,5)) #32print(pow(2,5,3)) #2
- range([lower,]stop[,step])
range()函数可按参数生成连续的有序整数列表。
print(range(1,10,2)) #range(1, 10, 2)
- repr()
将任意值转换为字符串,供计时器读取的形式
- reversed()
反转,逆序对象
- round(x[,n])
round()函数返回浮点数x的四舍五入值,如给出n值,则代表舍入到小数点后的位数。
print(round(5.9)) #6
- set()
将对象转换成集合
- slice()
切片功能
s = ["a","b""c","d"]print(slice(1,3,s))
slice(1, 3, ['a', 'bc', 'd'])
- sorted()
排序
列表排序,按数轴方向排,高阶函数,以绝对值大小排序,字符串排序,按照ASCII的大小排序,如果需要排序的是一个元组,则需要使用参数key,也就是关键字。反向排序,reserve=True
- str(obj)
str()函数把对象转换成可打印字符串。
print(str(4)) #4
- sum()
求和
- tuple(x)
tuple()函数把序列对象转换成tuple。
print(tuple("hello world"))
('h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd')
- type(obj)
type()函数可返回对象的数据类型。
print(type('123'))print(type(1))
<class 'str'><class 'int'>
- vars()
本函数是实现返回对象object的属性和属性值的字典对象。如果默认不输入参数,就打印当前调用位置的属性和属性值,相当于locals()的功能。如果有参数输入,就只打印这个参数相应的属性和属性值。
print(vars())#{'__name__': '__main__', '__spec__': None, '__package__': None, '__builtins__': <module 'builtins' (built-in)>, 'time': <module 'time' (built-in)>, '__cached__': None, '__doc__': None, '__file__': '/Users/hexin/PycharmProjects/py3/day4/2.py', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10e5f3c88>}
print(vars(time))
View Code
- zip()
将对象逐一配对
s='helloo'l=[1,2,3,4,5]z=zip(s,l)print(z)
for i in z:
print(i)
<zip object at 0x1051d1608>('h', 1)('e', 2)('l', 3)
('l', 4)
('o', 5)