第五篇 函数进阶

第五篇 函数进阶

==回顾基础==

函数对象:可以将定义在函数内的函数返回到全局使用,从而打破函数的层级限制.

名称空间与作用域:作用域关系在函数定义阶段时就已经固定死了,与调用位置无关,即在任意位置调用函数都需要跑到定义函数时找到作用域关系.

一 闭包函数

闭包

闭就是封闭(函数内部函数),包就是包含(该内部函数对外部作用域而非全局作用域的变量的引用).闭包指的是:函数内部函数对外部作用域而非全局作用域的引用.

提示

之前我们都是通过参数将外部的值传给函数,闭包提供了另外一种思路,包起来咯,包起哟,包起来哇

def outter():
    x = 1
    def inner():
        print(x)
     return inner

f = outter()

def f2():
    x = 2
    f()
    
f2()

# 1
两种为函数传参的方式
  1. 使用参数的形式
  2. 包给函数
闭包函数的应用

闭包的意义:返回的函数对象,不仅仅是一个函数对象,在函数还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域.

应用领域:延迟计算(原来我们是传参,现在我们是包起来),爬虫领域.

import requests

def ger(ur1):
    response = requests.get(ur1)
    print(f"done: {ur1}")
    
get('https://www.baidu.com')
get('https://www.baidu.com')
get('https://www.baidu.com')

get('https://www.cnblogs.com/linhaifeng')
get('https://www.cnblogs.com/linhaifeng')
get('https://www.cnblogs.com/linhaifeng')

二 装饰器

无参装饰器

什么是装饰器

装饰器指的是为被装饰器对象添加额外功能.因此定义装饰器就是定义一个函数,只不过该函数的功能是用来为其他函数添加额外功能的.

需要注意的是:

  1. 装饰器本身其实是可以任意调用的对象
  2. 被装饰器的对象也是可以是任意可调用的对象
装饰器作用

对已上线的软件进行维护,添加新的功能,但不改变其原来的用法,必须遵循一下原则;

  1. 不修改被装饰对象的源代码
  2. 不修改被装修对象的调用方式
用法
  1. 改变调用方式""

    import time
    
    def index():
        print('welcome to index')
        time.sleep(1)
    
    def time_count(func):
        start = time.time()
        func()
        end = time.time()
        print(f'{func} time is {start-end}")
    
    time_count(index)
  2. 包给函数-外包

    import time
    def index():
        print('welcome to index')
        time.sleep(1)
    
    def time_count(func):
        #func = 最原始的index
        def wrapper():
            start = time.time()
            func()
            end = time.time()
            print(f"{func} time is {start-end}")
         return wrapper
    # f= time_count(index)
    # f()
    
    index = time_conut(index)
    wrapper
    index()   #wrapper()

==完善装饰器==

上述的装饰器,最后调用index()的时候,其实是在调用wrapper(),因此如果原始的index有返回值的时候,wrapper()函数的返回值应该和index()的返回值相同,也就是说,我们需要同步原始的index()和wrapper()方法的返回值.

装饰器模板
   def deco(func):
   
        def wrapper(*args,**kwargs):
   
                    res = func(*args, **kwargs)
   
                    return res
   
        return wrapper

有参装饰器

无参装饰器只套了两层,有参装饰器可以套三层.

由于两层装饰器,参数必须得固定位func,但是三层的装饰器解除了这个限制.我们不仅仅可以使用上述单个参数的三层装饰器,多个参数的只需要在三层装饰器中多加入几个参数即可,也就是说装饰器三层即可,多加一层反倒无用.

详解[]https://www.cnblogs.com/nickchen121/p/10771174.html

三 迭代器

可迭代对象

python中一切皆对象,对于这一切对象中,但凡有——iter——方法的对象,都是可迭代对象

python内置可迭代对象:str,list,tuple,dict,set,file

迭代器对象

只有字符串和列表都是依赖索引取值的,而其他的可迭代对象都是无法依赖索引取值的。因此我们得找到一个方法让其他的可迭代对象不依赖索引取值。

在找到该方法前,首先我们给出迭代器对象的概念:可迭代的对象执行——iter——方法得到的返回值。并且可迭代对象会有一个——iter——方法得到的返回值。并且可迭代对象会有一个——next——方法。

我们可以使用while循环。其中使用的try...except...为异常处理模块

==总结==、

迭代器对象:执行可迭代对象的——iter——方法,拿到返回值就是迭代器对象。

特点:

  1. 内置——next——方法,执行该方法会拿到迭代器对象中的一个值
  2. 内置有——iter——方法,执行该方法会拿到迭代器本身
  3. 文件本身就是迭代器对象

缺点:

  1. 取值麻烦,只能一个一个取,并且只能往后取,值取了就没了
  2. 无法使用len()方法获取长度
for循环原理

for循环称为迭代器循环,in后必须是可迭代的对象。

因为迭代器使用——iter——后还是迭代器本身,因此for循环不用考虑in后的对象是可迭代对象还是迭代器对象。

由于对可迭代对象使用——iter——方法后变成一个迭代器对象,这个迭代器对象只是占用了一小块内存空间,他只有使用——next——后才会吐出一个一个值。

四 三元表达式

条件成立时的返回值if条件else条件不成立时的返回值

五 列表推导式

[expression for item1 in iterable1 if condition1
for item2 in iterable2 if condition2
...
for itemN in iterableN if conditionN
]
类似于
res=[]
for item1 in iterable1:
    if condition1:
        for item2 in iterable2:
            if condition2
                ...
                for itemN in iterableN:
                    if conditionN:
                        res.append(expression)

六 字典生成式

通过解压缩函数生成一个字典

info_dict = {'name': 'nick', 'age': 19, 'gender': 'male'}
print(f"info_dict.keys(): {info_dict.keys()}")
print(f"info_dict.values(): {info_dict.values()}")

res = zip(info_dict.keys(), info_dict.values())
print(F"zip(keys,values): {zip(info_dict.keys(),info_dict.values())}")

info_dict = {k: v for k, v in res}
print(f"info_dict: {info_dict}")

七 生成器

生成器本质就是迭代器,同时又不仅仅是迭代器,不过迭代器之外的用途不是很多;生成器提供了非常方便的自定义迭代器的途径。

yield关键字

yield的英语单词意思时生产,在函数中但凡出现yield关键字,再调用函数,就不会执行函数体代码,而是会返回一个值。

生成器表达式

把列表推导式的[]换成()就是生成器表达式

优点:省内存,一次只产生一个值在内存中

总结

yield:

  1. 提供一种自定义迭代器的方式
  2. yield可以暂停住函数,并提供当前的返回值

yield和return:

  1. 相同点:两者都是在函数内部使用,都可以返回值,并且返回值没有类型和个数的限制。
  2. 不同点:return只能返回一次值,yield可以返回多次值

八 递归

函数的嵌套调用是:函数嵌套函数。函数的递归调用:它是一种特殊的嵌套调用,但是它在调用一个函数的过程中,又直接或间直接调用了它自身。如果递归函数不断地带调用函数自身,那么这个递归函数将进入死循环,因此我们应该给递归函数一个明确的结束条件。

  1. 直接调用:指的是直接在函数内部调用函数自身。
  2. 间接调用:间接调用指的是:不在原函数体内调用函数自身,而是通过其他方法间接调用函数自身。

递归必须要有两个明确的阶段:

  1. 递推:一层一层递归调用下去,进入下一层递归的问题规模将会减小。

  2. 回溯:递归必须要有一个明确的结束条件,在满足该条件开始一层一层回溯

    递归的精髓在于通过不断地重复逼近一个最终的结果。

九 匿名函数

有名函数

我们之前定的函数都是有名函数,它是基于函数名使用。

匿名函数

匿名函数,他没有绑定名字,使用一次即被收回,加括号既可以运行。

与内置函数联用

匿名函数通常与max(),sorted(),filter(),filter()方法连用。

取最大值,可以用max,max默认比较的是字典的key:

  1. 首先将可迭代对象变成迭代器对象
  2. res=next(迭代器对象),将res当作参数传给key指定的函数,然后将该函数的返回值当作判断依据。

对字典值排序,使用sorted方法:

  1. 首先将可迭代对象变成迭代器对象
  2. res=next(迭代器对象),将res当作参数传给第一个参数指定的函数,然后该函数的返回值当作判断依据。

对列表中的某一数据做处理,可以用map方法

  1. 首先将可迭代对象变成迭代器对象
  2. res=next(迭代器对象),将res当作参数传给第一个参数传给指定的函数,然后该函数的返回值作为map方法的结果之一.

帅选含有你想要的数据,可以用filter方法:

  1. 首先将可迭代对象变成迭代器对象
  2. res=next(迭代器对象),将res当作参数传给第一个参数指定的函数,然后filter会判断函数的返回值的真假,如果为真则留下.

十 内置函数

掌握
  1. bytes

    解码字符

  2. chr/ord

    照ASCIL码表将数字转换成对应字符,ord()将字符转换成对应数字

  3. divmod

    分栏

  4. enumrate

    带有索引的迭代

  5. eval

    把字符串翻译成数据类型

  6. hash

    是否可以哈希

了解
  1. abs

    求绝对值

  2. all

    可迭代对象内元素为真,则返回真

  3. any

    而迭代对象中有一元素为真,则为真

  4. bin/oct/hex

    二进制,八进制,十六进制转换

  5. dir

    列举出所有time的功能

  6. frozenset

    不可变集合

  7. goabals/locals

    查看全局名字;查看局部名字

posted @ 2019-10-23 21:29  Mr-Allen  阅读(124)  评论(0编辑  收藏  举报