1.函数名的应用

1)如果直接打印函数名,打印出的为函数的地址

def func():
    print("你好,世界")
print(func)
输出:
<function func at 0x00000214BA4F5B70>
View Code

#可将函数赋值给一个变量,再通过该变量调用函数

def func():
    print("你好,世界")

a = func
a()           #通过变量,间接调用函数
输出:
你好,世界
View Code

#将一个函数赋值给另一个函数

def func():
    print("你好,世界")
def a():
    print("hello world")
a = func          #函数被另一个函数赋值
a()
输出:
你好,世界
View Code

例:将函数名放入列表,循环列表,进而调用每一个函数

def f1():
    print("英雄联盟")
def f2():
    print("地下城勇士")
def f3():
    print("QQ飞车")
def f4():
    print("穿越火线")
lst = [f1,f2,f3,f4]
for el in lst:
    el()
输出:
英雄联盟
地下城勇士
QQ飞车
穿越火线
View Code

2)将函数名作为函数的参数(即可以把函数作为参数,传递给另一个函数)

def fu(gun):
    gun()
def gun():
    print("hello world")
fu(gun)   #将函数作为参数传递
输出:
hello world
View Code

3)将函数作为返回值返回

def func():
    def inner():
        print("啊哈哈哈哈哈")
    return inner
ret = func()     #这里func()执行之后获取到的是inner函数
ret()           #这里让inner函数执行
输出:
啊哈哈哈哈哈
View Code

2.闭包

         闭包就是内层函数对外层函数(非全局)的变量的引用,叫做闭包

#闭包演示

def func():
    name = "张三"
    def inner():
        print(name)    #内层函数调用外层函数中的变量,叫做闭包
    return inner
ret = func()     #这里func()执行之后获取到的是inner函数
ret()           #这里让inner函数执行
输出:
张三
View Code

1)闭包特点:可以让一个局部变量常驻内存;因为内部函数有可能随时使用该变量,如上面的inner函数有可能随时使用name变量

2)闭包作用:对于定义在全局中的变量是不安全的(可在函数中通过global修改全局变量),如果使用闭包的方式定义了变量,只能在内部函数中修改,别的程序无法修改这个变量

def func():
    name = "张三"
    def inner():
        print(name)    #常驻内存;防止其他程序改变该变量
    def inner_change():
        nonlocal  name
        name = "李四"
    return inner 
View Code

3)闭包的好处

①在使用爬虫的时候,可将爬取的内容,常驻内存,下次爬取时,直接从内存中获取,而不需要再次爬取

例:

from urllib.request import urlopen
def but():
    content = urlopen("https://blog.51cto.com/egon09/1836763").read()
    def get_content():
        return content
    return get_content
fn = but() # 这个时候就开始加载内容
# 后⾯需要⽤到这⾥⾯的内容就不需要在执⾏⾮常耗时的⽹络连接操作了
content = fn() # 获取内容
print(content)
content2 = fn() # 重新获取内容
print(content2)
View Code

4)检测一个函数是否闭包,使用函数名_closure_ 若返回cell就是闭包,返回None就不是闭包

#检测闭包,返回cell,即返回了内容

def func():
    name = "张三"
    def inner():
        print(name)    #常驻内存;防止其他程序改变该变量
    print(inner.__closure__)           #判断是否为闭包
    return inner
ret = func()     #这里func()执行之后获取到的是inner函数
ret()           #这里让inner函数执行
输出:
(<cell at 0x00000191CAFF0B28: str object at 0x00000191CB8C1490>,)
张三
View Code

#如果没有闭包,返回None

def func():
    name = "张三"
    def inner():
        print("未使用外部变量")    #常驻内存;防止其他程序改变该变量
    print(inner.__closure__)           #判断是否为闭包
    return inner
ret = func()     #这里func()执行之后获取到的是inner函数
ret()           #这里让inner函数执行
输出:
None
未使用外部变量
View Code

3.迭代器

1) 可迭代对象:字符串、列表、元组、字典、set集合、文件句柄;可迭代对象可使用for循环遍历

①dir()可用来查看一个对象,数据类型中包含了哪些东西

lst = [1,3,5,6,9]
print(dir(lst))
输出:
['__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']
View Code

#查看基本数据类型中是否有函数__iter()__

lst = [1,3,5,6,9]
s = "我爱北京天安门"
num = 3399
dic = {'LOL':"英雄联盟",'DNF':"地下城勇士"}
tup = (20,34,21,2,5)
set = {1,2,2,3,4}
print("__iter__" in dir(lst))
print("__iter__" in dir(s))
print("__iter__" in dir(num))
print("__iter__" in dir(tup))
print("__iter__" in dir(set))
输出:
True
True
False
True
True
View Code

总结:如上数据类型,之所以可迭代是因为有一个内置含函数__iter__();所有包含了__iner__()的数据类型都市可迭代的数据类型 Iterable ; __iter__()的工作就是返回一个迭代器

2)迭代器操作

①获取迭代器:通过函数__iter()__

②迭代器往外获取元素:__neex__() 

         只能一个一个获取可迭代数据类型中的元素;当迭代到最后一个元素,继续往下迭代就会报错

lst = ["九尾妖狐","远古巫灵","无双剑姬","惩戒之箭"]
it = lst.__iter__()
print(it.__next__())
print(it.__next__())
print(it.__next__())
print(it.__next__())
print(it.__next__())
输出:
StopIteration
九尾妖狐
远古巫灵
无双剑姬
惩戒之箭
View Code

#模拟for循环,对可迭代对象遍历

lst = ["九尾妖狐","远古巫灵","无双剑姬","惩戒之箭"]
it  = lst.__iter__()
while True:
    try:                          #捕获异常
        name = it.__next__()
        print(name)
    except StopIteration:     #出现StopIteration错误,直接退出循环
        break
输出:
九尾妖狐
远古巫灵
无双剑姬
惩戒之箭
View Code

3)迭代器和可迭代对象是不一样的:

         ①存在__iter__说明是可迭代的,即是一个可迭代对象

②如果没有__next__说明绝对不是一个迭代器(迭代器中也有__iter__方法),有__next__不一定是一个迭代器

lst = [2,6,8]
print("__iter__" in dir(lst))   #是可迭代的
print("__next__" in dir(lst))   #不是迭代器
输出:
True
False
View Code

#判断一个实例是否为可迭代对象或者迭代器

lst = [1,3,5]
from collections import Iterable
from collections import  Iterator
#isinstance(xx,XX) 判断xx对象是否XX类型
print(isinstance(lst,Iterable))
print(isinstance(lst,Iterator))

it = lst.__iter__()
print(isinstance(it,Iterator))
输出:
True
False
True
View Code

总结:迭代器一定是可迭代的;迭代器中一定有__next__()方法和__iter__()方法

#注:文件句柄、range是一个迭代器;字符串、列表、元组等是可迭代的,但不是迭代器

from collections import Iterator
from collections import Iterable
with open("游戏",mode="r",encoding="utf-8") as f:
    print(isinstance(f,Iterable))
    print(isinstance(f,Iterator))
输出:
True
True
View Code

4)迭代器特点

①节省内存

②惰性机制

③不能反复,只能向下执行(只能从前往后走,不能从后往前走)