Python 学习笔记二

高级特性

切片

如果想取数组中的部分元素,则可以通过在数组中使用 [start:end] 实现,类似于JavaScript中的 slice(start, end);其中start和end都可以为负数,表示以倒数的方式来计算,也可以只写一个负数,也可以什么都不写只有一个:,表示复制整个数组。

如果是::,表明每隔一段来取一个,比如:

>>> 'ABCDEFG'[::2]
'ACEG'

也可以这么写,前6个数每2个取1个:

>>> 'ABCDEFG'[:6:2]
'BDF'

切片适用于类似数组的类型,比如 字符串,list,tuple等等。

迭代

在python中,迭代使用的是for...in...关键字,同时只要是可迭代对象,都可以迭代,比如json对象等等。

那么,如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:

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

列表生成式

将所有的表达式放到[]里面去执行:

>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]

生成器

怎么创建一个生成器呢?

  1. 列表生成式中外围的[]改为()即可

    可以通过next函数获取generator的下一个返回值。

    >>> L = [x * x for x in range(10)]
    >>> L
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    >>> g = (x * x for x in range(10))
    >>> g
    <generator object <genexpr> at 0x1022ef630>
    
    >>> next(g)
    0
    >>> next(g)
    1
  2. 在函数中使用yield关键字,其作用类似于return+print

    def odd():
        print('step 1')
        yield 1
        print('step 2')
        yield(3)
        print('step 3')
        yield(5)

    在执行过next后,再次执行的时候则从上一次执行yield后的位置继续执行,遇见yield则返回,但是如果执行到后面已经没有yield后,则会报错。

    >>> o = odd()
    >>> next(o)
    step 1
    1
    >>> next(o)
    step 2
    3
    >>> next(o)
    step 3
    5

    如果不想用next,一步一步的计算,同样的可以使用循环。

    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            yield b
            a, b = b, a + b
            n = n + 1
        return 'done'
    
    >>> for n in fib(6):
    ...     print(n)
    ...
    1
    1
    2
    3
    5
    8

    如果想要捕捉到返回值,则在找不到next的时候(异常)返回,例如:

    >>> g = fib(6)
    >>> while True:
    ...     try:
    ...         x = next(g)
    ...         print('g:', x)
    ...     except StopIteration as e:
    ...         print('Generator return value:', e.value)
    ...         break
    ...
    g: 1
    g: 1
    g: 2
    g: 3
    g: 5
    g: 8
    Generator return value: done

迭代器

注意区分 Iterable和Iterator,前者是可迭代的,后者是迭代器(类似于C++中vector和::iterator),同样的,可以使用isinstance来判断;

函数式编程

高阶函数

map/reduce

map(函数,Iterable),将可迭代对象中的元素执行函数以后生成一个新的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函数必须接收两个参数,一个是函数,一个是list,其重点在于将list中的元素进行函数计算后作用到下一个元素上。

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

比如这么用:

from functools import reduce

def str2int(s):
    def fn(x, y):
        return x * 10 + y
    def char2num(s):
        return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
    return reduce(fn, map(char2num, s))
    

filter

用于过滤序列,返回一个新的序列;

map一样,同样接收一个函数和序列,但不同的是,filter使用函数对序列中的元素进行筛选,也就是说该函数是一个bool函数,将值传递进去后只有返回成功才将该值加入到新的队列中。

def is_odd(n):
    return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 结果: [1, 5, 9, 15]

如果这不是一个筛选函数呢?python则认为均为false,也就是不加入任何元素,返回空序列。

sorted

对序列进行排序,后面还可以加上key来指定排序函数,还可以加上reverse表示反向排序;

class Student:
        def __init__(self, name, grade, age):
                self.name = name
                self.grade = grade
                self.age = age
        def __repr__(self):
                return repr((self.name, self.grade, self.age))

# student_objects = [
#        Student('john', 'A', 15),
#        Student('jane', 'B', 12),
#        Student('dave', 'B', 10),
#]

# 使用lambda
sorted(student_objects, key=lambda student: student.age, reverse=True)   
# sort by age
# [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

# 或者使用attrgetter
sorted(student_objects, key=attrgetter('age'), reverse=True)

闭包

当你调用了一个函数A,这个函数A返回内部的函数B,这个返回的函数B就是闭包;

def func(name):
    def inner_func(age):
        print 'name:', name, 'age:', age
    return inner_func

bb = func('the5fire')
bb(26)  # >>> name: the5fire age: 26

匿名函数

lambda表示匿名函数(和C++ 11.0中的lambda表达式类似),格式为:

lambda x : x * x

冒号前面表示参数,返回值为冒号后面的计算结果。

装饰器

需要单独写一篇文章进行总结(重要)

总之就是在不改变一个函数的前提下(其它调用该函数的也不需要改变,只需要在调用函数前面加上@decorator就行),往该函数上加功能进行任意的扩展。

偏函数

functools.partial表示的是将函数“保存”下来,返回来一个在原来函数的基础上重新定义的函数;

例子:

import functools

def add(a, b):
    return a + b

add(4, 2)
6

plus3 = functools.partial(add, 3)
plus5 = functools.partial(add, 5)

plus3(4)
7

plus5(10)
15

除此之外,functools模块还包括:

  • functool.update_wrapper:从原始对象拷贝或加入现有partial对象
  • functool.wraps:调用函数装饰器partial
  • functools.reduce:等同于内置函数reduce()
  • functools.cmp_to_key:将老式鼻尖函数转换成key函数,用在接受key函数的方法中
  • functools.total_ordering:它是针对某个类如果定义了__lt__、le、gt、__ge__这些方法中的至少一个,使用该装饰器,则会自动的把其他几个比较函数也实现在该类中。

面向对象编程

继承和多态

对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。

对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了:

实例属性和类属性

在编写程序的时候,千万不要把实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性,个人不建议在示例上添加任何新的属性,在类中加上属性即可。

posted @ 2017-04-21 13:59 banananana 阅读(...) 评论(...) 编辑 收藏