hi,朋友们大家好,今天将英文原著作者 @yasoob《Intermediate Python》进行翻译和在工作中使用的Python技巧进行了总结。Gitbook里面有翻译的版本,大家可以下载下来看看。我今天主要是将该英文原著翻译成适合自己的理解的语言,并附加一些自己在工作中使用Python的技巧。废话少说,下面我们依次来学习一下@yasoob的原著。
如果在翻译过程中有问题或者code无法运行,还请各位大侠指正。
我们在函数定义时,会经常使用*args和**kwargs这两个魔法变量,特别是函数参数数量不确定或参数较多时。当然*args和**kwargs这两个name并不是惟一的name,可以改成*as和**kwas,只要在命名前面加上修饰符*和**即可。我们先来看一下*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
将不定长度的键值对作为参数传递给函数,我们来看一下。
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
我们在生产和测试环境很少安装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模式。 无论是命令行模式还是嵌套代码模式所有调试代码的命令都是一样的,主要有如下几个快捷键:
Generators(生成器)很多教程在讲解Generators都会先讲解Iter(迭代器),因为生成器大多数场景都是基于迭代器的。所以我们先来了解学习一些迭代器相关的内容。
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,reduce这三个函数式python的buildin函数,是一个开箱即用的函数,更是Python提供面向函数编程的一个优势。我们先来看一下这三个函数的原型:
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这是一个过滤的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是将列表结果进行规约处理的,又叫“规约函数”.我们来看一下处理:
from functools import reduce
print(reduce(lambda x,y:x+y,(2,3,4,5)))
##输出为
14
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
由于内容较多,所以分成三个博客篇幅来介绍。