Python3进阶

zip

zip(*iterables)

  • zip函数可以接受一系列的可迭代对象作为参数,将对象中对应的元素打包成一个个tuple(元组),然后由这些tuple(元组)组成一个list(列表)返回。

E.g.1:

a = [1, 2, 3, 4, 5]
b = ['a', 'b', 'c', 'd', 'e']
c = zip(a, b)
print(type(c))
print(c)  # 返回zip对象而不是内容
print(list(c))
<class 'zip'>
<zip object at 0x00000143FAE1AF80>
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')]
  • 如果传入的可迭代对象的长度不一致,则返回可迭代对象中最短的一个对象的长度

E.g.2:

a = [1, 2, 3, 4, 5]
b = ['a', 'b', 'c', 'd']
c = zip(a, b)
print(list(c))
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]

E.g.3:

names = ["zhangsan", "lisi", "wangwu", "zhaoliu", "sunqi"]
weights = [72, 68, 72, 66, 76]

user_weight = dict(zip(names, weights))
print(user_weight)
{'zhangsan': 72, 'lisi': 68, 'wangwu': 72, 'zhaoliu': 66, 'sunqi': 76}

实例:

机器学习模型训练中,经常需要打乱数据集,用 zip() 函数可以实现如下:

import random
X = [1, 2, 3, 4, 5, 6]
y = [0, 1, 0, 0, 1, 1]
zipped_data = list(zip(X, y))
# 将样本和标签一 一对应组合起来,并转换成list类型方便后续打乱操作
random.shuffle(zipped_data)
# 使用random模块中的shuffle函数打乱列表,原地操作,没有返回值
new_zipped_data = list(map(list, zip(*zipped_data)))
# zip(*)反向解压,map()逐项转换类型,list()做最后转换
new_X, new_y = new_zipped_data[0], new_zipped_data[1]
# 返回打乱后的新数据
print('X:', X, '\n', 'y:', y)
print('new_X:', new_X, '\n', 'new_y:', new_y)

输出结果(因未设置随机种子seed,因此每次运行结果可能不一样):

X: [1, 2, 3, 4, 5, 6]
 y: [0, 1, 0, 0, 1, 1]
new_X: [6, 1, 5, 2, 3, 4]
 new_y: [1, 0, 1, 1, 0, 0]

enumerate

enumerate(iterable, start=0)

  • enumerate函数可以同时返回列表和元组等可迭代对象的下标和内容,但实际上,enumerate函数实际返回的是一个enumerate类型的可迭代对象。

E.g.1:

seq = [1, 2, '3', 'hello world']
for i, element in enumerate(seq):
    print(i, element)
0 1
1 2
2 3
3 hello world
  • 同样,enumerate返回一个可迭代的对象

E.g.2:

seq = [1, 2, '3', 'hello world']
print(type(enumerate(seq)))
print(enumerate(seq))
print(list(enumerate(seq)))
<class 'enumerate'>
<enumerate object at 0x000001FC9787AFC0>
[(0, 1), (1, 2), (2, '3'), (3, 'hello world')]

map

map(function, iterable, ...)

  • map对list中每一个元素都调用function函数进行处理,返回一个新的列表。

E.g.1

d = [1, 2, 3]


def func(s):
    return s * 100


print(map(func, d))
print(type(map(func, d)))
print(list(map(func, d)))
<map object at 0x0000019A46BF5E50>
<class 'map'>
[100, 200, 300]
  • map可以处理多个可迭代的对象,如果传入的可迭代对象的长度不一致,则返回可迭代对象中最短的一个对象的长度。

E.g.2:

d = [1, 2, 3]
e = [7, 8, 9, 10]


def func(a, b):
    return a * 100 + b


print(list(map(func, d, e)))

[107, 208, 309]
  • 可以使用lambda定义小函数,使程序更加简洁。
d = [1, 2, 3]
e = [7, 8, 9, 10]
print(list(map(lambda a, b: a * 100 + b, d, e)))
[107, 208, 309]

reduce

functools.reduce(function, iterable, [initial_value])

  • function -- 函数,有两个参数
  • iterable -- 可迭代对象
  • initial_value -- 可选,初始参数

E.g.1:

import functools  # python3


def add(x, y):
    print("x = %d, y = %d" % (x, y))
    return x + y


print(functools.reduce(add, [1, 2, 3, 4, 5]))
print(functools.reduce(add, [1, 2, 3, 4, 5], 8))
x = 1, y = 2
x = 3, y = 3
x = 6, y = 4
x = 10, y = 5
15
x = 8, y = 1
x = 9, y = 2
x = 11, y = 3
x = 14, y = 4
x = 18, y = 5
23
  • 可以使用lambda定义小函数,使程序更加简洁。

E.g.2:

import functools  # python3

print(functools.reduce(lambda x, y: x + y, [1, 2, 3, 4, 5], 8))
print(functools.reduce(lambda x, y: 10 * x + y, [1, 2, 3, 4, 5], 8))
23
812345

filter

filter(function, iterable)

  • 对iterable中的每一个元素都调用function进行判断,返回满足条件的元素列表。

E.g.1:

print(filter(lambda a: a % 2 == 0, range(20)))
print(list(filter(lambda a: a % 2 == 0, range(20))))
<filter object at 0x0000025BE94AD190>
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

collections模块

namedtuple

collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)

  • namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素。这样一来,我们用namedtuple可以很方便地规定一种数据类型,它具备tuple的不变性,又可以根据属性来引用,使用十分方便。

E.g.1:

import collections

Point = collections.namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
print(p.x)
print(p.y)

pp = Point(x=3, y=4)
print(pp.x)
print(pp.y)
1
2
3
4
  • namedtuple的属性不能更改,否则会报错。
  • 可以验证创建的Point对象是tuple的一种子类。

E.g.2:

import collections

Point = collections.namedtuple('Point', ['x', 'y'])
p = Point(1, 2)

print(isinstance(p, Point))
print(isinstance(p, tuple))
True
True
defaultdict
  • 使用dict时,如果引用的Key不存在,就会抛出KeyError,如果希望key不存在时,返回一个默认值,就可以用defaultdict。除了在Key不存在时返回默认值,defaultdict的其他行为跟dict是完全一样的。

E.g.1:

import collections

dd = collections.defaultdict(lambda: 'N/A')
dd['key1'] = 'abc'

print(dd['key1'])

print(dd['key2'])
abc
N/A
  • 统计词频

E.g.2:

import collections

cnt = collections.defaultdict(int)
for char in ["a", "b", "c", "b", "d", "a", "a"]:
  cnt[char] += 1
print(cnt)
defaultdict(<class 'int'>, {'a': 3, 'b': 2, 'c': 1, 'd': 1})
Counter
  • Counter是一个简单的计数器,例如,统计字符出现的个数

E.g.1:

import collections

c = collections.Counter('gallahad')
print(c)
Counter({'a': 3, 'l': 2, 'g': 1, 'h': 1, 'd': 1})

itertools模块

chain

itertools.chain(*iterables)

  • chain可以把一组迭代对象串联起来,形成一个更大的迭代器

E.g.1:

import itertools
for c in itertools.chain('ABC', 'XYZ'):
    print(c)
A
B
C
X
Y
Z
groupby

itertools.groupby(iterable, key=None)

  • groupby把迭代器中相邻的重复元素(key)挑出来放在一起

E.g.1:

import itertools
for key, group in itertools.groupby('AAABBBCCAAA'):
    print(key, list(group))
A ['A', 'A', 'A']
B ['B', 'B', 'B']
C ['C', 'C']
A ['A', 'A', 'A']

E.g.2:

import itertools
date = [
    ("1班", "刘一", 93),
    ("1班", "陈二", 72),
    ("1班", "张三", 81),
    ("2班", "李四", 98),
    ("2班", "王五", 91),
    ("3班", "赵六", 86),
    ("3班", "孙七", 48),
    ("3班", "周八", 89),
    ("3班", "吴九", 64),
    ("3班", "郑十", 79),
]

for key, group in itertools.groupby(date, key=lambda m: m[0]):
    print(key, list(group))
1班 [('1班', '刘一', 93), ('1班', '陈二', 72), ('1班', '张三', 81)]
2班 [('2班', '李四', 98), ('2班', '王五', 91)]
3班 [('3班', '赵六', 86), ('3班', '孙七', 48), ('3班', '周八', 89), ('3班', '吴九', 64), ('3班', '郑十', 79)]

时间模块

datetime
  • datetime是Python处理日期和时间的标准库。

E.g.1:

import datetime
now = datetime.datetime.now()
print(now)
print(type(now))
print(now.timestamp())  # 注意Python的timestamp是一个浮点数。如果有小数位,小数位表示毫秒数,
2020-08-18 19:40:09.972192
<class 'datetime.datetime'>
1597750809.972192
  • 很多时候,用户输入的日期和时间是字符串,要处理日期和时间,首先必须把str转换为datetime。转换方法是通过datetime.datetime.strptime实现,需要一个日期和时间的格式化字符串

E.g.2:

import datetime
cday = datetime.datetime.strptime('2019-6-20 18:19:59', '%Y-%m-%d %H:%M:%S')
print(cday)
2019-06-20 18:19:59
  • 如果已经有了datetime对象,要把它格式化为字符串显示给用户,就需要转换为str,转换方法是通过strftime实现的,同样需要一个日期和时间的格式化字符串

E.g.3:

import datetime

now = datetime.datetime.now()
print(now.strftime('%Y-%m-%d %H:%M:%S'))
2020-08-18 19:53:20
  • 对日期和时间进行加减实际上就是把datetime往后或往前计算。,得到新的datetime。加减可以直接用+和-运算符,需要使用timedelta这个类。
import datetime
now = datetime.datetime.now()
print(now)

print(now + datetime.timedelta(hours=10))
print(now - datetime.timedelta(days=1))
print(now + datetime.timedelta(days=2, hours=12))
2020-08-18 20:35:57.941536
2020-08-19 06:35:57.941536
2020-08-17 20:35:57.941536
2020-08-21 08:35:57.941536