有一些小的知识点,或者在某一个模块里很好用的,但是过一段时间总是忘记,然后回头看,还是写个东西记录一下,以后回顾的时候也算是有个基准
可迭代对象与迭代器
在理解可迭代对象之前首先要理解python的数据结构中的容器:list,tuple,dict,str,还有collections中的deque,defaultdict,Counter 这些都是数据组织的容器。
可迭代的对象,凡是实现了__iter__方法,迭代器是实现了__iter__与__next__两个方法,其实我也不知道这
生成器
它的创立是为了解决处理大的数据集,能够通过某种规律或者算法不断的推算出来的元素,这样就不必创建完整的数据从而节省大量的空间,这种一边循环一遍计算的机制就是生成器
举个例子我需要一个斐波那契数列,那么用常规办法的话就是创建一个list,不断的往里面放,那么入股我只需要用到最后几个,那么前面的计算结果就是浪费,下面做一个对比
def normal_prime(num):
prime_list = []
a, b, n = 0, 1, 0
while n < num:
a = a + b
b = a
prime_list.append(b)
n += 1
return prime_list
list_alpha = normal_prime(200000)
print(sys.getsizeof(list_alpha) / 1024 / 1024, 'MB')
1.5943450927734375 MB
使用生成器
def prime_func(num):
"""
0 1 1 2 3 5
:param num:
:return:
"""
a = 0
b = 1
n = 0
while n < num:
a = a + b
b = a
yield b
n += 1
list_beta = prime_func(200000)
print(sys.getsizeof(list_beta) / 1024 / 1024, 'MB')
0.00011444091796875 MB
可以看出这两个差别是巨大的,如果碰到更大的数据集那么内存的占用是巨大的,所以需要转换一个思路。生成器存的是一个函数,一个可以推导式。如果有需求就拿出来进行处理
Collections
- 1、defaultdict
讲实话我实在是没有get到这个好用在哪里,除非装个逼啥的,论实用我还是觉得dict.get(key,defauult_value)这个
def func_defaultdict():
dict_alpha = defaultdict(lambda: 0)
# dict_alpha = defaultdict(int,str)
dict_alpha_lambda = defaultdict(lambda: 1)
dict_alpha_int = defaultdict(int)
dict_alpha_str = defaultdict(str)
dict_alpha_list = defaultdict(list)
dict_alpha_tuple = defaultdict(tuple)
key_list = [_ for _ in ascii_lowercase] * 3
for ele in key_list:
dict_alpha[ele] += 1
# 不过也有一个好玩的事情,就是defaultdict()参数是一个容器的时候,是可以直接调用容器的方法。
# 看看能不能做点什么。
random_string = random.choices(ascii_lowercase, k=40)
str_dict = defaultdict(list)
for ele in random_string:
str_dict[ele].append(ele)
# note 常规办法
dict_beta = {}
for ele in key_list:
if ele not in dict_beta.keys():
dict_beta[ele] = 0
dict_beta[ele] += 1
# get方法
dict_gamma = {}
for ele in key_list:
dict_gamma[ele] = dict_gamma.get(ele, 0) + 1
- 2、Counter
这个我觉得还是偶尔有点用的,做一些简单的统计来说不用重新写方法,可以直接用
import random
from collections import Counter
list_alpha = [random.choice(ascii_lowercase) for _ in range(100)]
countered_list = Counter(list_alpha)
countered_list.most_common(3)
- 3、ChainMap
两个或者多个字典进行合并可以使用,但是我觉得实用性不是特别的大,我专门写了一个测试,两个速度也没啥区别,甚至还更慢一些,就当装个逼吧。
def time_spend(func):
def wrapper(*args, **kwargs):
print(args)
print(kwargs)
time_start = time.time()
func(*args, **kwargs)
time_end = time.time()
print(f" time spend:{time_end - time_start}")
return wrapper
@time_spend
def func_alpha(repeat_time):
dict_alpha = dict(zip(ascii_lowercase, [_ for _ in range(50)]))
dict_beta = dict(zip(ascii_lowercase, [_ for _ in range(0, 50)]))
for _ in range(repeat_time):
# dict_gammas = ChainMap(dict_alpha, dict_beta)
dict_gammas = dict_alpha.update(dict_beta)
functools
其实这里面我就觉得一个partial还算是有点用,其他的对于业务来说没啥效果,其实就是类似于在函数的外部加了一个装饰器,可以调整函数的某几个参数,而不需要创建类似的函数,这个有点像Java里的方法重载。
def func_alpha(a, b, c, d):
print(a, b, c, d)
return a + b + c + d
def test():
f_d = partial(func_alpha, 1, 1, 1)
result = f_d(100)
itertools
- accumulate()
计算累计,比如对一个list进行计算
list_alpha = [_ for _ in range(1, 10)]
result_alpha = itertools.accumulate(list_alpha)
result_alpha = itertools.accumulate(list_alpha, lambda x, y: x * y)
# [1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
# [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
- cycle()
我倒觉得这个还挺好用的,好像有一次需要不断循环一个dataframe某一列,然后某一列循环在某一个值的list。创建测试数据时候应该很有用。
list_beta = ["x", "y", "z"]
temp_val = itertools.cycle(list_beta)
result_list = []
result_list = []
for i in range(200):
result_list.append(next(temp_val))
- count(start,step)
就是创建一个count对象,然后每次遍历的时候得到end
def func_beta():
count_alpha = itertools.count(1, 0.5)
for _ in range(5):
print(next(count_alpha))
- repeat
返回一个Iterator,然后就是进行遍历,其实这个基本没有啥必要,直接[val]*n就好了。
def func_alpha():
alpha = itertools.repeat(4, 10)
val = next(alpha)
# list_alpha = list(alpha)
try:
for i in range(100):
print(f"start:{i}")
print(next(alpha))
except StopIteration:
print("end")
- 排列组合
提供了四种工具函数,分别是
笛卡尔积product(p,q,…[repet=1])是序列p、q、…序列的元素进行排列(元素肯定是会重复),其实就是多个循环嵌套
permutations(p,[,r])排列,从P中抽取r个元素进行排列,
combinations(p,[,r])组合,从P中抽取r个元素进行组合,
combination_with_replacement(p,[,r])从P中抽取可重复的r个元素。
def func_beta():
beta = [_ for _ in "abcd"]
all_pos = itertools.permutations(beta)
# 有重复元素的排列
result = itertools.product(beta, repeat=3)
list(result)
# 排列
list(all_pos)
# 组合
some = list(itertools.combinations(beta, 3))
# 组合 有重复元素
result = list(itertools.combinations_with_replacement(beta, 3))
- groupby
这里好像是对连续的进行分割,即:如果两个元素是连续相等的,那么就是一个group,如果不连续那么就不在一个group,仔细对比相面两个,不知道有什么用途,但是感觉很好玩。
result_alpha = itertools.groupby("aabbccdddd")
result_beta = itertools.groupby("aabccbdddd")
result_gamma=itertools.groupby("aabbccaa",lambda x:x=="a")
for k, v in result_[alpha,beta,gamma]:
print(k, list(v))
- zip_longest()
平时用的最多的创建测试字典的办法就是zip-shortest。。。,这里是按照最长的那个来,
key_list = [_ for _ in string.ascii_lowercase]
val_list = [_ for _ in string.digits]
dict_alpha = dict(itertools.zip_longest(key_list, val_list, fillvalue=None))
dict_beta = dict(zip(key_list, val_list))
- compress()
针对两个list,可以根据一个列的bool值来进行筛选。
list_alpha = [_ for _ in range(10)]
list_beta = [random.choice([0, 1]) for _ in range(80)]
# list_beta 是作为一个筛选器,这个可以是小于或者大于iterable的范围。
result = list(itertools.compress(list_alpha, list_beta))
混淆的地方
test_1 = [['_'] * 3] * 3
test_2 = [['_'] * 3 for _ in range(3)]
test_1[1][1] = "x"
test_2[1][1] = 'x'
第一个其实是下面的缩写
row_1 = ['_'] * 3
board_1 = []
for i in range(3):
board_1.append(row_1)
board_2 = []
第二个是下面的缩写
for i in range(3):
row = ['_'] * 3
board_2.append(row)
board_1[1][1] = "x"
board_2[1][1] = "x"
这两个最大的区别就是第一个是不断地往list中添加一个已经创建好的list,其元素的内存地址都是一个;第二个是不断的创建新的子list,所以list中的元素都是单独的。