Python进阶教程(一)

时间:2022-05-07
本文章向大家介绍Python进阶教程(一),主要内容包括概述、Intermediate Python 中译、Debugging、Generators、map,filter and reduce、set data struct、三元运算符、总结、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

概述

hi,朋友们大家好,今天将英文原著作者 @yasoob《Intermediate Python》进行翻译和在工作中使用的Python技巧进行了总结。Gitbook里面有翻译的版本,大家可以下载下来看看。我今天主要是将该英文原著翻译成适合自己的理解的语言,并附加一些自己在工作中使用Python的技巧。废话少说,下面我们依次来学习一下@yasoob的原著。

Intermediate Python 中译

如果在翻译过程中有问题或者code无法运行,还请各位大侠指正。

*args和**kwargs

我们在函数定义时,会经常使用*args和**kwargs这两个魔法变量,特别是函数参数数量不确定或参数较多时。当然*args和**kwargs这两个name并不是惟一的name,可以改成*as和**kwas,只要在命名前面加上修饰符*和**即可。我们先来看一下*args。

*args

def test_args_kwargs(name,*args):
    print("frist arg: ",name)
    for arg in args:
        print("another arg through *argv: ",arg)

test_args_kwargs("brian","eric","rose")
#输出为
frist arg:  brian
another arg through *argv:  eric
another arg through *argv:  rose

我们也可以通过参数列表进行传递,比如:

names=("brian","eric","rose")
test_args_kwargs(*names)
frist arg:  brian
another arg through *argv:  eric
another arg through *argv:  rose

**kwargs

将不定长度的键值对作为参数传递给函数,我们来看一下。

def greet_me(**args):
    for key,value in args.items():
        print("{0}=={1}".format(key,value))

greet_me(name="brian",age=20,sex="男")
#输出为
name==brian
age==20
sex==男

或者也可以这样

person = {"name":"brian","age":20,"sex":"男"}
greet_me(**person)
#输出为
name==brian
age==20
sex==男

如何使用

在很多场景里面都大量使用比如: 1.装饰器 2.函数定义 3.单元测试 4.猴子补丁(在运行时修改某些代码),在英文版本里面主要介绍了通过猴子补丁修改API来进行测试。 ……

import someclass

def get_info(self,*args):
	return "Test Data"
someclass.get_info=get_info

Debugging

我们在生产和测试环境很少安装IDE进行调试的,如有有紧急需要修改或者出现问题如何快速排查问题和定位问题是非常重要的意见事情,也是主要衡量一个工程师水平的一个标准。那么在Python是如何做呢? 1.日志,不仅在关键的业务处理进行相应的日志输出,也要在入口和出口进行详细的日志处理。 2.Debugging,我们可以通过pdb、ipdb和jupyter进行有效的调试。 3.python docstring一定规范写好,方便调试和定位问题,特别是研发人员的流失比较严重时。 ……

我们今天来看一下通过pdb通过命令行和嵌套debug代码这两种方式都可以调试代码。我们来看一下, 1.命令行运行

python -m pdb test.py

2.嵌套代码

import pdb
def method(*args,**kwargv):
	pdb.set_trace()
	...
method(name="sasa")

当函数调用时进入debug模式。 无论是命令行模式还是嵌套代码模式所有调试代码的命令都是一样的,主要有如下几个快捷键:

  • c:继续在当前程序上下文执行直到遇到断点或者trace位置为止,即继续执行。
  • w:显示当前执行程序上下文信息。
  • a:打印当前函数的参数列表。
  • s:执行当前代码行。
  • n:执行下一行的代码。

Generators

Generators(生成器)很多教程在讲解Generators都会先讲解Iter(迭代器),因为生成器大多数场景都是基于迭代器的。所以我们先来了解学习一些迭代器相关的内容。

  • Iterable(可迭代对象):Python即对象,呵呵。Python的任意对象定了返回__iter__方法或者支持下标的__getitem__方法,它就是一个可迭代的对象。可迭代对象就是提供迭代器的任何对象
  • Iterator(迭代器):一般是指定义了__next__方法的对象。
  • Iteration(迭代):字面意思,不言而喻。实在不理解的,可以简单的理解为循环。

Generators也是一种迭代器,只不过你只能对其只能迭代一次,它并不是列表这种集合类型的数据保存在内存中,而是保存的是运行时的某个值。主要是通过yield来终止并暂存运行时栈,相当于保护现场进而为下次迭代提供记录和便利。特别一次性不需要全部结果集时显得非常重要。 我们来看一个简单的例子:

def fibon(n):
    a=b=1
    for i in range(n):
        yield a
        a,b=b,a+b

for i in fibon(3):
    print(i)
#输出为
1
1
2
#通过next方法来进行获取生成器的下一个迭代
gen_fibon = fibon(3)
print(next(gen_fibon))
print(next(gen_fibon))
print(next(gen_fibon))
#输出结果为
1
1
2
#如果我们再进行下一个迭代时,会出现Exception,这说明我们的迭代已经完成,生成器已经没有再生成Python对象。
print(next(gen_fibon))
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-18-5f779bae9fed> in <module>()
----> 1 next(gen_fibon)

StopIteration:

我们来看一下python的string类型是不是可以直接通过迭代器来获取元素。比如:

name="brian"
next(name)
#输出结果为,告诉我们python的str了O型不是一个迭代器,那么就无法进行迭代。所以我们需要将str对象模型变成可迭代的python对象数据模型,只需要通过iter(object)方法即可。
TypeError: 'str' object is not an iterator
#代码修改
iter_name = iter(name)
next(iter_name)

iter(object)是将一个可迭代的对象变为一个迭代器对象,从而通过next来获取数据。

map,filter and reduce

map,filter,reduce这三个函数式python的buildin函数,是一个开箱即用的函数,更是Python提供面向函数编程的一个优势。我们先来看一下这三个函数的原型:

  • map(function_apply,array/list_inputs)
  • filter(function_apply,array/list_inputs)
  • reduce(function_apply,array/list_inputs)

map

map在处理并行计算提供了极大的便利,巧妙的使用map可以使自己的application变得快速和代码优化。我们先看一个简单的例子:

temp=[2,7,14,18]
list(map(lambda x: x**2,temp))
#输出结果为:
[4, 49, 196, 324]

lambda 函数式python的匿名函数,处理逻辑简单开箱即用的“一行函数”。,当然我们也可以将输入统一,具体行为或者业务不一致的code分装成函数,将具体执行各自的任务和逻辑单元。比如:

def add(x):
    return x+x

def multiply(x):
    return x*x
funcs=(add,multiply)

for i in range(5):
    print(list(map(lambda func:func(i),funcs)))
#输出为
[0, 0]
[2, 1]
[4, 4]
[6, 9]
[8, 16]

filter

filter这是一个过滤的build-in函数,它的作用主要在于过滤行为。

nums=range(-5,5)
less_than_zero=list(filter(lambda x:x<0,nums))
#输出为
[-5, -4, -3, -2, -1]

在后面的我们会介绍列表推导式也很方便,我可以改一下该例子。

list(i for i in nums if i<0)
#输出结果为同样的

reduce

reduce是将列表结果进行规约处理的,又叫“规约函数”.我们来看一下处理:

from functools import reduce
print(reduce(lambda x,y:x+y,(2,3,4,5)))
##输出为
14

set data struct

python中的set数据结构是等价于数学意义上的集合。数学意义上的集合最重要的性质有:唯一性,可重复性,无序性。那么在Python的set数据结构中数据元素也是表现如此。我们来看一个得到重复元素的例子。

str_nums=('a','a','b','c','c','c','d','e','f')
duplicates=set([x for x in str_nums if str_nums.count(x)>1])
print(duplicates)
{'a', 'c'}
当然你也可以使用collection的Counter去处理
from collections import Counter
print(Counter(str_nums))
##输出为
Counter({'a': 2, 'b': 1, 'c': 3, 'd': 1, 'e': 1, 'f': 1})

和set相关的操作自然想到交集、并集合差集。下面我们依次看一下Python提供的API。

colors=set({'red','yellow','green'})
input_colors=set({'red','blue'})
#交集API
print(input_colors.intersection(colors))
#输出
{'red'}
#差集API
print(input_colors.difference(colors))
#输出
{'blue'}
#并集API
print(input_colors.union(colors))
#输出
{'blue', 'green', 'red', 'yellow'}

值得注意的是set的定义是通过{}来定义的或者通过set()初始化来定义。

三元运算符

三元运算符和其它语言的三元运算符所表达的语义是相同的,只是形式不一样。我们来看下: condition_true if condition else condition_is_false

flag = True
print("Brian" if flag else "Not Brian")
#输出
Brian

总结

由于内容较多,所以分成三个博客篇幅来介绍。