day4 函数对象 函数嵌套 名称空间与作用域 闭包函数 装饰器 迭代器 生成器 内置函数
一、函数对象
1 可以被引用
2 可以当作参数传递
3 返回值可以是函数
3 可以当作容器类型的元素
def foo(): print('from foo') func=foo print(foo) print(func) func() 输出结果如下: <function foo at 0x00000000026220D0> <function foo at 0x00000000026220D0> from foo
二、函数嵌套
python允许在定义函数的时候,其函数体内又包含另外一个函数的完整定义,这就是我们通常所说的嵌套定义。为什么?因为函数是用def语句定义的,凡是其他语句可以出现的地方,def语句同样可以出现。
像这样定义在其他函数内的函数叫做内部函数,内部函数所在的函数叫做外部函数。当然,我们可以多层嵌套,这样的话,除了最外层和最内层的函数之外,其它函数既是外部函数又是内部函数。#函数的嵌套定义
def f1(): def f2(): print('from f2') def f3(): print('from f3') f3() f2() f1()
输出结果如下:
from f2
from f3
三、名称空间与作用域
三种名称空间:
内置名称空间:随着python解释器的启动而产生。
print(sum) print(max) print(min) 输出结果如下: <built-in function sum> <built-in function max> <built-in function min>
dir()函数接受模块名作为参数,返回一个排好序的字符串列表,内容是一个模块里定义过的名字。便获得了内建模块里定义的名字: import builtins for i in dir(builtins): print(i) 输出结果: ArithmeticError AssertionError AttributeError BaseException BlockingIOError BrokenPipeError BufferError BytesWarning ChildProcessError ConnectionAbortedError ConnectionError ConnectionRefusedError ConnectionResetError DeprecationWarning EOFError Ellipsis EnvironmentError Exception False FileExistsError FileNotFoundError FloatingPointError FutureWarning GeneratorExit IOError ImportError ImportWarning IndentationError IndexError InterruptedError IsADirectoryError KeyError KeyboardInterrupt LookupError MemoryError ModuleNotFoundError NameError None NotADirectoryError NotImplemented NotImplementedError OSError OverflowError PendingDeprecationWarning PermissionError ProcessLookupError RecursionError ReferenceError ResourceWarning RuntimeError RuntimeWarning StopAsyncIteration StopIteration SyntaxError SyntaxWarning SystemError SystemExit TabError TimeoutError True TypeError UnboundLocalError UnicodeDecodeError UnicodeEncodeError UnicodeError UnicodeTranslateError UnicodeWarning UserWarning ValueError Warning WindowsError ZeroDivisionError __build_class__ __debug__ __doc__ __import__ __loader__ __name__ __package__ __spec__ abs all any ascii bin bool bytearray bytes callable chr classmethod compile complex copyright credits delattr dict dir divmod enumerate eval exec exit filter float format frozenset getattr globals hasattr hash help hex id input int isinstance issubclass iter len license list locals map max memoryview min next object oct open ord pow print property quit range repr reversed round set setattr slice sorted staticmethod str sum super tuple type vars zip
全局名称空间:文件的执行会产生全局名称空间,指的是文件级别定义的名字都会放入该空间
x=1 def func(): money=2000 x=2 print('func') print(x) print(func) func() print(money) 输出结果如下: 1 <function func at 0x0000000002493E18> func Traceback (most recent call last): File "D:/py17/day4/名称空间与作用域.py", line 59, in <module> print(money) NameError: name 'money' is not defined
作用域:
1. 全局作用域:内置名称空间,全局名层空间
2. 局部作用:局部名称空间
名字的查找顺序:局部名称空间---》全局名层空间---》内置名称空间
x=1 def func(): x=2 print(x) sum=123123 print(sum) func() 输出结果: 2 123123
查看全局作用域内的名字:gloabls()
查看局局作用域内的名字:locals()
x=1000 def func(y): x=2 print(locals()) print(globals()) func(1) 输出结果: {'x': 2, 'y': 1} {'__name__': '__main__', '__doc__': '\n作用域:\n 1. 全局作用域:内置名称空间,全局名层空间\n 2. 局部作用:局部名称空间\n', '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000002566828>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/py17/day4/名称空间与作用域.py', '__cached__': None, 'x': 1000, 'func': <function func at 0x0000000002153E18>}
全局作用域:全局有效,在任何位置都能被访问到,除非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
四、闭包函数
1. 定义在内部函数
2. 包含对外部作用域而非全局作用域的引用,
3.该内部函数就成为闭包函数
def f1(): x = 1 def f2(): print(x) return f2
闭包应用:惰性计算
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'))
五、装饰器
定义:本质是函数,(装饰其他函数),就是为其他函数添加附加功能。
原则:1. 不能修改被装饰的函数的源代码。
2. 不能修改被装饰的函数的调用方式。
实现装饰器知识储备:
1. 函数即'变量'
2.高阶函数
a. 把一个函数名当做实参传递给另外一个函数(在不修改被装饰函数的源代码的情况下为其添加功能)
b. 返回值中包含函数名
3. 嵌套函数
高阶函数 + 嵌套函数 =》 装饰器
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 def index(): time.sleep(3) print('welcome to index') index() 输出结果: welcome to index run time is 3.000171422958374
六、迭代器
迭代的概念: 重复+上一次迭代的结果为下一次迭代的初始值。
重复的过程称为迭代,每次重复即一次迭代,
并且每次迭代的结果是下一次迭代的初始值。
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 输出结果: <list_iterator object at 0x000000000261AFD0> 1 2 3 Traceback (most recent call last): File "D:/py17/day4/迭代器.py", line 57, in <module> print(i.__next__()) #抛出异常:StopIteration StopIteration
i={'a':1,'b':2,'c':3}.__iter__()
--------------------------------------------------
print(i.__next__())
print(i.__next__())
print(i.__next__())
print(i.__next__())
输出结果:
Traceback (most recent call last):
File "D:/py17/day4/迭代器.py", line 65, in <module>
print(i.__next__())
StopIteration
a
b
c
-----------------------------------------------------------------------
dic={'a':1,'b':2,'c':3}
i=dic.__iter__()
while True:
try:
key=i.__next__()
print(dic[key])
except StopIteration:
break
输出结果:
1
2
3
------------------------------------------------------------------------
s={'a',3,2,4}
s.__iter__() #iter(s)
i=iter(s)
print(next(i))
print(next(i))
print(next(i))
print(next(i))
#print(next(i))
输出结果:
2
a
3
4
-------------------------------------------------- print(i.__next__()) print(i.__next__()) print(i.__next__()) print(i.__next__()) 输出结果: Traceback (most recent call last): File "D:/py17/day4/迭代器.py", line 65, in <module> print(i.__next__()) StopIteration a b c ----------------------------------------------------------------------- dic={'a':1,'b':2,'c':3} i=dic.__iter__() while True: try: key=i.__next__() print(dic[key]) except StopIteration: break 输出结果: 1 2 3 ------------------------------------------------------------------------ s={'a',3,2,4} s.__iter__() #iter(s) i=iter(s) print(next(i)) print(next(i)) print(next(i)) print(next(i)) #print(next(i)) 输出结果: 2 a 3 4
判断是不是可以迭代,用Iterable
判断是不是迭代器,用Iterator
在Python中可以使用type()与isinstance()这两个函数判断对象类型,而isinstance()函数的使用上比type更加方便。
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))
输出结果:
True
True
True
True
True
True
----------------------------------------------------------------------------------
#只有文件是迭代器对象
print(isinstance('abc',Iterator))
print(isinstance([],Iterator))
print(isinstance((),Iterator))
print(isinstance({'a':1},Iterator))
print(isinstance({1,2},Iterator))
print(isinstance(f,Iterator))
输出结果:
False
False
False
False
False
True
生成器
生成器函数:只要函数体包含yield关键字,该函数就是生成器函数生成器就是迭代器。
生成器就是迭代器
def foo(): print('first') yield 1 print('second') yield 2 print('third') yield 3 print('fourth') yield 4 print('fifth') yield 5 g=foo() print(next(g)) #触发迭代器g的执行,进而触发函数的执行 print(next(g)) print(next(g)) print(next(g)) print(next(g))
yield的功能:
1.相当于为函数封装好__iter__和__next__
2.return只能返回一次值,函数就终止了,
而yield能返回多次值,每次返回都会将函数暂停,下一次next会从
上一次暂停的位置继续执行。
内置函数
内置参数详解 https://docs.python.org/3/library/functions.html?highlight=built#ascii