• 代码重构之路 --- 一些编程规范和 python idiom make your code more pythonic


    蓝色的 mandelbrot

    1. 重构代码(《重构》的python实现):

    常量和临时变量

    • 提取常量
    • 加入解释性变量
    • 分解临时变量(单一原则)
    • 去除临时变量
    • 移除控制标记(直接return 或 break)

    函数

    • 拆分
    • 去除(去除简单的)
    • 合并多个函数,使用参数
    • 函数不应有副作用,单一职责原则,一个函数不应做两件事,函数粒度尽量小

    表达式

    • 过多的条件逻辑, 难以理解正常的执行路径. 在python中的特征是, 缩进太深(尽早return 改为平行的 if)
    • 合并条件表达式(对于返回结果相同的条件)
    • 分解复杂条件表达式(分别从if,else中提炼出独立函数)
    • 合并重复的代码片段(if 和 else都有的代码,放到外面去)

    参数及返回值

    • 提取对象(如果参数/返回值是一组相关的数值, 且总是一起出现, 可以考虑提取成一个对象)
    • 减少参数(中间不需要的步骤)
    def get_width_height():
        ....
    
        return width, height
    
    def get_area(width, height):
        return width, height
    # to
    class Rectangle(object):
        def __init__(self, width, height):
            self.width = width
            self.height = height
    
        def area(self):
            return self.width * self.height
    
    def get_shape():
        ....
        return Rectangle(height, width)
    

    • 搬移,函数/字段
    • 拆分类
    • 去除类 (类做的事不多,不再独立存在)

    模式

    • 慎用,只用熟悉的,只用符合业务场景的
    • 装饰器

    参考:http://www.wklken.me/posts/2017/06/17/refactoring-07.html#yuan-ze

    2. pycharm重构快捷键

    序号 快捷键 功能
    1 F5 复制文件
    2 F6 移动文件
    3 SHIFT F6 重命名
    4 ALT delete 安全删除
    5 CTRL F6 改变函数形参
    6 CTRL ALT M 将代码提取为函数
    7 CTRL ALT V 将代码提取为变量
    8 CTRL ALT C 将代码提取为常数
    9 CTRL ALT F 将代码提取为字段
    10 CTRL ALT P 将代码提取为参数

    3. python idiom, pythonic

    每当你在代码库中看到以下的模式可以参照以下的建议进行重构,让代码变得更加的pythonic,可读性更好,更容易维护。
    参考:Python重构代码的一些模式 http://mpwang.github.io/2017/08/26/python-refactor-patterns/

    enumerate

    需要使用列表的下标时,不要使用C风格的下标遍历

    lst = ['a', 'b', 'c']
    # DON'T
    i = 0
    for i in lst:
        print i, '-->', lst[i]
        i += 1
    # OR
    for i in range(len(lst)):
        print(i, '-->', lst[i])
    # DO
    for idx, item in enumerate(lst):
        print(idx, '-->', item)
    
    

    zip/izip

    同时遍历两个列表时,不要使用C风格的下标遍历

    lst1 = ['a', 'b', 'c']
    lst2 = [1, 2, 3]
    # DON'T
    for i in range(len(lst1)):
        print(lst1[i])
        print(lst2[i])
    # DO
    for lst1_item, lst2_item in zip(lst1, lst2):
        print(lst1_item)
        print(lst2_item)
    # BETTER
    # 不需要在内存中生成包含lst, lst2的第三个列表
    from itertools import izip
    for lst1_item, lst2_item in izip(lst1, lst2):
        print(lst1_item)
        print(lst2_item)
    
    

    unpacking tuple

    x, y = y, x
    foo, bar, _ = words # 使用 _ 如果你不需要这个值
    

    Dict.setdefault/defaultdict

    处理字典中key不存在时的默认值

    # group words by frequency
    words = [(1, 'apple'), (2, 'banana'), (1, 'cat')]
    frequency = {}
    # DON'T
    for freq, word in words:
        if freq not in frequency:
            frequency[freq] = []
        frequency[freq].append(word)
    # DO
    for freq, word in words:
        frequency.setdefault(freq, []).append(word)
    # BETTER
    from collections import defaultdict
    frequency = defaultdict(list)
    for freq, word in words:
        frequency[freq].append(word)
    # 在工作中要经常处理字典为空或键值不存在的情形,用get和setdefault代替dict_name['key']
    

    setdefault vs get
    setdefault()的使用,类似get方法,如果字典中包含有给定键,则返回该键对应的值,否则返回为该键设置的值
    不同点:1.setdefault会把不存在的item保存到原来的dict,2.setdefault比get快10percent

    person_dict = {}
    person_dict['liqi'] = 'LiQi'
    person_dict.setdefault('liqi', 'Liqi')  # 'LiQi'
    person_dict.setdefault('Kim', 'kim')  # 'kim'
    person_dict
    person_dict.get('Dim', 'D')  # 'D'
    person_dict  # {'liqi': 'LiQi', 'Kim': 'kim'}
    
    

    Dict.iteritems

    遍历字典

    words = {'apple': 1, 'banana': 2, 'cat': 3}
    # OK
    for word in words:
        print word, '-->', words[word] # 需要计算word的hash值
    # GOOD
    for word, freq in words.items():
        print word, '-->', freq
    # BETTER
    # 不需要在内存中生存包含words所有元素的中间结果
    for word, freq in words.iteritems():
        print word, '-->', freq
    
    

    for...else

    break and nobreak

    # DO
    for word in words:
        if condition(word):
            # 处理存在符合condition的元素的情况
            print 'Found'
            break
    else:
        # 处理没有符合condition元素的情况
        print 'Not found'
    

    try...except...else

    分开异常处理与正常情况

    # GOOD
    try:
        result = json.loads(get_external_json())
        do_something_with(result)
    except Exception as e:
        handle_error(e)
    # BETTER
    try:
        # 异常可能抛出点
        result = json.loads(get_external_json())
    except Exception as e:
        # 异常处理
        handle_error(e)
    else:
        # 正常情况
        do_something_with(result)
    
    

    https://medium.com/the-andela-way/idiomatic-python-coding-the-smart-way-cc560fa5f1d6

    1. chained comparison operators

    # bad
    if x <= y and y <= z:
      # do something
    # good
    if x <= y <= z:
      # do something
    

    2. indentation(if else )

    3. use the falsy & truthy concepts

    For example an empty list/sequences [], empty dictionaries {} None, False, Zero for numeric types, are considered “falsy”. On the other hand, almost everything else is considered “truthy”.

    # bad
    x = True
    y = 0
    if x == True:
      # do something
    elif x == False:
      # do something else
    if y == 0:
      # do something
    ls = [2, 5]
    if len(ls) > 0:
      # do something
    # good
    (x, y) = (True, 0)
    # x is truthy
    if x:
      # do something
    else:
      # do something else
    # y is falsy
    if not y:
      # do something
    ls = [2, 5]
    if ls:
      # do something
    

    4. ternary operator replacement

    # bad
    a = True
    value = 0
    if a:
      value = 1
    print(value)
    # good
    a = True
    value = 1 if a else 0
    print(value)
    
    

    5. use the 'in' keyword

    # bad
    city = 'Nairobi'
    found = False
    if city == 'Nairobi' or city == 'Kampala' or city == 'Lagos':
      found = True
    # good
    city = 'Nairobi'
    found = city in {'Nairobi', 'Kampala', 'Lagos'}
    

    6. Use ‘return’ to evaluate expressions, in addition to return values

    # bad
    def check_equal(x, y):
      result = False
    
      if x == Y:
        result = True
      return result
    # good
    def check_equal(x, y):
      return x == y
    

    7. multiple assignment

    # good
    x = y = z = 'foo'
    

    8. formatting strings

    def user_info(user):
      return 'Name: {user.name} Age: {user.age}'.format(user=user)
    
    

    9. list comprehension(set, dict)

    ls = [element for element in range(10) if not(element % 2)]
    emails = {user.name: user.email for user in users if user.email}
    

    10. sets

    ls1 = [1, 2, 3, 4, 5]
    ls2 = [4, 5, 6, 7, 8]
    elements_in_both = list( set(ls1) & set(ls2) )
    print(elements_in_both)
    
    

    11. dont't repeat yourself(dry)

    # bad
    if user:
      print('------------------------------')
      print(user)
      print('------------------------------')
    # good
    if user:
      print('{0}
    {1}
    {0}'.format('-'*30, user))
    
    
  • 相关阅读:
    连分数法解佩尔方程特解
    hdu2281&&POJ1320——Pell方程
    Gym
    代入法求递推式
    nodemcu固件的烧录及lua开发
    ESP8266MOD、刷可以使用AT指令的固件、作为客户端向贝壳云端发送固定数据
    Quick Start NodeMCU / ESP8266 12E
    CF388C&&2018EC Final D题——博弈&&水题
    使用cookie登录网盘账号
    Spring的Bean之Bean的基本概念
  • 原文地址:https://www.cnblogs.com/bruspawn/p/9236379.html
Copyright © 2020-2023  润新知