函数名的应用
函数名是一个变量,但它是一个特殊的变量,与括号配合可以执行函数的变量。
1. 函数名的内存地址
def func():
print("呵呵")
print(func)
结果:
<function func at 0x0000000000A5D2F0>
Process finished with exit code 0
2. 函数可以赋值给其它变量
def func():
print("呵呵")
a = func
a()
结果:
呵呵
Process finished with exit code 0
3. 函数名可以当做容器类元素
def func1():
print("呵呵")
def func2():
print("呵呵")
def func3():
print("呵呵")
def func4():
print("呵呵")
lst = [func1, func2, func3, func4]
for i in lst:
i()
结果:
呵呵
呵呵
呵呵
呵呵Process finished with exit code 0
4. 函数名可以当做函数的参数
def func():
print("吃了么")
def func2(fn):
print("我是func2")
fn() # 执⾏传递过来的fn
print("我是func2")
func2(func) # 把函数func当成参数传递给func2的参数fn
结果:
我是func2
吃了么
我是func2Process finished with exit code 0
闭包
闭包就是内层函数,对外层函数(非全局)的变量的引用,叫闭包。
def func1():
name = "Python"
def func2():
print(name) # 闭包
func2()
func1()
结果:
Python
Process finished with exit code 0
注意:我们可以使用__closure__来检测函数是否是闭包,使用函数名.__closure__返回cell就是闭包,返回None就不是闭包。
def func1():
name = "Python"
def func2():
print(name) # 闭包
func2()
print(func2.__closure__) # 检验是否闭包
func1()
结果:
Python
(<cell at 0x00000000007B5C48: str object at 0x000000000069B928>,)Process finished with exit code 0
那么问题来了,如何利用外部函数调用内部函数呢?
def outer():
name = "Python"
# 内部函数
def inner():
print(name)
return inner
fn = outer() # 访问外部函数, 获取到内部函数的函数地址
fn()
结果:
Python
Process finished with exit code 0
在进行多次嵌套之后,我们应该如何调用内部函数呢?很简单,只需要一层一层的往外面调用即可。
def func1():
def func2():
def func3():
print("Python")
return func3
return func2
func1()()()
结果:
Python
Process finished with exit code 0
闭包的作用:
在一般情况下,函数体执行完毕后解释器会将内存回收,但是当内部函数如果可能有需要调用的外部数据时,这些外部数据在内存中不会消亡,会常驻内存。总之就是确保外部函数内存不会被解释器回收。
接下来演示一个爬虫的实例:
from urllib.request import urlopen
def but():
content = urlopen("http://www.xiaohua100.cn/index.html").read()
def get_content():
return content
return get_content
fn = but() # 这个时候就开始加载校花100的内容
content = fn() # 获取内容
print(content)
content2 = fn() # 重新获取内容
print(content2)
结果:
(爬到的是网站站点的的前端代码,太长故而不做演示。)
迭代器
目前所研究的我们所熟知的可迭代对象有str,list,tuple,dict,set,文件句柄等。
为什么int类型不是可迭代对象呢,我们试图这样做一下,看看会发生什么。
s = "abc"
for c in s:
print(c)
# 错的
for i in 123:
print(i)
结果:
a
b
c
Traceback (most recent call last):
File "D:/Zhenxian/Python/DayTwelve/Basic.py", line 252, in <module>
for i in 123:
TypeError: 'int' object is not iterableProcess finished with exit code 1
容易看出,字符串对象可以被迭代,但是int类型迭代会报错。
倘若我们不能了解某些对象存在的方法,我们可以通过使用dir()函数要查看该对象可存在的操作。
s = "Python"
print(dir(s)) # 可以打印对象中的方法和函数
print(dir(str)) # 也可以打印类中声明的方法和函数
结果:
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']Process finished with exit code 0
我们再试试list对象和元组对象:
lst = ["Python", "Java", "Ruby"]
tu = (1, 2, 3, 4, 5)
print(dir(lst))
print(dir(tu))
结果:
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']Process finished with exit code 0
我们很容易看出这些可迭代对象里面都有__iter__函数,如果拥有这个函数,那这个对象就是可迭代的。使用__iter__可以帮助我们获取对象中的迭代器,我们使用迭代器中的__next__()来获取一个迭代器中的元素。
s = "我爱北京天安门"
c = s.__iter__() # 获取迭代器
print(c.__next__()) # 使用迭代器进行迭代. 获取一个元素 我
print(c.__next__()) # 爱
print(c.__next__()) # 北
print(c.__next__()) # 京
print(c.__next__()) # 天
print(c.__next__()) # 安
print(c.__next__()) # 门
print(c.__next__()) # StopIteration
结果:
Traceback (most recent call last):
我
File "D:/AiBentao/Python/DayTwelve/Basic.py", line 274, in <module>
爱
北
京
print(c.__next__()) # StopIteration
天
安
StopIteration
门Process finished with exit code 1
细心的同学可能已经发现了,本次示例代码是存在问题的,运行结果抛出了StopIteration的错误。
分析:字符串有七个字符,然而我们使用迭代器迭代了八次,相当于迭代结果已经完了,但是我们继续操作__next__(),就会出现这样的错误。
为了避免这样的错误,我们将通过try操作来捕捉,使得程序有条不紊的运行。
s = "我爱北京天安门"
c = s.__iter__() # 获取迭代器
while True:
try:
i = c.__next__()
print(i)
except StopIteration:
break
结果:
我
爱
北
京
天
安
门Process finished with exit code 0
总结
Iterable:可迭代对象。
内部包含__iter__()函数
Iterato:迭代器
内部包含__iter__() 同时包含__next__()。
迭代器的特点:
1. 节省内存。
2. 惰性机制 。
3. 不能反复,只能向下执行。