Pythonic

本文介绍了将代码转换为美观、地道Python代码的多种技巧,包括列表和字典解析式的使用、元素命名、统计元素频率、字典操作、函数式编程、迭代器操作、字符串拆分以及装饰器缓存数据等内容,能有效提高代码的可读性和可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

过滤掉列表List中的负数—列表解析式

import random

List = random.sample(range(-100, 100), 10)
new_List = [x for x in List if x >= 0]

筛选出Dict中值不为空的项—字典解析式

Dict = {'a': 79, 'b': None, 'c': 12,}

new_Dict = {k:v for k, v in Dict.items() if v }

给元祖中的每个元素命名,提高程序的可读性

from collections import namedtuple

Student = namedtuple('Student', ['name', 'age', 'sex', 'email'])
one_student = Student('Rick', '18', 'male', 'loveweihaitong@foxmail.com')
# one_student.name --> Rick

给可迭代对象中的每个元素命名(解构赋值)

student = ['Tom', 18, 'male']
name, age, gender = student
print(name, age, gender)
# Tom 18 male

num_list = [100, 19, 20, 98]
first, *left_num_list, last = num_list
print(first, left_num_list, last)
# 100 [19, 20] 98

student = [['Tom', (98, 96, 100)], ['Jack', (98, 96, 100)]]

for name, (first, second, third) in student:
    print(name, first, second, third)
# Tom 98 96 100
# Jack 98 96 100

统计随机序列中出现频率最高的三个元素,并统计它们出现的次数

from collections import Counter
from random import randint

random_sequence = [randint(0, 5) for _ in range(10)]
# [1, 5, 2, 4, 3, 0, 5, 5, 1, 0]
result = Counter(random_sequence)
# Counter({5: 3, 1: 2, 0: 2, 2: 1, 4: 1, 3: 1})
new_result = result.most_common(3)
# [(5, 3), (1, 2), (0, 2)]

反向遍历集合

colors = ['red', 'green', 'blue', 'yellow']

for i in range(len(colors)-1, -1, -1):
    print(colors[i])

# better
for color in reversed(colors):
	print(color)

快速找到字典中的公共键

from random import randint
from functools import reduce

# d1 -> {'库里': 29, '汤普森': 14, '杜兰特': 25, '格林': 11, '帕楚里亚': 22, '欧文': 17, '詹姆斯': 28}
d1 = {x: randint(10, 30) for x in ['库里', '汤普森', '杜兰特', '格林', '帕楚里亚', '欧文', '詹姆斯']}
d2 = {x: randint(10, 30) for x in ['汤普森', '杜兰特', '格林', '麦基', '香波特', '詹姆斯', '库里', '韦德']}
d3 = {x: randint(10, 30) for x in ['格林', '杜兰特', '利文斯顿', '库里', '香波特', '詹姆斯', '汤普森', '韦德']}



# 如果你想映射一个序列到另一个序列,直接调用map函数。
# map(f(x),Itera) 第一个参数为某个函数,第二个为可迭代对象。
Set = map(dict.keys, [d1, d2, d3])

# 使用reduce函数,取所有函数的keys集合的交集, 并集用|,差集用-
reduce(lambda a, b: a & b, Set)
# {'库里', '汤普森', '杜兰特', '格林', '詹姆斯'}

合并字典

query = {'id': 1, 'render_fast': True}
post = {'email': 'j@j.com', 'name': 'Joff'}
route = {'id': 271, 'title': 'Fast_apps'}

# 这里面如果有相同的键,后面键的值会覆盖前面的值,例如本例中的id。
merge_dic = {**query, **post, **route}
# {'id': 271, 'render_fast': True, 'email': 'j@j.com', 'name': 'Joff', 'title': 'Fast_apps'}

使用defaultdict实现树结构

defaultdict 允许我们通过工厂方法来动态创建不存在的属性

from collections import defaultdict

my_dict = defaultdict(lambda: 'Default Value')
my_dict['a'] = 42

print(my_dict['a'])
print(my_dict['b'])

# 42 Default Value

用defaultdict来构造一颗树形数据结构

from collections import defaultdict
import json

def tree():
    """
    Factory that creates a defaultdict that also uses this factory
    """
    return defaultdict(tree)

root = tree()
root['Page']['Python']['defaultdict']['Title'] = 'Using defaultdict'
root['Page']['Python']['defaultdict']['Subtitle'] = 'Create a tree'
root['Page']['Java'] = None

print(json.dumps(root, indent=4))

"""
{
    "Page": {
        "Python": {
            "defaultdict": {
                "Subtitle": "Create a tree",
                "Title": "Using defaultdict"
            }
        },
        "Java": null
    }
}
"""

Switch/Case 实现

函数式编程,很好的解耦每个case中的业务逻辑。提高复用性和可维护性

# pythonic: 巧用字典的数据结构的代码代替通常switch语句,完成case的功能。

def get_sunday():
    return 'sunday'


def get_monday():
    return 'monday'


def get_tuesday():
    return 'tuesday'


def get_default():
    return 'unknown'


def switcher(arg):
    switch = {
        0: get_sunday,
        1: get_monday,
        2: get_tuesday,
    }
    return switch.get(arg, get_default)()


day = 9
day_name = switcher(day)
print(day_name)

使用iter()连续调用函数

blocks = []
while True:
    block = f.read(32)
    if block == '':
        break
    blocks.append(block)

# better
blocks = []
for block in iter(partial(f.read, 32), ''):
    blocks.append(block)

iter 接受两个参数时. 第一个参数是一个可调用对象(函数), 第二个参数是边界值, 当可调用对象返回这个值时, 就会抛出StopIteration

使用字典进行计数

colors = ['red', 'green', 'red', 'blue', 'green', 'red']

d = {}
for color in colors:
    if color not in d:
        d[color] = 0
    d[color] += 1

# better
d = {}
for color in colors:
    d[color] = d.get(color, 0) + 1


d = defaultdict(int)
for color in colors:
d[color] += 1

使用ignored() 代替 pass exception

try:
    os.remove('somefile.tmp')
except OSError:
    pass

# better
with ignored(OSError):
    os.remove('somefile.tmp')

使用上下文管理器减少临时变量

# Temporarily redirect standard out to a file and then return it to normal
with open('help.txt', 'w') as f:
    oldstdout = sys.stdout
    sys.stdout = f
    try:
        help(pow)
    finally:
        sys.stdout = oldstdout

# better
with open('help.txt', 'w') as f:
    with redirect_stdout(f):
        help(pow)

@contextmanager
def redirect_stdout(fileobj):
    oldstdout = sys.stdout
    sys.stdout = fileobj
    try:
        yield fieldobj
    finally:
        sys.stdout = oldstdout

生成器函数实现可迭代对象

class PrimeNumbers(object):
    def __init__(self, *, start, end):
        self.start = start
        self.end = end

    def isPrimeNum(self, k):
        if k < 2:
            return False
        for i in range(2, k):
            if k % i == 0:
                return False
        return True

    def __iter__(self):
        for k in range(self.start, self.end + 1):
            if self.isPrimeNum(k):
                yield k


pn = PrimeNumbers(start=1, end=30)
print(list(pn))
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

反向迭代

class FloatRange(object):
    def __init__(self, start, end, step=0.1):
        self.start = start
        self.end = end
        self.step = step

    # 正向迭代器
    def __iter__(self):
        t = self.start
        while t <= self.end:
            yield t
            t += self.step

    # 反向迭代器
    def __reversed__(self):
        t = self.end
        while t >= self.start:
            yield t
            t -= self.step


floatRange = FloatRange(1.0, 4.0, 0.5)
# 正向迭代器实例
print(list(floatRange))
# [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0]
# 反向迭代器实例
print(list(reversed(floatRange)))
# [4.0, 3.5, 3.0, 2.5, 2.0, 1.5, 1.0]

使用itertools里的islice()对迭代器做切片操作

"""对迭代器做切片操作"""
from itertools import islice

print(list(islice(floatRange, 2, 6)))
# [2.0, 2.5, 3.0, 3.5]

在一个for语句中迭代多个可迭代对象


from random import randint
from itertools import chain

chinese = [randint(60, 100) for _ in range(10)]
math = [randint(60, 100) for _ in range(10)]
english = [randint(60, 100) for _ in range(10)]
# chinese -> [98, 65, 99, 94, 97, 74, 95, 64, 90, 87]
# math -> [88, 98, 63, 73, 80, 73, 65, 79, 74, 64]
# english -> [95, 87, 61, 65, 62, 94, 91, 88, 72, 78]

# 并行
total = []
# zip()函数可将多个迭代对象合并,每次迭代返回一个元祖
for c, m, e in zip(chinese, math, english):
    total.append(c + m + e)

# total -> [281, 250, 223, 232, 239, 241, 251, 231, 236, 229]

# 串行
total = []
# itertools中chain()可以进行多个迭代对象的连接
print(list(chain(chinese, math, english)))
# [98, 65, 99, 94, 97, 74, 95, 64, 90, 87, 88, 98, 63, 73, 80, 73, 65, 79, 74, 64, 95, 87, 61, 65, 62, 94, 91, 88, 72, 78]

使用 itertools.combinations 求列表或生成器中指定数目的元素不重复的所有组合

x = itertools.combinations(range(4), 3)
print(list(x))
[(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]

使用itertools.combinations_with_replacement 求允许重复元素的组合

x = itertools.combinations_with_replacement(range(4), 3)
print(list(x))
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 2, 2), (0, 2, 3), (0, 3, 3), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 2), (1, 2, 3), (1, 3, 3), (2, 2, 2), (2, 2, 3), (2, 3, 3), (3, 3, 3)]

使用itertools.compress 按照真值表筛选元素

x = itertools.compress(range(5), (True, False, True, True, False))
print(list(x))
[0, 2, 3]

使用 itertools.cycle 循环指定的列表和迭代器

x = itertools.cycle('ABC')
print(list(itertools.islice(x, 0, 10, 1)))
['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C', 'A']

使用 itertools.dropwhile 按照真值函数丢弃掉列表和迭代器前面的元素

x = itertools.dropwhile(lambda e: e < 5, range(10))
print(list(x))
[5, 6, 7, 8, 9]

使用 itertools.filterfalse 保留对应真值为False的元素

x = itertools.filterfalse(lambda e: e < 5, (1, 5, 3, 6, 9, 4))
print(list(x))
[5, 6, 9]

使用 itertools.groupby 按照分组函数的值对元素进行分组

x = itertools.groupby(range(10), lambda x: x < 5 or x > 8)
for condition, numbers in x:
    print(condition, list(numbers))                                                                                             
True [0, 1, 2, 3,4]                                                              
False [5, 6, 7,8]                                                           
True [9]

拆分含有多种分隔符的字符串

import re

s = 'ab;gdgfdg|iuiu,sddsd|iweoiru\t8998;rst,qwq\tererer'
# 正则来对字符串进行选择
res = re.split('[,;\t|]+', s)
# ['ab', 'gdgfdg', 'iuiu', 'sddsd', 'iweoiru', '8998', 'rst', 'qwq', 'ererer']

使用装饰器来缓存数据

"""
题目一: 斐波那契数列(Fibonacci Sequence),又称黄金分割数列,
        指的是这样一个数列:1,1,2,3,5,8,13,21,.....
        这个数列从第三项开始,每一项都等于前两项之和。求数列第N项
"""

def memo(func):
    cache = {}

    def wrap(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]

    return wrap

@memo
def fibonacci(n):
    if n <= 1:
        return 1
    return fibonacci(n - 1) + fibonacci(n - 2)

import sys
sys.setrecursionlimit(1000000)

print(fibonacci(50))
# 20365011074

"""
题目二: 一个共有10个台阶的楼梯,从下面走到上面,一次只能迈1-3个台阶,
        并且不能后退,走完这个楼梯共有多少种方法。
"""

@memo
def climb(n, steps):
    count = 0
    if n == 0:
        count = 1
    elif n > 0:
        for step in steps:
            count += climb(n - step, steps)
    return count


print(climb(10, (1, 2, 3)))
# 274

属性可以修改的函数装饰器

from functools import wraps
import time
from random import randint

import logging


def warn(timeout):
    timeout = [timeout]

    def decorator(func):
        def wrapper(*args, **kwargs):
            start = time.time()
            res = func(*args, **kwargs)
            used = time.time() - start
            if used > timeout[0]:
                msg = '%s : %s > %s' % (func.__name__, used, timeout[0])
                logging.warn(msg)
            return res

        def setTimeout(k):
            nonlocal timeout  # python 3
            # timeout = k
            timeout[0] = k

        wrapper.setTimeout = setTimeout
        return wrapper

    return decorator

@warn(1.5)
def rand():
    print('In test')
    while randint(0, 1):
        time.sleep(0.5)

for _ in range(30):
rand()
# In test
# In test
# WARNING:root:rand : 1.5010855197906494 > 1.5
# In test
# In test
# .........
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值