如何写出更 Pythonic 的代码

290 阅读3分钟

如何写出更 Pythonic 的代码

1. PEP8 代码风格

注意对齐

def context(user,password
            timeout,command)
    pass

注意最后一个括号的位置

user_list = [
    'user1',
    'user2',
    'user3',
    'user4'
]

定义变量

x = 1
long_variable = 3

命名方式


import my_module # 可以使用下划线的方式,都是小写的
import mymodule  # 当然也可以使用完整词语,都是小写的

MAX_TOTAL = 100 # 常量使用全大写加下划线的格式

class MyClass(Object):
 """ this is a demo class
 """

 def __init__(self):
  pass

2. 在判断语句中使用 True 和 False

基本类型的判断

false_values = [
    False,
    0,
    0.0,
    None,
    '',
    [],
    {},
    ()
]

for value in false_values:
    """这两个输出的结果都是False"""
    print('{}是否为空{}'.format(value, bool(value)))
    print(True if value else False)  # 我们一般通过这种形式来判断是否为空
    print(True if bool(value) else False)  # 上面的其实就是这个意思

自定义对象如何返回 bool 值呢?

class MyType(object):

    def __init__(self):
        self.values = []

    def add(self, x):
        self.values.append(x)

    def __bool__(self):
        print('__bool__ 被调用了')
        return bool(self.values)  # 由上述的推论我们得知,当列表为空时返回的是False


m = MyType()
print(bool(m))  # False  当调用 bool 时其实调用的就是__bool__方法
m.add(1)
print(bool(m))  # True

if bool(m) == True:  # 现在MyType不为为空时返回True,我们可以按照自己的逻辑进行代码编写了,优化下格式就是 if m
    print('m is not empty')

if m:
    print('m is not empty')

3. if 条件判断较多时的优化

import random
import time
from enum import Enum


class Condition(Enum):
    A = 1
    B = 2
    C = 3
    D = 4


values = [1, 2, 3, 4]
condition = Condition(random.choice(values))

# 第一种写法

begin = time.time()
for index in range(1000000):
    if condition == Condition.A or condition == Condition.B or condition == Condition.C:
        pass
    else:
        pass
print('cost {}'.format(time.time() - begin))  # cost 0.42326903343200684

# 优化后
options = [Condition.A, Condition.B, Condition.C]
begin = time.time()
for index in range(1000000):
    if condition in options:
        pass
    else:
        pass
print('cost {}'.format(time.time() - begin))  # cost 0.1031181812286377

4. 使用列表解析

numbers = list(range(1, 101))
# 将所有偶数放到新列表中
numbers_new = []
for number in numbers:
    if number % 2 == 0:
        numbers_new.append(number)
print(numbers_new)

# 使用列表解析,还可以对其进行格式化 [str(item) + '-00' for item in numbers if item % 2 == 0]
numbers_new = [item for item in numbers if item % 2 == 0]
print(numbers_new)

5. 使用字典解析

numbers = list(range(1, 6))
dict = {}

# 普通循环
for number in numbers:
    dict[number] = str(number)
print(dict)  # {1: '1', 2: '2', 3: '3', 4: '4', 5: '5'}

# 字典解析 左边是key,右边是value,同样可以格式化
dict_new = {number: str(number) for number in numbers}
print(dict_new)  # {1: '1', 2: '2', 3: '3', 4: '4', 5: '5'}

6. 使用 yield 减少内存消耗

def my_range(total):
    value = 0
    while value < total:
        yield value  # 你可以把它理解为return,但是return只会返回一次,它会返回很多次,并且可以供你遍历
        value += 1


i = my_range(100)
print(i)  # 返回的就是一个生成器 <generator object my_range at 0x118cedd60>
print(dir(i))  # 可以发现里面有__iter__方法

# 注意只能使用一次
for item in i:
    print(item)  # 0
    break

for item in i:
    print(item)  # 1
    break

7. 小心默认参数的陷阱

def default_args(x, time, target=[]):
    for item in range(time):
        target.append(x)
    return target


target = default_args('a', 3)
print(target)  # ['a', 'a', 'a']

target = default_args('b', 3)
print(target)  # ['a', 'a', 'a', 'b', 'b', 'b']  可以看出如果没指定列表的话,它就会使用上次使用的,这是非常危险的

target = default_args('c', 3, target=[])
print(target)  # ['c', 'c', 'c']

target = default_args('d', 3, target=[])
print(target)  # ['d', 'd', 'd']


# 总不能每次都传递 target=[] 吧

def default_args_better(x, time, target=None):
    if not target:
        target = []
    for item in range(time):
        target.append(x)
    return target


target = default_args_better('a', 3)
print(target)  # ['a', 'a', 'a']

target = default_args_better('b', 3)
print(target)  # ['b', 'b', 'b']