levels of contents

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'\xe7\x88\xac\xe8\x99\xab'

# 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()函数的返回类型:\n", type(tuple1))
    # 将zip对象转化为列表
    print("zip对象转化为列表:\n", 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("行与列相同:\n", list(zip(m, n)))
      # 行与列不同
      print("行与列不同:\n", 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)返回:\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)

反射函数

详见


posted @ 2019-07-13 21:50  panky  阅读(213)  评论(0编辑  收藏  举报