零散整理,可能内容多是pythonic方面的,毕竟每有新知,都很开心。
一、列表推导与lambda函数
之所以把他两放在第一部分,原因有二:比较能体现出python语言的特性、经常使用。
列表推导式
代码说话,简单明了,如数据很大,则使用生成器代替列表使用。
mylist = [1, 4, -5, 10, -7, 2, 3, -1, 0]
[n for n in mylist if n > 0]
# (n for n in mylist if n > 0) # 生成器格式
[n if n > 0 else 0 for n in mylist]# 复杂逻辑判断使用
values = ['1', '2', '-3', '-', '4', 'N/A', '5']
def is_int(val):
pass
ivals = list(filter(is_int, values)) # output:['1', '2', '-3', '4', '5']# 应用场景,当有一张用户表、一张数学成绩表,希望关联并对比打印出数学成绩大于80分的同学。
from itertools import compress
best = [n > 80 for n in score]
list(compress(students, best))
lambda函数
基本形式:lambda argument_list:expersion,表达式中出现的参数需要在argument_list中有定义,并且表达式只能是单行的。
# 使用def定义的函数
def add( x, y ):
return x + y# 使用lambda的表达式
lambda x, y: x + y# lambda也允许有默认值和使用变长参数
lambda x, y = 2: x + y
lambda *z: z# 调用lambda函数
>>> a = lambda x, y: x + y
>>> a( 1, 3 )
4>>> b = lambda x, y = 2: x + y
>>> b( 1 )
3>>> b( 1, 3 )
4>>> c = lambda *z: z
>>> c( 10, 'test')
(10, 'test')# 直接传递实参
(lambda x:x**2)(3)
9
pep8的规范:PEP 8 -- Style Guide for Python Code,Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier.
pep8不推荐作为短函数命名使用,建议直接def,但直接匿名函数还是可以的。
结合map、filter、sorted的使用的一些例子:
fliter(lambda x:x%3==0,[1,2,3,4,5,6])
a=[('b',3),('a',2),('d',4),('c',1)]
sorted(a,key=lambda x:x[0])from functools import reduce
print(reduce(lambda a,b:'{},{}'.format(a,b),[1,2,3,4,5,6,7,8,9]))
二、面向对象特性
类的方法共享,属性不共享,是问题的关键,有助于思考构建什么样的类、怎么用。
数据封装、继承和多态是面向对象的三大特点。
一个继承list类的例子
class AthleteList(list):
def __init__(self, a_name, a_dob=None, a_times=[]):
list.__init__([]) self.name = a_name
self.dob = a_dob self.extend(a_times)def top3(self):
return (sorted(set([sanitize(t) for t in self])) [0:3])
可变参数
允许函数接受过量的参数,不用显式声明参数,python中他们的次序是重要的。
位置参数,*args,让函数接受任意多的位置参数。python把参数收集到一个元组中,作为变量args。显式声明的参数之外如果没有位置参数,这个参数就作为一个空元组。
关键字参数,**kwargs,kwargs是一个正常的python字典类型,包含参数名和值。如果没有更多的关键字参数,kwargs就是一个空字典。
另外一种用法是,调用函数时利用参数列表传参。
def add(a, b, c):
return a + b + cadd(1, 2, 3)
add(a=4, b=5, c=6)
args = (2, 3)
add(1, *args)
kwargs={'b': 8, 'c': 9}
add(a=7, **kwargs) # all is OK.add(a=7, *args)
# TypeError: add() got multiple values for keyword argument 'a'
# 当传递一个元组作为过量的位置参数时,不能显式的传递关键字参数,python不能决定那个值是给a的。add(1, 2, a=7)
TypeError: add() got multiple values for keyword argument 'a'
函数式编程
略。
三、yield与迭代器
犹记得2019年努力学习的时候,看到youtube的一个视频,叫做《迭代器与生成器,最后的前沿》,可惜人懒事多,又是英文听着耗时,不了了之。
但这并不妨碍我两年后再来学习总结一下嘛,朝花夕拾,哈哈。
迭代是一种操作;可迭代是对象的一种特性。
如果一个函数包含 yield 表达式,那么它是一个生成器函数;调用它会返回一个特殊的迭代器,称为生成器。
也可以用生成器表达式,即用()替代常用的列表表达式即可。
总结下,很多都是可迭代的,迭代器通过__next__返回元素,生成器是较之迭代器更加优雅的方式。
四、常用工具包
itertools
迭代器最大的优势就是延迟计算,按需使用,从而提高开发体验和运行效率。
import itertools
x = itertools.combinations(range(4), 3)
print(list(x)) # 求列表或生成器中指定数目的元素不重复的所有组合x = itertools.permutations(range(4), 3) # 顺序相关的所有排列。
x = itertools.combinations_with_replacement('ABC', 2) # 允许重复的组合
x = itertools.product('ABC', range(3)) # 两个列表的笛卡尔积
x = itertools.dropwhile(lambda e: e < 5, range(10)) # itertools.takewhile,相反的
print(list(x)) # 按照真值函数丢弃掉列表和迭代器前面的元素(再结合个tee使用就好的很)
# itertools.filterfalse看上去是差不多的功能。x = itertools.islice(range(10), 0, 9, 2)
print(list(x)) # 对迭代器进行切片。x = itertools.zip_longest(range(3), range(5)) # 较之zip,可以保留最长列表的长度。
y = zip(range(3), range(5))x = itertools.tee(range(10), 2)
# 生成多个迭代器(返回列表,列表中的每个迭代器还是只能用一次)
collections
包含了一些特殊的容器类型,大致了解有啥就好,按需使用,常用操作和set有点像。
OrderedDict类:排序字典,是字典的子类。
defaultdict:使用工厂函数创建字典,使不用考虑缺失的字典键。
namedtuple()函数:命名元组,是一个工厂函数
Counter类:为hashable对象计数,是字典的子类
deque:双向队列。
functools
提供Python 高阶函数相关的函数,functools 模块中函数有 cmp_to_key、partial、reduce、total_ordering、 update_wrapper、wraps。
reduce,之所以出现在这里就是因为 Guido 的独裁,他并不喜欢函数式编程中的“map-reduce”概念,因此打算将 map 和 reduce 两个函数移出内建函数库,最后在社区的强烈反对中将 map 函数保留在了内建库中(哈哈哈)。
enumate
for i,num in enumerate(number_list):
print(f'当前索引位置:{i}')
print(f'当前元素:{num}') # 类似的,字典类型用items(),复杂数据操作时非常好用。
zip
将多个列表、元组或其它序列成对组合成一个元组列表,可以处理任意多的序列,但最终元素的个数取决于最短的序列。
couple_zip_list = list(zip(man_list,woman_list))
# zip解包,解出来的部署列表,是元组。
man_tuple,woman_tuple = zip(*couple_list)
# man_tuple,('黄晓明', '刘恺威', '贾乃亮')
附,参考资料:
1、Python列表推导以及过滤,http://yangcongchufang.com/python-list-elem-filter.html
2、log1p(x) 和 expm1(x) 函数的实现,https://blog.csdn.net/liyuanbhu/article/details/8544644
3、Python函数式编程——匿名函数lambda,http://www.pythoner.com/18.html
4、细说Python的lambda函数用法,建议收藏,https://zhuanlan.zhihu.com/p/80960485
5、Python减少代码量的两个内置函数,https://zhuanlan.zhihu.com/p/90844971
6、相见恨晚的itertools库,https://segmentfault.com/a/1190000008590958
7、Python标准库——collections模块的Counter类,http://www.pythoner.com/205.html
8、Python functools 模块,https://blog.windrunner.me/python/functools.html
9、一篇文章搞懂Python中的面向对象编程,http://yangcongchufang.com/%E9%AB%98%E7%BA%A7python%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80/python-object-class.html
10、Python 中的黑暗角落(一):理解 yield 关键字,https://liam.page/2017/06/30/understanding-yield-in-python/
11、Iterables vs. Iterators vs. Generators,https://nvie.com/posts/iterators-vs-generators/
彩蛋
很有意思的一个小知识点,log1p(x)和expm1(x)有啥用,再简单一点,log(x)和log1p有啥区别。
计算机类的工科一般会学一门课程叫做《数值分析》(我很喜欢这门课,可惜授课老师很渣),浮点数运算过程中损失有效数字,一般发生在两个相近的或相差很大的值相减时。
log1p就是求log(1+x),实现的算法很多,详见参考资料2,我的理解主要还是用泰勒公式去逼近,提高有效数字。
至于为什么要计算log(1+x)而不是log(x),本质上还是精度的问题,如下:








网友评论