python一些Tips(一)

有一些小的知识点,或者在某一个模块里很好用的,但是过一段时间总是忘记,然后回头看,还是写个东西记录一下,以后回顾的时候也算是有个基准

可迭代对象与迭代器

在理解可迭代对象之前首先要理解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中的元素都是单独的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值