首页 > Python基础教程 >
-
Python要点总结,我使用了100个小例子!(2)
mode取值表:
字符 | 意义 |
---|---|
'r' |
读取(默认) |
'w' |
写入,并先截断文件 |
'x' |
排它性创建,如果文件已存在则失败 |
'a' |
写入,如果文件存在则在末尾追加 |
'b' |
二进制模式 |
't' |
文本模式(默认) |
'+' |
打开用于更新(读取与写入) |
48 pow( base , exp [, mod ])
base为底的exp次幂,如果mod给出,取余
In [149]: pow(3, 2, 4)
Out[149]: 1
49 print(objects)
打印对象,此函数不解释
50 class property( fget=None , fset=None , fdel=None , doc=None )
返回 property 属性,典型的用法:
class C:
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
# 使用property类创建 property 属性
x = property(getx, setx, delx, "I'm the 'x' property.")
使用python装饰器,实现与上完全一样的效果代码:
class C:
def __init__(self):
self._x = None
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
51 range(stop)
range(start, stop[,step])
生成一个不可变序列:
In [153]: range(11)
Out[153]: range(0, 11)
In [154]: range(0,11,1)
Out[154]: range(0, 11)
52 reversed( seq )
返回一个反向的 iterator:
In [155]: rev = reversed([1,4,2,3,1])
In [156]: for i in rev:
...: print(i)
...:
1
3
2
4
1
53 round( number [, ndigits ])
四舍五入,ndigits代表小数点后保留几位:
In [157]: round(10.0222222, 3)
Out[157]: 10.022
54 class set([ iterable ])
返回一个set对象,可实现去重:
In [159]: a = [1,4,2,3,1]
In [160]: set(a)
Out[160]: {1, 2, 3, 4}
55 class slice( stop )
class slice( start , stop [, step ])
返回一个表示由 range(start, stop, step) 所指定索引集的 slice对象
In [170]: a = [1,4,2,3,1]
In [171]: a[slice(0,5,2)] #等价于a[0:5:2]
Out[171]: [1, 2, 1]
56 sorted( iterable , *, key=None , reverse=False )
排序:
In [174]: a = [1,4,2,3,1]
In [175]: sorted(a,reverse=True)
Out[175]: [4, 3, 2, 1, 1]
In [178]: a = [{'name':'xiaoming','age':18,'gender':'male'},{'name':'
...: xiaohong','age':20,'gender':'female'}]
In [180]: sorted(a,key=lambda x: x['age'],reverse=False)
Out[180]:
[{'name': 'xiaoming', 'age': 18, 'gender': 'male'},
{'name': 'xiaohong', 'age': 20, 'gender': 'female'}]
57 @ staticmethod
将方法转换为静态方法,不做解释
58 vars()
返回模块、类、实例或任何其它具有 __dict__
属性的对象的 __dict__
属性
In [2]: vars()
Out[2]:
{'__name__': '__main__',
'__doc__': 'Automatically created module for IPython interactive environment',
'__package__': None,
'__loader__': None,
'__spec__': None,
'__builtin__': <module 'builtins' (built-in)>,
'__builtins__': <module 'builtins' (built-in)>,
'_ih': ['', 'vars([1,2,3])', 'vars()'],
'_oh': {},
'_dh': ['C:\\Windows\\system32'],
'In': ['', 'vars([1,2,3])', 'vars()'],
'Out': {},
'get_ipython': <bound method InteractiveShell.get_ipython of <IPython.terminal.interactiveshell.TerminalInteractiveShell object at 0x0000026004D91C50>>,
'exit': <IPython.core.autocall.ExitAutocall at 0x26006011048>,
'quit': <IPython.core.autocall.ExitAutocall at 0x26006011048>,
'_': '',
'__': '',
'___': '',
'_i': 'vars([1,2,3])',
'_ii': '',
'_iii': '',
'_i1': 'vars([1,2,3])',
'_i2': 'vars()'}
59 sum( iterable , / , start=0 )
求和:
In [181]: a = [1,4,2,3,1]
In [182]: sum(a)
Out[182]: 11
In [185]: sum(a,10) #求和的初始值为10
Out[185]: 21
60 super([ type [, object-or-type ]])
返回一个代理对象,它会将方法调用委托给 type 的父类或兄弟类
61 tuple([ iterable ])
虽然被称为函数,但 tuple
实际上是一个不可变的序列类型
62 class type
( object )
class type
( name , bases , dict )
传入一个参数时,返回 object 的类型:
In [186]: type(xiaoming)
Out[186]: __main__.Student
In [187]: type(tuple())
Out[187]: tuple
63 zip
(* iterables )
创建一个聚合了来自每个可迭代对象中的元素的迭代器:
In [188]: x = [3,2,1]
In [189]: y = [4,5,6]
In [190]: list(zip(y,x))
Out[190]: [(4, 3), (5, 2), (6, 1)]
In [191]: a = range(5)
In [192]: b = list('abcde')
In [193]: b
Out[193]: ['a', 'b', 'c', 'd', 'e']
In [194]: [str(y) + str(x) for x,y in zip(a,b)]
Out[194]: ['a0', 'b1', 'c2', 'd3', 'e4']
3 列表生成式
python里面[] 表示一个列表,对容器类型的数据进行运算和操作,生成新的列表最高效、快速的办法,就是列表生成式。它优雅、简洁,值得大家多多使用!今天盘点列表生成式在工作中的主要使用场景。
3.1 入门例子
1
range快速生成连续列表
In [1]: a = range(11)
In [2]: a
Out[2]: range(0, 11)
In [3]: list(a)
Out[3]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2
对列表里面的数据进行运算后重新生成一个新的列表:
In [5]: a = range(0,11)
In [6]: b = [x**2 for x in a]
In [7]: b
Out[7]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
3
对一个列表里面的数据筛选,只计算[0,11) 中偶数的平方:
In [10]: a = range(11)
In [11]: c = [x**2 for x in a if x%2==0]
In [12]: c
Out[12]: [0, 4, 16, 36, 64, 100]
4
前面列表生成式都只传一个参数x,带有两个参数的运算:
In [13]: a = range(5)
In [14]: b = ['a','b','c','d','e']
In [20]: c = [str(y) + str(x) for x, y in zip(a,b)]
In [21]: c
Out[21]: ['a0', 'b1', 'c2', 'd3', 'e4']
3.2 中级例子
5
结合字典,打印键值对:
In [22]: a = {'a':1,'b':2,'c':3}
In [23]: b = [k+ '=' + v for k, v in a.items()]
In [24]: b = [k+ '=' + str(v) for k, v in a.items()]
In [25]: b
Out[25]: ['a=1', 'b=2', 'c=3']
6
输出某个目录下的所有文件和文件夹的名称:
In [33]: [d for d in os.listdir('d:/summary')]
Out[33]: ['a.txt.txt', 'python-100']
7
列表中所有单词都转化为小写:
In [34]: a = ['Hello', 'World', '2019Python']
In [35]: [w.lower() for w in a]
Out[35]: ['hello', 'world', '2019python']
3.3 高级例子
8
将值分组:
In [36]: def bifurcate(lst, filter):
...: return [
...: [x for i,x in enumerate(lst) if filter[i] == True],
...: [x for i,x in enumerate(lst) if filter[i] == False]
...: ]
...:
In [37]: bifurcate(['beep', 'boop', 'foo', 'bar'], [True, True, False, True])
Out[37]: [['beep', 'boop', 'bar'], ['foo']]
9
进一步抽象例子8,根据指定函数fn 对lst 分组:
In [38]: def bifurcate_by(lst, fn):
...: return [
...: [x for x in lst if fn(x)],
...: [x for x in lst if not fn(x)]
...: ]
...:
In [39]: bifurcate_by(['beep', 'boop', 'foo', 'bar'], lambda x: x[0] == 'b')
Out[39]: [['beep', 'boop', 'bar'], ['foo']]
10
返回可迭代对象的差集,注意首先 都把a, b
用set 包装
In [53]: def difference(a, b):
...: _a, _b =set(a),set(b)
...: return [item for item in _a if item not in _b]
...:
...:
In [54]: difference([1,1,2,3,3], [1, 2, 4])
Out[54]: [3]
11
进一步抽象10,根据函数fn 映射后选取差集,如下列表元素分别为单个元素和字典的例子:
In [61]: def difference_by(a, b, fn):
...: ...: _b = set(map(fn, b))
...: ...: return [item for item in a if fn(item) not in _b]
...: ...:
...:
In [62]: from math import floor
...: difference_by([2.1, 1.2], [2.3, 3.4],floor)
Out[62]: [1.2]
In [63]: difference_by([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], lambda v : v['x'])
Out[63]: [{'x': 2}]
12
过滤非重复值,结合list 的count( 统计出元素在列表中出现次数):
In [64]: def filter_non_unique(lst):
...: return [item for item in lst if lst.count(item) == 1]
In [65]: filter_non_unique([1, 2, 2, 3, 4, 4, 5])
Out[65]: [1, 3, 5]
4 Collections
Python有许多很好的库(libraries),实现这些功能只需要几行代码。今天介绍一个库: collections . 这个模块提供容器相关的更高性能的数据类型,它们提供比通用容器 dict , list , set 和 tuple 更强大的功能。
今天介绍其中三种数据类型,最后你可能会惊讶它们怎么这么好用。
4.1 NamedTuple
对于数据分析或机器学习领域,用好namedtuples 会写出可读性强、易于维护的代码。大家回忆这种熟悉的场景,你正在做特征工程,因为你尤其喜爱list, 所以把一堆特征放到一个list 中,然后喂到机器学习模型中。很快,你将会意识到数百个特征位于此list 中,这就是事情变得糟糕的开始。
In [10]: feature = ['age','height','name']
In [11]: data = [[10,1,'xiaoming'],[12,1,5,'xiaohong']]
In [12]: data[0][0] #只能靠整数索引到某个特征,0对应age
Out[12]: 10
某天,你想使用某个特征,这时比较棘手,你不知道它的index!更糟糕的是,当你准备离职要交接工作时,他们看到一个一个的数字型索引,完全对不上哪个和哪个,他们懵逼,你也尴尬。
如果我们使用NamedTuples去处理以上数据,乱为一团的事情将会迅速变得井然有序:
In [4]: Person = namedtuple('Person',['age','height','name'])
In [15]: data2 = [Person(10,1.4,'xiaoming'),Person(12,1.5,'xiaohong')]
In [16]: data2[0].age
Out[16]: 10
仅仅几行代码,我们将会很容易索引到第0行数据的age属性取值,这在实际中真是太好用。你告别indexes访问你的数据集中的特征值,而是使用更加人性化,可读性强的names索引。
NamedTuples会使得代码易读、更易维护。
4.2 Counter
Counter正如名字那样,它的主要功能就是计数。这听起来简单,但是我们在分析数据时,基本都会涉及计数,真的家常便饭。
习惯使用list 的看过来,有一些数值已经放在一个list中:
skuPurchaseCount = [3, 8, 3, 10, 3, 3, 1, 3, 7, 6, 1, 2, 7, 0, 7, 9, 1, 5, 1, 0]
In [33]: for i in skuPurchaseCount:
...: if countdict.get(i) is None:
...: countdict[i]=1
...: else:
...: countdict[i]+=1
In [34]: countdict
Out[34]: {3: 5, 8: 1, 10: 1, 1: 4, 7: 3, 6: 1, 2: 1, 0: 2, 9: 1, 5: 1}
如果使用Counter,我们可以写出更简化的代码:
In [35]: from collections import Counter
In [42]: Counter(skuPurchaseCount).most_common()
Out[42]:
[(3, 5),(1, 4),(7, 3),(0, 2),(8, 1),(10, 1),(6, 1),(2, 1),(9, 1),(5, 1)]
仅仅一行代码,我们便输出统计计数结果,并且是一个按照次数统计出来的由大到小排序好的tuples列表,因此我们很快就会看到,购买3次是出现最多的,一共5次。
购买为1次的占多数,属于长尾。
4.3 DefaultDict
DefaultDict是一个被初始化的字典,也就是每个键都已经被访问一次:
In [53]: d = defaultdict(int)
In [54]: for k in 'collections':
...: d[k] += 1
In [55]: d
Out[55]:
defaultdict(int,
{'c': 2, 'o': 2, 'l': 2, 'e': 1, 't': 1, 'i': 1, 'n': 1, 's': 1})
一般地,当你尝试访问一个不在字典中的值时,将会抛出一个异常。但是defaultdict可以帮助我们初始化,它的参数作为default_factory. 在上面例子中,将生成 int
对象,意思是默认值为int 型,并 设定初始值为0
,所以我们可以很容易地统计每个字符出现的次数。
Simple and clean!
更有用的一个使用场景,我们有很多种商品,在每秒内下单次数的统计数据如下:
In [56]: data = [('iphone11',103), ('华为macbook-SKU1232',210),('iphone11',21),('
...: 华为macbook-SKU1232',100)]
In [57]: d = defaultdict(list)
In [58]: for ele in data:
...: d[ele[0]].append(ele[1])
In [59]: d
Out[59]: defaultdict(list, {'iphone11': [103, 21], '华为macbook-SKU1232': [210, 100]})
上面例子default_dict取值为list, 因此,我们可以立即append一个元素到list中,更简洁。
总结
至此,你已经了解collections库中的三个类型,它们确实太好用,大家可以操练起来了!
5 itertools: 高效节省内存的方法
Python循环这样写,高效节省内存100倍
5.0 前言
说到处理循环,我们习惯使用for, while等,比如依次打印每个列表中的字符:
lis = ['I', 'love', 'python']
for i in lis:
print(i)
I
love
python
在打印内容字节数较小时,全部载入内存后,再打印,没有问题。可是,如果现在有成千上百万条车辆行驶轨迹,叫你分析出其中每个客户的出行规律,堵车情况等,假如是在单机上处理这件事。
你可能首先要面临,也可能被你忽视,最后代码都写好后,才可能暴露出的一个问题: outofmemory
, 这在实际项目中经常遇到。
这个问题提醒我们,处理数据时,如何写出高效利用内存的程序,就显得很重要。今天,我们就来探讨如何高效利用内存,节省内存同时还能把事情办好。
其实,Python已经准备好一个模块专门用来处理这件事,它就是 itertools
模块,这里面几个函数的功能其实很好理解。
我不打算笼统的介绍它们所能实现的功能,而是想分析这些功能背后的实现代码,它们如何做到高效节省内存的,Python内核的贡献者们又是如何写出一手漂亮的代码的,这很有趣,不是吗?
OK,let's go. Hope you enjoy the journey!
5.1 拼接元素
itertools 中的chain 函数实现元素拼接,原型如下,参数*表示个数可变的参数
chain
( iterables )
应用如下:
In [33]: list(chain(['I','love'],['python'],['very', 'much']))
Out[33]: ['I', 'love', 'python', 'very', 'much']
哇,不能再好用了,它有点join的味道,但是比join强,它的重点在于参数都是可迭代的实例。
那么,chain如何实现高效节省内存的呢?chain大概的实现代码如下:
def chain(*iterables):
for it in iterables:
for element in it:
yield element
以上代码不难理解, chain本质返回一个生成器,所以它实际上是一次读入一个元素到内存,所以做到最高效地节省内存
。
5.2 逐个累积
返回列表的累积汇总值,原型:
accumulate
( iterable [, func , *, initial=None ])
应用如下:
In [36]: list(accumulate([1,2,3,4,5,6],lambda x,y: x*y))
Out[36]: [1, 2, 6, 24, 120, 720]
accumulate大概的实现代码如下:
def accumulate(iterable, func=operator.add, *, initial=None):
it = iter(iterable)
total = initial
if initial is None:
try:
total = next(it)
except StopIteration: