zoukankan      html  css  js  c++  java
  • Python函数(2)

    Python函数(2)

    闭包

    • 内层函数对外层函数的变量的引用(非全局)
    • 闭包只存在函数中
    • 逐层返回,最终返回最外层

    特性:解释器执行程序时,如果遇到函数,随着函数的结束而关闭临时名称空间,但是如果遇到闭包,那么闭包的空间不会随着函数的结束而关闭

    本质:就是在内存中开辟一个空间,常贮存一下内容,以便以后调用

    判断是一个函数否是闭包

    # 是闭包
    def func():
        name = 'panky'
        def inner():
            print(name)
        print(inner.__closure__)
        return inner
    
    
    inner = func()
    inner()
    
    >>> (<cell at 0x000001FE50DF9588: str object at 0x000001FE50E8A228>,)
    >>> panky
    
    # 非闭包
    name = 'panky'
    
    
    def func2():
        def inner():
            print(name)
        print(inner.__closure__)
        return inner
    
    
    f = func2()
    f()
    
    >>> None
    >>> panky
    

    闭包应用:

    • 装饰器
    • 爬虫

    装饰器

    • 本质是一个闭包
    • 在不改变原函数的调用的方式上,给原函数增加一些额外功能
    def wrapper(f):
        def inner(*args, **kwargs):
            print("Before the function")
            ret = f(*args, **kwargs)
            print("After the function")
            return ret
        return inner
    
    
    @wrapper
    def func(a, b):
        print(a, b)
        return a + b
    
    
    res = func(1, 3)
    print(res)
    
    
    >>> Before the function
    >>> 1 3
    >>> After the function
    >>> 4
    
    # 带有标志位的装饰器
    def outer(flag=False):
        def wrapper(func):
            def inner(*args, **kwargs):
                if flag:
                    print('Before the function')
                ret = func(*args, **kwargs)
                if flag:
                    print("After the function")
                return ret
            return inner
        return wrapper
    
    
    @outer(flag=True)
    def func(a, b):
        print(a, b)
        return a + b
    
    
    res = func(2, 5)
    print(res)
    
    
    >>> Before the function
    >>> 2 5
    >>> After the function
    >>> 7
    
    # 多个装饰器
    
    def wrapper1(func):
        def inner(*args, **kwargs):
            print("wrapper1, before the function")
            ret = func(*args, **kwargs)
            print("wrapper1, after the function")
            return ret
        return inner
    
    
    def wrapper2(func):
        def inner(*args, **kwargs):
            print('wrapper2, before the function')
            ret = func(*args, **kwargs)
            print('wrapper2, after the function')
            return ret
        return inner
    
    
    @wrapper1
    @wrapper2
    def fun(a, b):
        print(a, b)
        return a + b
    
    
    res = fun(9, 8)
    print(res)
    
    
    >>> wrapper1, before the function
    >>> wrapper2, before the function
    >>> 9 8
    >>> wrapper2, after the function
    >>> wrapper1, after the function
    >>> 17
    

    迭代器

    可迭代对象:内部含有__iter__()方法,遵循可迭代协议,使用__iter__()方法或者内置函数iter()可以将可迭代对象变为迭代器

    迭代器:内部含有__iter__()__next__()方法,遵循迭代器协议,使用__next__()方法或者内置函数next()可以对迭代器进行取值

    • 节省内存
    • 惰性机制,逐个取值
    • 一条路走到黑,不回头

    判断是否是可迭代对象:

    1. '__iter__' in dir(object)

    2. from collections import Iterable
      isinstance(object, Iterable)
      

    判断是否是迭代器:

    1. '__iter__' in dir(object) and '__next__' in dir(object)

    2. from collections import Iterator
      isinstance(object, Iterator)
      

    可迭代对象转化为迭代器:

    1. iterable.__iter__()
    2. iter(iterable)
    s = "That is life"
    print('__iter__' in dir(s))
    print('__next__' in dir(s))
    new_s = s.__iter__()
    print('__next__' in dir(new_s))
    print(next(new_s))
    print(next(new_s))
    
    
    >>> True
    >>> False
    >>> True
    >>> T
    >>> h
    
    
    # 用for loop对iterable进行取值
    # for loop机制:在遍历之前,先调用iterable对象的__iter__方法,将其转化为一个iterator,然后
    # 在利用__next__方法或者next()内置函数去遍历取值
    for i in "That is life":
        print(i)
    
    
    # 用while loop模拟for loop
    s1 = 'abcd1234'
    obj = iter(s1)
    while True:
        try:
            print(next(obj))
        except StopIteration:
            break    
    

    生成器

    Generator: A generator is a kind of iterator that is defined with normal function syntax.

    构建方式:

    1. 生成器函数

      # 一个包含yield关键字的函数就是生成器函数
      # yield不会终止函数,调用生成器函数不会得到返回的具体值,而是一个iterable object
      # 每一次获取这个iterable object 的value,就会推动函数的执行,获取返回值,直到函数结束
      
    2. 生成器表达式

    send方法next()内置函数

    def func():
        count = yield 666
        print(count, 'in yield 1')
        name = yield 'panky'
        print(name, 'in yield 2')
        name2 = yield 'suki'
        print(name2, 'in yield 3')
        name3 = yield 'snoopy'
        print(name3, 'in yield 4')
    
    
    generator = func()
    print(next(generator))
    print(next(generator))
    print(next(generator))
    print(next(generator))
    
    
    # 666
    # None in yield 1
    # panky
    # None in yield 2
    # suki
    # None in yield 3
    # snoopy
    
    # send 不仅能对yield取值,还可以给上一个yield发送一个值
    
    def func():
        count = yield 666
        print(count, 'in yield 1')
        name = yield 'panky'
        print(name, 'in yield 2')
        name2 = yield 'suki'
        print(name2, 'in yield 3')
        name3 = yield 'snoopy'
        print(name3, 'in yield 4')
    
    
    generator = func()
    print(generator.send(None))  # 第一次取值不能用send传值
    print(generator.send('yield 2'))
    print(generator.send('yield 3'))
    print(generator.send('yield 4'))  # 最后一个yield永远不能得到send传的值
    
    
    # 666
    # yield 2 in yield 1
    # panky
    # yield 3 in yield 2
    # suki
    # yield 4 in yield 3
    # snoopy
    

    yield from将一个iterable object变成iterator返回

    def func():
        list1 = [1, 2, 4, 3, 0]
        yield from list1
    
    
    generator = func()
    print(next(generator))
    print(next(generator))
    

    各种推导式

    列表推导式:

    • 循环模式——[变量(加工后的变量) for 变量 in iterable]
    • 筛选模式——[变量(加工后的变量) for 变量 in iterable if 条件]
    • 三元模式——ret = value1 if 条件 else value2

    生成器表达式:与列表推导式一致,将[]换成()

    generator1 = ("python %s season" % i for i in range(1, 10))
    for i in generator1:
        print(i)
    

    集合推导式:

    {i:666 for i in range(1, 10)}
    
    dic1 = {'a': 1, 'b': 2, 'c': 3}
    dic2 = {value:key for key, value in dic1.items()}
    
    set1 = {1, 2, 3, -4, 4}
    set2 = {i**2 for i in set1}
    

    lambda函数

    lambda函数:针对只有返回值的函数

    格式:

    函数名 = lambda 参数: 返回值
    

    递归函数

    详见

    Python常用内置函数

    数学相关

    # abs() : 求取绝对值
    abs(-4)
    
    # max() : 求取object最大值
    max([1, 2, 3])
    
    # min() : 求取object最小值
    min([1, 2, 3])
    
    # sum() : 求取object的和
    sum([1, 3, 5])
    
    # len() : 长度
    len('abc')
    
    # divmod(a,b): 获取商和余数
    divmod(5, 2) >>> (2, 1)
    
    # pow(a,b) : 获取乘方数
    pow(2, 3) >>> 8
    
    # round(a,b) : 获取指定位数的小数。a代表浮点数,b代表要保留的位数
    round(3.1415926,2) >>> 3.14
    
    # range(a[,b]) : 生成一个a到b的数组,左闭右开 
    range(1,10) >>> [1,2,3,4,5,6,7,8,9]
    

    类型转换

    # int(str): 转换为int型
    int('1') >> > 1
    
    # float(int / str): 将int型或字符型转换为浮点型
    float('1') >> > 1.0
    
    # str(int): 转换为字符型
    str(1) >> > '1'
    
    # bool(int): 转换为布尔类型
    str(0) >> > False
    str(None) >> > False
    
    # bytes(str, code): 接收一个字符串,与所要编码的格式,返回一个字节流类型
    bytes('abc', 'utf-8') >> > b'abc'
    bytes(u'爬虫', 'utf-8') >> > b'xe7x88xacxe8x99xab'
    
    # list(iterable): 转换为list
    list((1, 2, 3)) >> > [1, 2, 3]
    
    # iter(iterable): 返回一个可迭代的对象
    iter([1, 2, 3]) >> > <list_iterator object at0x0000000003813B00>
    
    # dict(iterable): 转换为dict
    dict([('a', 1), ('b', 2), ('c', 3)]) >> > {'a': 1, 'b': 2, 'c': 3}
    
    # tuple(iterable): 转换为tuple 
    tuple([1, 2, 3]) >> > (1, 2, 3)
    
    # set(iterable): 转换为set 
    set([1, 4, 2, 4, 3, 5]) >> > {1, 2, 3, 4, 5}
    set({1: 'a', 2: 'b', 3: 'c'}) >> > {1, 2, 3}
    
    # hex(int): 转换为16进制
    hex(1024) >> > '0x400'
    
    # oct(int): 转换为8进制
    oct(1024) >> > '0o2000'
    
    # bin(int): 转换为2进制
    bin(1024) >> > '0b10000000000'
    
    # chr(int): 转换数字为相应ASCI码字符
    chr(65) >> > 'A'
    
    # ord(str): 转换ASCI字符为相应的数字
    ord('A') >> > 65
    

    其它操作

    # eval(): 执行一个表达式,或字符串作为运算
    eval('1+1') >> > 2
    # exec(): 执行python语句
    exec('print("Python")') >> > Python
    
    # type():返回一个对象的类型。
    type('abc') >>> <class 'str'>
    
    # id(): 返回一个对象的唯一标识值
    id('str')
    
    # hash(object):返回一个对象的hash值,具有相同值的object具有相同的hash值
    hash('python') >>> 7070808359261009780
    
    # help():调用系统内置的帮助系统。
    help(str)
    help(dict)
    
    # isinstance():判断一个对象是否为该类的一个实例。
    s = 'abc'
    print(isinstance(s, str)) >>> True
    print(isinstance(s, dict))>>> False
    
    # issubclass():判断一个类是否为另一个类的子类。
    class A:
        pass
    
    class B(A):
        pass
    
    class C:
        pass
    
    print(issubclass(B, A)) >>> True
    print(issubclass(C, A)) >>> False
    
    # globals(): 返回当前全局变量的字典。
    globals()
    >>> {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000240FB1CE358>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/python36panky/07_Luffy project/luffyproject/test.py', '__cached__': None}
    
    # next(iterator[, default]): 接收一个迭代器,返回迭代器中的数值,如果设置了default,则当迭代器中的元素遍历后,输出default内容。
    
    # reversed(sequence) : 生成一个反转序列的迭代器。 
    reversed('abc') >> > ['c', 'b', 'a']
    

    重要内置函数

    sorted()——排序函数

    详见


    enumerate()——枚举函数

    enumerate()是python的内置函数、适用于python2.x和python3.x
    enumerate在字典上是枚举、列举的意思
    enumerate参数为可遍历/可迭代的对象(如列表、字符串)
    enumerate多用于在for循环中得到计数,利用它可以同时获得索引和值,即需要index和value值的时候可以使用enumerate
    enumerate()返回的是一个enumerate对象

    lst = [1, 2, 3, 4, 5, 6]
    res = enumerate(lst)
    print(res)  # <enumerate object at 0x000002092226D3A8>
    

    使用enumerate()

    lst = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
    for index, value in enumerate(lst):
        print(index, value)
    
    
    # 0 a
    # 1 b
    # 2 c
    # 3 d
    # 4 e
    # 5 f
    # 6 g
    
    # 指定索引从1开始
    lst = ['a', 'b', 'c', 'd', 'e']
    for index, value in enumerate(lst, 2):
        print(index, value)
    
    
    # 2 a
    # 3 b
    # 4 c
    # 5 d
    # 6 e
    

    补充:
    如果要统计文件的行数,可以这样写:
    count = len(open(filepath, 'r').readlines())
    这种方法简单,但是可能比较慢,当文件比较大时甚至不能工作。

    可以利用enumerate()

    count = 0
    for index, line in enumerate(open(filepath, 'r')):
        count += 1
    

    zip()——拉链函数

    zip()定义:

    • 从参数中的多个迭代器取元素组合成一个新的迭代器
    • 返回:返回一个zip对象,其内部元素为元祖;可以转化为列表或元祖
    • 传入参数:元祖、列表、字典等迭代器

    使用zip():

    • 当zip()函数中只有一个参数时
      zip(iterable)iterable中依次取一个元组,组成一个元组

      # zip()函数单个参数
      list1 = [1, 2, 3, 4]
      tuple1 = zip(list1)
      # 打印zip函数的返回类型
      print("zip()函数的返回类型:
      ", type(tuple1))
      # 将zip对象转化为列表
      print("zip对象转化为列表:
      ", list(tuple1))
      
      """
      zip()函数的返回类型:
       <class 'zip'>
      zip对象转化为列表:
       [(1,), (2,), (3,), (4,)]
      """
      
    • 当zip()函数有两个参数时

      • zip(a,b)zip()函数分别从a和b依次各取出一个元素组成元组,再将依次组成的元组组合成一个新的迭代器--新的zip类型数据

      • 注意:

        # 要求a与b的维数相同,当两者具有相同的行数与列数时,正常组合对应位置元素即可;
        
        # 当a与b的行数或列数不同时,取两者结构中最小的行数和列数,依照最小的行数和列数将对应位置的元素进行组合;这时相当于调用itertools.zip_longest(*iterables)函数。
        
        # zip()函数有2个参数
        m = [[1, 2, 3],  [4, 5, 6],  [7, 8, 9]]
        n = [[2, 2, 2],  [3, 3, 3],  [4, 4, 4]]
        p = [[2, 2, 2],  [3, 3, 3]]
        # 行与列相同
        print("行与列相同:
        ", list(zip(m, n)))
        # 行与列不同
        print("行与列不同:
        ", list(zip(m, p)))
        
        """
        行与列相同:
         [([1, 2, 3], [2, 2, 2]), ([4, 5, 6], [3, 3, 3]), ([7, 8, 9], [4, 4, 4])]
        行与列不同:
         [([1, 2, 3], [2, 2, 2]), ([4, 5, 6], [3, 3, 3])]
        """
        

    zip()应用于矩阵:

    # zip()应用
    # 矩阵相加减、点乘
    m = [[1, 2, 3],  [4, 5, 6],  [7, 8, 9]]
    n = [[2, 2, 2],  [3, 3, 3],  [4, 4, 4]]
    # 矩阵点乘
    print('=*'*10 + "矩阵点乘" + '=*'*10)
    print([x*y for a, b in zip(m, n) for x, y in zip(a, b)])
    # 矩阵相加,相减雷同
    print('=*'*10 + "矩阵相加,相减" + '=*'*10)
    print([x+y for a, b in zip(m, n) for x, y in zip(a, b)])
    
    
    """
    =*=*=*=*=*=*=*=*=*=*矩阵点乘=*=*=*=*=*=*=*=*=*=*
    [2, 4, 6, 12, 15, 18, 28, 32, 36]
    =*=*=*=*=*=*=*=*=*=*矩阵相加,相减=*=*=*=*=*=*=*=*=*=*
    [3, 4, 5, 7, 8, 9, 11, 12, 13]
    """
    

    *zip():

    *zip()函数是zip()函数的逆过程,将zip对象变成原先组合前的数据。

    # *zip()函数 
    print('=*'*10 + "*zip()函数" + '=*'*10)
    m = [[1, 2, 3],  [4, 5, 6],  [7, 8, 9]]
    n = [[2, 2, 2],  [3, 3, 3],  [4, 4, 4]]
    print("*zip(m, n)返回:
    ", *zip(m, n))
    m2, n2 = zip(*zip(m, n))
    # 若相等,返回True;说明*zip为zip的逆过程
    print(m == list(m2) and n == list(n2))
    
    
    """
    =*=*=*=*=*=*=*=*=*=**zip()函数=*=*=*=*=*=*=*=*=*=*
    *zip(m, n)返回:
     ([1, 2, 3], [2, 2, 2]) ([4, 5, 6], [3, 3, 3]) ([7, 8, 9], [4, 4, 4])
    True
    """
    

    filter()——过滤函数

    filter被称为高阶函数是有道理的。

    filter(self, /, *args, **kwargs)

    Docstring:      filter(function or None, iterable) --> filter object  
    
    Return an iterator yielding those items of iterable for which function(item) is true. If function is None, return the items that are true
    

    从Doc的简单描述可以看出,filter的主要作用是通过functioniterable中的元素进行过滤,并返回一个迭代器(iterator),其中是function返回True的元素。如果function传入None,则返回所有本身可以判断为True的元素。

    example_1

    lst = [x for x in range(10)]
    filter_object = filter(lambda x: x % 2 == 0, lst)
    print(filter_object)
    print(list(filter_object))  # 因为filter返回的是一个iterator,所以输出的时候需要用list进行转换
    
    
    """
    <filter object at 0x00000249AF02A438>
    [0, 2, 4, 6, 8]
    """
    

    example_2

    lst = [x for x in range(0, 10)]
    filter_object = filter(None, lst)
    print(filter_object)
    print(list(filter_object))
    
    
    """
    <filter object at 0x0000020CC222A438>
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    """
    

    和例1的输入略有区别,输入是0--9,filter的第一个参数传入了None,所以在迭代过程中,0被判断为False从而被过滤,1~9被保留下来。这个方法可以替代for循环的数据拾取。

    通过上面的例子可以看出,调用filter时并没有触发过滤过程,因为调用filter函数只是返回了一个iterator,它是惰性计算,只有next或者list的时候,才真正开始计算过程。

    example_3

    def _odd_iter():
        n = 1
        while True:
            n = n + 2
            yield n
    
    
    def _not_divisible(n):
        return lambda x: x % n > 0
    
    
    def primes():
        yield 2
        it = _odd_iter()
        ftr = filter(_not_divisible(2), it)  # 1
        while True:
            n = next(ftr)  # 2
            yield n
            ftr = filter(_not_divisible(n), ftr)  # 3
    
    
    for n in primes():
        if n < 100:
            print('now:', n)
        else:
            break
    

    通过这个example_3,可以看到filter的两个高级用法:

    1. 其实filter返回的是一个filter对象。#3行通过重复赋值,可以向filter中添加多个过滤器。例子中,就是通过每次执行#3行,把当前素数作为新的被除数条件加入到过滤器ftr 中,所以在for循环的后续迭代中,每次都增加一个素数条件进入过滤器

      通过这种重复赋值的方法,可以给filter添加多个过滤函数,极大的加强了过滤功能

    2. filter的第二个参数可以传入iterator。当然,此时就不能用list取filter的结果,只能用next(filter对象)取下一个过滤结果为True的元素


    map()——映射函数

    map(func, *iterables)是 Python 内置的高阶函数,它接收一个函数 f 和一个或多个iterable,并通过把函数 f 依次作用在 一个或多个iterable 的每个元素上,得到一个map object并返回

    1. 当seq只有一个时,将函数func作用于这个seq的每个元素上,并得到一个新的seq

    example_1

    def f(x):
        return x*x
    
    
    map_object = map(f, [1, 2, 3, 4, 5, 6, 7])
    print(map_object)  # <map object at 0x0000016F8C8FA470>
    print(list(map_object))  # [1, 4, 9, 16, 25, 36, 49]
    
    # 注意:map()函数不改变原有的 list,而是返回一个新的 list。
    # 利用map()函数,可以把一个 list 转换为另一个 list,只需要传入转换函数。
    # 由于list包含的元素可以是任何类型,因此,map() 不仅仅可以处理只包含数值的 list,事实上它可以处理包含任意类型的 list,只要传入的函数f可以处理这种数据类型。
    

    example_2

    """
    假设用户输入的英文名字不规范,没有按照首字母大写,后续字母小写的规则,请利用map()函数,把一个list(包含若干不规范的英文名字)变成一个包含规范英文名字的list:
    输入:['adam', 'LISA', 'pankY']
    输出:['Adam', 'Lisa', 'Panky']
    """
    
    
    def format_name(s):
        s1 = s[0:1].upper() + s[1:].lower()
        return s1
    
    
    map_object = map(format_name, ['adam', 'LISA', 'panky'])
    print(map_object)  # <map object at 0x000001C1CE7FA588>
    print(list(map_object))  # ['Adam', 'Lisa', 'Panky']
    
    1. 当seq多于一个时,map可以并行(注意是并行)地对每个seq执行如下图所示的过程

    example_3

    map_obj = map(lambda x, y: x**y, [1, 2, 3], [1, 2, 3])
    for i in map_obj:
        print(i)
    
    
    """
    1
    4
    27
    """
    

    exampe_4

    map_obj = map(lambda x, y: (x**y, x + y), [1, 2, 3], [1, 2, 3])
    for i in map_obj:
        print(i)
    
    
    """
    (1, 2)
    (4, 4)
    (27, 6)
    """
    

    example_5

    # python3中可以处理类表长度不一致的情况,但无法处理类型不一致的情况,
    map_obj1 = map(lambda x, y: (x ** y, x + y), [1, 2, 3], [1, 2])
    for i in map_obj1:
        print(i)
    
    map_obj2 = map(lambda x, y: (x ** y, x + y), [1, 2, 3], [1, 2, 'a'])
    for i in map_obj2:
        print(i)
    

    example_6

    特殊用法,做类型转换:
    map_obj = map(int,'1234')
    for i in map_obj:
        print(type(i))
        print(i)
    

    反射函数

    详见


  • 相关阅读:
    联考20200520 T2 函数
    联考20200520 T1 石子游戏
    模拟赛T2 中继系统
    模拟赛T2 仙人掌毒题
    BZOJ3462 DZY Loves Math II
    20200129模拟赛T1 string
    BZOJ1316 树上的询问
    BZOJ4559 成绩比较
    JZOJ4238 纪念碑
    BZOJ 2648 世界树
  • 原文地址:https://www.cnblogs.com/pankypan/p/11182235.html
Copyright © 2011-2022 走看看