美文网首页
python基础语法2

python基础语法2

作者: go含羞草 | 来源:发表于2018-04-17 17:45 被阅读0次

    高级特性

    1.切片

    #取一个list或tuple的部分元素是非常常见的操作。比如,一个list如下:
    L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
    L[0:3] #L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素。
    L[:3] #如果第一个索引是0,还可以省略
    L[1:3] #也可以从索引1开始,取出2个元素出来:
    L[-2:]  #支持倒数切片
    L[-2:-1] #记住倒数第一个元素的索引是-1。
    
    我们先创建一个0-99的数列:
    L = list(range(100))
    L[:10:2] #前10个数,每两个取一个:
    L[::5] #所有数,每5个取一个:
    L[:] #原样复制一个list
    
    #tuple也是一种list,唯一区别是tuple不可变。因此,tuple也可以用切片操作,只是操作的结果仍是tuple:
    (0, 1, 2, 3, 4, 5)[:3]  #(0, 1, 2)
    #字符串'xxx'也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串:
    'ABCDEFG'[:3] #'ABC'
    'ABCDEFG'[::2] #'ACEG'
    

    2.迭代

    如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。
    因为dict的存储不是按照list的方式顺序排列,所以,迭代出的结果顺序很可能不一样。
    默认情况下,dict迭代的是key。如果要迭代value,可以用for value in d.values(),
    如果要同时迭代key和value,可以用for k, v in d.items()。
    由于字符串也是可迭代对象,因此,也可以作用于for循环:for ch in 'ABC':
    那么,如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:

    from collections import Iterable
    isinstance('abc', Iterable) # str是否可迭代 True
    isinstance([1,2,3], Iterable) # list是否可迭代 True
    isinstance(123, Iterable) # 整数是否可迭代 False
    

    最后一个小问题,如果要对list实现类似Java那样的下标循环怎么办?
    Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:

    for i, value in enumerate(['A', 'B', 'C']):
        print(i, value)
    for x, y in [(1, 1), (2, 4), (3, 9)]:
        print(x, y)
    

    3.列表生成式

    
    list(range(1, 11))
    #但如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?方法一是循环:
    L = []
    for x in range(1, 11):
        L.append(x * x)
    #方法2
    [x * x for x in range(1, 11)]
    #写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来,
    # 十分有用,多写几次,很快就可以熟悉这种语法。
    
    #for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:
    [x * x for x in range(1, 11) if x % 2 == 0]
    #还可以使用两层循环,可以生成全排列
    [m + n for m in 'ABC' for n in 'XYZ']
    
    #运用列表生成式,可以写出非常简洁的代码。例如,列出当前目录下的所有文件和目录名,可以通过一行代码实现:
    import os # 导入os模块,模块的概念后面讲到
    [d for d in os.listdir('.')] # os.listdir可以列出文件和目录
    d = {'x': 'A', 'y': 'B', 'z': 'C' }
    [k + '=' + v for k, v in d.items()]#['y=B', 'x=A', 'z=C']
    
    L = ['Hello', 'World', 'IBM', 'Apple']
    [s.lower() for s in L] #['hello', 'world', 'ibm', 'apple']
    

    4.生成器

    这种一边循环一边计算的机制,称为生成器:generator。

    L = [x * x for x in range(10)]
    g = (x * x for x in range(10))
    for n in g:
        print(n)
    #创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。
    #如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:
    #我们讲过,generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,
    # 直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
    
    #斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
    
    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            print(b)
            a, b = b, a + b
            n = n + 1
        return 'done'
    
    #也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:
    
    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            yield b
            a, b = b, a + b
            n = n + 1
        return 'done'
    #这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:
    
    def odd():
        print('step 1')
        yield 1
        print('step 2')
        yield(3)
        print('step 3')
        yield(5)
    #调用该generator时,首先要生成一个generator对象,然后用next()函数不断获得下一个返回值:
    
    #但是用for循环调用generator时,发现拿不到generator的return语句的返回值。
    # 如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:
    g = fib(6)
    while True:
        try:
            x = next(g)
            print('g:', x)
        except StopIteration as e:
            print('Generator return value:', e.value)
            break
    
    #杨辉三角
    def triangles():
        L = [1]
        while True:
            yield L[:]
            L.append(0)
            L = [L[i - 1] + L[i] for i in range(len(L))]
        return 'done'
    

    5.迭代器

    我们已经知道,可以直接作用于for循环的数据类型有以下几种:
    一类是集合数据类型,如list、tuple、dict、set、str等;
    一类是generator,包括生成器和带yield的generator function。
    这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
    可以使用isinstance()判断一个对象是否是Iterable对象:

    from collections import Iterable
    isinstance([], Iterable) #True
    isinstance({}, Iterable) #True
    isinstance('abc', Iterable) #True
    isinstance((x for x in range(10)), Iterable)  #True
    
    可以被next()函数调用并不断返回下一个值的对象称为迭代器: Iterator
    可以使用isinstance()判断一个对象是否是Iterator对象:
    from collections import Iterator
    isinstance((x for x in range(10)), Iterator) #True
    isinstance([], Iterator) #False
    isinstance({}, Iterator) #False
    isinstance('abc', Iterator) #False
    #生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
    
    #把list、dict、str等Iterable变成Iterator可以使用iter()函数:
    

    凡是可作用于for循环的对象都是Iterable类型;
    凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

    集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

    Python的for循环本质上就是通过不断调用next()函数实现的.

    函数式编程

    1.高阶函数

    • 变量可以指向函数
    • 函数名也是变量
    • 传入函数
      既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

    2.map/reduce

    Python内建了map()和reduce()函数。
    map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

    def f(x):
        return x * x
    r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
    list(r) #[1, 4, 9, 16, 25, 36, 49, 64, 81]
    
    

    reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

    reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
    #例子
    from functools import reduce
    def fn(x, y):
        return x * 10 + y
    reduce(fn, [1, 3, 5, 7, 9]) #13579
    

    3.filter

    Python内建的filter()函数用于过滤序列。
    和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

    4.sorted

    Python内置的sorted()函数就可以对list进行排序:

    sorted([36, 5, -12, 9, -21]) #[-21, -12, 5, 9, 36]
    sorted([36, 5, -12, 9, -21], key=abs) #[5, 9, -12, -21, 36]
    #可实现忽略大小写的排序
    sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
    #要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True:
    sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
    

    2.返回函数

    返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
    如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:

    3.匿名函数

    list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
    #通过对比可以看出,匿名函数lambda x: x * x实际上就是:
    def f(x):
       return x * x
    #关键字lambda表示匿名函数,冒号前面的x表示函数参数。
    

    4.装饰器

    函数对象有一个name属性,可以拿到函数的名字:
    现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
    本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,可以定义如下:

    
    def log(func):
        def wrapper(*args, **kw):
            print('call %s():' % func.__name__)
            return func(*args, **kw)
        return wrapper
    #观察上面的log,因为它是一个decorator,所以接受一个函数作为参数,并返回一个函数。
    # 我们要借助Python的@语法,把decorator置于函数的定义处:
    
    @log
    def now():
        print('2015-3-25')
    #调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:
    
    #wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。
    # 在wrapper()函数内,首先打印日志,再紧接着调用原始函数。
    
    #如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。
    def log(text):
        def decorator(func):
            def wrapper(*args, **kw):
                print('%s %s():' % (text, func.__name__))
                return func(*args, **kw)
            return wrapper
        return decorator
    #这个3层嵌套的decorator用法如下:
    
    @log('execute')
    def now():
        print('2015-3-25')
    
    #now = log('execute')(now)
    
    #不需要编写wrapper.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的,
    # 所以,一个完整的decorator的写法如下:
    
    import functools
    
    def log(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('call %s():' % func.__name__)
            return func(*args, **kw)
        return wrapper
    
    def log(text):
        def decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kw):
                print('%s %s():' % (text, func.__name__))
                return func(*args, **kw)
            return wrapper
        return decorator
    

    偏函数

    #int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:
    int('12345')
    #但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换:
    int('12345', base=8) #5349
    #假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,
    # 我们想到,可以定义一个int2()的函数,默认把base=2传进去:
    def int2(x, base=2):
        return int(x, base)
    
    # functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2:
    import functools
    int2 = functools.partial(int, base=2)
    #所以,简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),
    #返回一个新的函数,调用这个新函数会更简单。
    #注意到上面的新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值:
    int2('1000000', base=10)
    #最后,创建偏函数时,实际上可以接收函数对象、*args和**kw这3个参数,当传入:
    
    int2 = functools.partial(int, base=2)
    max2 = functools.partial(max, 10)
    #实际上会把10作为*args的一部分自动加到左边,也就是:
    
    max2(5, 6, 7) #相当于:
    args = (10, 5, 6, 7)
    

    相关文章

      网友评论

          本文标题:python基础语法2

          本文链接:https://www.haomeiwen.com/subject/hcuukftx.html