Python进阶(上)

《Intermediate Python》阅读笔记 上半部分

args 和 ***kwargs**

  • 不是必须写成*args 和**kwargs。 只有变量前⾯的 * 才是必须的

*args的用法

  • 将不定数量的参数传递给⼀个函数

  • 发送⼀个⾮键值对的可变数量的参数列表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def test_var_args(f_arg, *argv): 
    print("first normal arg:", f_arg)
    for arg in argv:
    print("another arg through *argv:", arg)

    test_var_args('yasoob', 'python', 'eggs', 'test')

    # 输出:
    first normal arg: yasoob
    another arg through *argv: python
    another arg through *argv: eggs
    another arg through *argv: test

**kwargs的用法

  • 将不定长度的键值对,作为参数传递给⼀个函数——适合在一个函数中处理带有名字的参数

    1
    2
    3
    4
    5
    6
    def greet_me(**kwargs):
    for key, value in kwargs.items():
    print("{0} == {1}".format(key, value))

    >>> greet_me(name="yasoob")
    name == yasoob
  • 所有参数(包括标准参数)的使用:

    1
    some_func(fargs, *args, **kwargs)

调试(Debugging)

  • Python debugger(pdb)

    1
    $ python -m pdb my_script.py
    • debugger在脚本第⼀⾏指令处停⽌执⾏
    • 可以通过pdb模式接着查看变量信息
  • 脚本内部设置断点,在某些特定点查看变量信息和各种执⾏时信息

    1
    2
    3
    4
    5
    import pdb
    def make_bread():
    pdb.set_trace()
    return "I don't have time"
    print(make_bread())
    • 运⾏时进⼊debugger模式
    • 命令列表
      • c: 继续执⾏
      • w: 显⽰当前正在执⾏的代码⾏的上下⽂信息
      • a: 打印当前函数的参数列表
      • s: 执⾏当前代码⾏,并停在第⼀个能停的地⽅(相当于单步进⼊)
      • n: 继续执⾏到当前函数的下⼀⾏,或者当前⾏直接返回(单步跳过)

生成器(Generators)

  • 迭代器(iterators)

    • 可以遍历⼀个容器(特别是列表)对象
    • 任意定义了__next__方法的对象
  • 可迭代对象(Iterable):Python 中任意的对象,只要定义可以返回⼀个迭代器的__iter__⽅法,或支持下标索引的__getitem__方法

  • 迭代(Iteration):从某地方取出一个元素的过程

  • 生成器:只能对其迭代一次的迭代器

    • 运行时生成值

    • 通过遍历使用

      • for循环

      • 将生成器传递给任意可迭代的函数和结构

      1
      2
      3
      4
      5
      def generator_function():
      for i in range(10):
      yield i
      for item in generator_function():
      print(item) # 最终打印出数字0-9
    • 应用场景:不想同⼀时间将所有计算出来的⼤量结果分配到内存

      1
      2
      3
      4
      5
      6
      7
      8
      # 计算斐波那契数列
      def fibon(n):
      a = b = 1
      for i in range(n):
      yield a
      a, b = b, a + b
      for x in fibon(1000000):
      print(x)
    • 可迭代对象不一定是迭代器——⽀持迭代,但不能直接对其进⾏迭代操作

      1
      2
      3
      my_string = "Yasoob"
      next(my_string) # 内置函数,用于获取⼀个序列的下⼀个元素
      >>>Output: Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: str object is not an iterator
      • iter():根据⼀个可迭代对象返回⼀个迭代器对象

MapFilterReduce

  • Map

    1
    map(function_to_apply, list_of_inputs)
  • 将⼀个函数映射到⼀个输⼊列表的所有元素上

  • 适用于“需要把列表中所有元素⼀个个地传递给⼀个函数”甚至一组函数的情况

    1
    2
    3
    4
    5
    6
    7
    8
    def multiply(x):
    return (x*x)
    def add(x):
    return (x+x)
    funcs = [multiply, add]
    for i in range(5):
    value = map(lambda x: x(i), funcs)
    print(list(value)) # 返回迭代器
  • Filter
  • 过滤列表中的元素,返回⼀个由所有符合要求的元素所构成的列表——即函数映射到该元素时返回值为True

    1
    2
    number_list = range(-5, 5)
    less_than_zero = filter(lambda x: x < 0, number_list)
  • Reduce

    • 要对⼀个列表进⾏⼀些计算并返回结果

      1
      2
      3
      # 计算阶乘
      from functools import reduce
      product = reduce( (lambda x, y: x * y), [1, 2, 3, 4] )

set 数据结构

  • 不包含重复的值

  • 两个结合的交集

    1
    input_set1.intersection(input_set2)
  • 两个集合的差集

    1
    input_set1.difference(input_set2)

三元运算符

  • 伪代码:condition_is_true if condition else condition_is_false

    1
    2
    is_fat = True
    state = "fat" if is_fat else "not fat"
  • 简单的⼀⾏快速判断

装饰器

前述

  • 函数赋值给一个变量

    1
    2
    3
    4
    def hi(name="yasoob"):
    return "hi " + name
    greet = hi
    print(greet())
  • 函数嵌套函数

  • 函数中返回函数——一个函数作为变量被返回

  • 函数作为参数传递给另一个函数

装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 原理
def a_new_decorator(a_func):
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
def a_function_requiring_decoration():
print("I am the function which needs some decoration to remove my foul smell")
a_function_requiring_decoration()
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
#now a_function_requiring_decoration is wrapped by wra
a_function_requiring_decoration()
##now a_function_requiring_decoration is wrapped by wrapTheFunction()
# I am the function which needs some decoration to remove my foul smell
# I am doing some boring work after executing a_func()

#使用@:
@a_new_decorator
def a_function_requiring_decoration():
print("I am the function which needs some decoration to " "remove my foul smell")
a_function_requiring_decoration()
#outputs: I am doing some boring work before executing a_func()
# I am the function which needs some decoration to remove my foul smell
# I am doing some boring work after executing a_func()
  • 但@重写了函数的名字和注释⽂档,即a_function_requiring_decoration.__name__wrapTheFunction——@wraps接受⼀个函数进⾏装饰,并具有复制函数名称、注释⽂档、参数列表等功能

  • from functools import wraps
    def a_new_decorator(a_func):
        @wraps(a_func)
        ...
    @a_new_decorator
    def a_function_requiring_decoration():
        pass
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    * 蓝本规范

    ```python
    from functools import wraps
    def decorator_name(f):
    @wraps(f)
    def decorated(*args, **kwargs):
    if not can_run:
    return "Function will not run"
    return decorated

    @decorator_name
    def func():
    return("Function is running")
    can_run = True
    func()
  • 应用

    • 授权:⽤于Flask和Django web框架

    • 日志

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      from functools import wraps
      def logit(logfile='out.log'):
      @wraps(func)
      def with_logging(*args, **kwargs):
      log_string = func.__name__ + " was called"
      print(func.__name__ + " was called")
      with open(logfile, 'a') as opened_file:
      opened_file.write(log_string + '\n')
      return func(*args, **kwargs)
      return with_logging
      @logit(logfile='func2.log')
      def addition_func(x):
      """Do some math."""
      return x + x
      result = addition_func(4) # Output: addition_func was called func2.log 的⽂件出现,并记录上⾯的字符串
  • 带参数的装饰器

    • 具体参见上面的日志应用场景

Global 和 Return

  • global变量:在函数以外的区域都能访问
  • 返回多个变量

slots

  • 默认情况下Python⽤⼀个字典来保存⼀个对象的实例属性

  • 对于有着已知属性的⼩类来说,这个字典浪费了许多内存——最好直接分配⼀个固定量的内存来保存所有的属性,即使用__slot__给一个固定集合的属性分配空间

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 不使⽤ __slots__
    class MyClass(object):
    def __init__(self, name, identifier):
    self.name = name
    self.identifier = identifier
    self.set_up()
    pass
    # 使⽤ __slots__,为内存减轻负担
    class MyClass(object):
    __slots__ = ['name', 'identifier']
    def __init__(self, name, identifier):
    self.name = name
    self.identifier = identifier
    self.set_up()
    pass