函数的三大器

 

迭代器

  1.函数名的使用以及第一类对象

  2.闭包

  3.迭代器

一.函数名的运用

  函数名是一个变量,但它是一个特殊的变量,与括号配合可以执行函数的变量

  1.函数名的内存地址

 

def func():
    print('呵呵')
print(func)

# 结果:
# <function func at 0x0000000000502E18>

 

  2.函数名可以赋值给其他变量

    

def func():
    print('呵呵')


a = func
a()

# 结果:
#  呵呵

  3.函数名可以当做容器类的元素

 

def func1():
    print('呵呵111')
def func2():
    print('呵呵222')
def func3():
    print('呵呵333')
def func4():
    print('呵呵444')


li = [func1,func2,func3,func4]
for func in li:
    func()
    
# 结果:
'''
呵呵111
呵呵222
呵呵333
呵呵444
'''

 

 

  4.函数名可以当做函数的参数

  

def func():
    print('你是谁?我是猪八戒啊')

def fn(s):
    print('谁在我里面,谁在说话?')
    s()
    print('哇,不好了,连我也中招了')

fn(func)

#  结果
'''
谁在我里面,谁在说话?
你是谁?我是猪八戒啊
哇,不好了,连我也中招了
'''

  5.函数名可以作为函数的返回值

  

def func():
    print('我是func ')
    def fn():
        print('我是fn')
    print('我是func')
    return fn

fn = func()
fn()

# 结果
'''
我是func 
我是func
我是fn

'''

 

 二 .闭包

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

  

def fuc():
    name = 'hahage'
    def foo():
        print(name)
    foo()
fuc()
# 结果:
# hahage

 

  可以使用__closure__ 来检测函数是否是闭包,使用函数名 .__closure__ 返回 cell就是 闭包,返回None不是闭包

  

def func():
    name = '哈哈哥'
    def foo():
        print(name)
    foo()
    print(foo.__closure__)
func()

# 结果:
# 哈哈哥
# (<cell at 0x00000000026F7D98: str object at 0x00000000021EAA50>,)

 

  问题 ---- 如何在函数外边调用内部函数呢?

def outer():
    name = '哈哈哥'
    def foo():
        print(name)
    return foo
foo = outer()  # 访问外部函数,获取到内部函数的函数地址
foo()          # 访问内部函数

# 结果
# 哈哈哥

  那如果多层嵌套呢? 很简单 --- 只需要一层一层的往外层返回就行了

def func():
    def foo():
        def fn():
            print('嘿嘿嘿')
        return fn
    return foo
foo = func()
fn = foo()
fn()
# 结果
# 嘿嘿嘿

  由它可以引出闭包的好处,由于我们在外界可以访问内部函数,那这个时候内部函数访问的时间和时机就不一样了,因为在外部,在任意时间访问内部函数,这个时候,想一想,我们之前说过,如果一个函数执行完毕,则这个函数中的变量以及局部命名空间中的内容都将会被销毁,在闭包内,如果变量被销毁了,那内部的函数将不能正常执行,所以,python规定,如果你在内部函数中访问了外层函数的变量,那么这个变量将不会消亡,,,将会常驻内存中,也就是说,使用闭包,可以保证外层函数中的变量在内存中常驻,这样做有什么好处?非常大的好处,我们来看一个关于爬虫的代码:

from urllib.request import urlopen
def but():
    content = urlopen('http://www.521609.com/').read()
    def get_content():
        return content
    return get_content
fn = but()
content = fn()
print(content)

content2 = fn()
print(content2)

 

 

  综上; 闭包的作用就是让一个变量能够常驻内存,供后面的程序使用

  三 . 迭代器

    我们之前一直在用可迭代对象进行迭代操作,那么到底什么是可迭代对象,本小节主要讨论可迭代对象,首先我们先回顾一下目前我们所熟知的可迭代对象有哪些?

    str,list,tuple,dict,set ,那为什么我们可以称他们为可迭代对象呢?因为他们都遵循了可迭代协议,什么是可迭代协议?首先看一段代码

  

# 对的
s = 'abc'
for c in s:
    print(c)

# 错的
for i in 123:

    print(i)
# 结果:
'''
a
b
c
Traceback (most recent call last):
  File "F:/爬虫/函数.py", line 28, in <module>
    for i in 123:
TypeError: 'int' object is not iterable
'''
 

 

 

  注意看报错信息中有这样一句话"'int' object is not iterable" 翻译过来就是整数类型对象是不可迭代的,iterable表示可迭代的,表示可迭代协议,那么如何进行验证你的数据类型是否符合可迭代协议,我们可以通过dir函数来查看类中定义好的所有方法

s = '我是哈哈哥'
print(dir(s))    # 打印对象中的方法和函数
print(dir(str))  # 打印类中声明的方法和函数

'''
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', 
'__gt__', '__hash__', '__init__', '__init_subclass__', '__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__', '__init_subclass__', '__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']
'''

 

  在打印结果中,寻找 __iter__ 如果能找到,那么这个类的对象就是一个可迭代对象

  我们发现字符串中可以找到 __iter__ ,list,tuple,dict,set ,range 都有 __iter__ ,这几个数据类型同时也可以进行  for循环

  这是查看一个对象是否是可迭代对象的第一种办法,我们还可以通过 isinstence() 函数来查看对象是什么类型的

l = [1,2,3]
l_iter = l.__iter__()
from collections import Iterable
from collections import Iterator

print(isinstance(l,Iterable))   # True
print(isinstance(l,Iterator))   # False

print(isinstance(l_iter,Iterable))  # True
print(isinstance(l_iter,Iterator))   # True

 

 

  综上 ----- 我们可以确定,如果对象中有 __iter__函数,那么我们认为这个对象遵循了 可迭代协议,就可以获取到相对应的迭代器,这里的 __iter__ 是帮帮助我们获取到对象的迭代器,我们使用迭代器中的 __next__( 来获取到一个迭代器中的元素,那么我们之前讲的 for 循环 的工作原理到底是什么,还是看下面的代码 ----------

 

s = '我是哈哈哥'
c = s.__iter__()    # 获取迭代器
print(c.__next__())  # 使用迭代器进行迭代 ,获取一个元素  我
print(c.__next__())  #
print(c.__next__())  #
print(c.__next__())  #
print(c.__next__())  #

  for 循环的机制 

  

for i in [1,2,3]:
    print(i)

  使用 while 循环 + 迭代器来模拟 for 循环

  

lst = [1,2,3]
lst_iter = lst.__iter__()

while 1:
    try:
        i = lst_iter.__next__()
        print(i)
    except StopIteration:
        break

  总结:

    iterable:可迭代对象,内部包含 __iter__ () 函数

    iterator : 迭代器 -- 内部包含__iter__()  同时包含 __next__()  

    迭代器的特点:

      1.节省内存

      2.惰性机制

      3.不能反复,只能向下执行

  我们可以把要迭代的内容当成子弹,然后呢?获取到迭代器 __iter__( ),就是把子弹都装在弹夹中,然后发射就是 __next__() 把每一个子弹(元素)打出来,也就是说,for 循环的时候,一开始的时候是 __iter__()来获取迭代器,后面每次取元素都是通过 __next__()来完成的,当程序遇到StopIteration将结束循环

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

posted @ 2019-07-16 20:58  会飞的草帽  阅读(215)  评论(0编辑  收藏  举报