论Python代码风格与编程习惯的重要性

1,062 阅读6分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。


引言

实现高内聚,低耦合、结构清晰不臃肿、可读性高、数据冗余性低、高复用、易扩展的代码,并非易事。上到设计模式,下到某个类、方法、函数的构造。在这里我分享一下我自己的代码设计、编写风格,让我们互相学习。


Python代码风格

首先我们要以 PEP8 代码规范为标准,但也无需完全遵守。例如:一行不能超过 79 个字符等。


Python模块模板

  • 模块开头指定编码格式
  • 模块文档注释,展示模块的信息,信息内容自己决定,如:
    • Author,作者
    • Desc,模块描述
    • Date,创建时间
  • 有一个 main() 函数
  • 有一个程序主入口 if __name__ == '__main__':
#!/usr/bin/python3
# -*- coding:utf-8 -*-
# @Author: Hui
# @Desc: { 项目主入口模块 }
# @Date: 2020/05/21 13:04


def main():
    print('Hello Python')


if __name__ == '__main__':
    main()

main() 函数方便用于测试当前模块功能。


import 导入

import 导入,避免使用 from ... import * ,因为这可能导致模块、类、变量名重复而导致错误。

我自己的 import 代码风格有两种。


由短到长

根据代码的长度由短到长依次导入,import 过度到 from ... import ... ,换行分割可有可无,我是根据 from ... import ... 前面的 import 的数量和整体美观来决定要不要换行。

import os
import sys
import time
import random
import config
import pygame
import requests
import numpy as np

from PIL import Image
from threading import Thread
from datetime import datetime

分类导入

分类导入,是分好类后在根据代码的长度由短到长依次导入,主要有:

  • Python内置模块
  • Python自建模块
  • Python第三方库
# Python内置模块导入
import os
import sys
import time
import random
from threading import Thread
from datetime import datetime

# Python自建模块、第三方库导入
import config
import pygame
import requests
import numpy as np
from PIL import Image

导入顺序依次为

Python内置模块  -->  Python自建模块  -->  Python第三方库

根据自己的风格,导入的自建模块、Python第三方库少时可以在一起无需换行

导入的自建模块少时可以跟Python内置模块在一起,就是转换成 由短到长 的风格


建议

导入模块代码风格无需照搬照抄地遵循,我们做任何的优化就是为了让代码更好看,结构清晰,无需刻意遵循死规则、烂规则,应该活学活用,创新变化,学习别人优秀的方案,总结出适合自己的。

例如:

假如import 导入语句比 from 导入语句更长,要遵循或者纠结 import 是要在 from 导入语句前面还是由短到长排放呢?

import numpy as np
import multiprocessing

from PIL import Image

import numpy as np
from PIL import Image
import multiprocessing

无需太过纠结、抠字眼,两种导入风格都可以。


变量的命名规范

命名规范 可以被视为一种 惯例,并无绝对与强制 目的是为了 增加代码的识别和可读性


下划线命名法

  1. 在定义变量时,为了保证代码格式,= 的左右应该各保留一个空格
  2. Python 中,如果 变量名 需要由 二个多个单词 组成时,可以按照以下方式命名
    • 每个单词都使用小写字母
    • 单词与单词之间使用 _下划线 连接
    • 例如:first_namelast_nameqq_numberqq_password

驼峰命名法

  • 变量名 是由二个或多个单词组成时,还可以利用驼峰命名法来命名
  • 小驼峰式命名法
    • 第一个单词以小写字母开始,后续单词的首字母大写
    • 例如:firstNamelastName
  • 大驼峰式命名法
    • 每一个单词的首字母都采用大写字母
    • 例如:FirstNameLastNameCamelCase

驼峰命名法

Java、C 等其他语言一般用 驼峰命名法,在 Python 中则推荐使用下划线命名法,符合 PEP8 规范。


Django 代码范例

模块导入

import re
import json
import logging

from django import http
from django.views import View
from django.conf import settings
from django.db import DatabaseError
from django.contrib.auth import authenticate
from django.contrib.auth import login, logout
from django_redis import get_redis_connection
from django.shortcuts import render, reverse, redirect

from goods.models import SKU
from users import constants
from users.models import User
from users.models import Address
from users.utils import generate_verify_email_url
from users.utils import check_verify_email_token
from carts.utils import merge_cart_cookie_to_redis

from meiduo_mall.utils.result import R
from meiduo_mall.utils.constants import RedisKey
from meiduo_mall.utils.constants import CookieKey
from meiduo_mall.utils.enums import StatusCodeEnum
from meiduo_mall.utils.constants import HtmlTemplate
from meiduo_mall.utils.views import LoginRequiredMixin
from meiduo_mall.utils.views import LoginRequiredJSONMixin
from meiduo_mall.utils.exceptions import BusinessException
from celery_tasks.email.tasks import celery_send_verify_email

这样导入看起来更舒服,有换行代码不紧凑,分类有条理。


封装html的url网址

渲染 html 页面,把 html 的存放路径总体封装到一个类里面,方便日后维护。

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Hui
# @Desc: { 项目公共常量模块 }
# @Date: 2021/09/25 15:57

class HtmlTemplate(object):
    """
    项目 html网页模板路径汇总类
    """

    # 首页
    INDEX_HTML = 'index.html'

    """
    用户登录模块
    """
    # 用户登录
    LOGIN_HTML = 'users/login.html'

    # 用户注册
    REGISTER_HTML = 'users/register.html'

    # 用户中心个人信息
    USER_CENTER_INFO_HTML = 'users/user_center_info.html'

    
    """
    商品模块
    """
    # 商品列表
    GOODS_LIST_HTML = 'goods/list.html'

    # 商品详情
    GOODS_DETAIL_HTML = 'goods/detail.html'

    
    """
    购物车模块
    """
    # 购物车列表
    CART_LIST_HTML = 'carts/cart.html'
    

    """
    项目错误 html 模板
    """
    ERRORS_404_HTML = 'errors/404.html'



视图访问与渲染

from meiduo_mall.utils.constants import HtmlTemplate

# /
class IndexView(View):
    """首页类视图"""

    def get(self, request):
        context = {
            'name': 'hui'
        }
        return render(request, HtmlTemplate.INDEX_HTML, context)
    

# /login    
class LoginView(View):
    """用户登录类视图"""

    def get(self, request):
        """
        提供登录界面
        :param request: 请求对象
        :return: 登录界面
        """
        return render(request, HtmlTemplate.LOGIN_HTML)
    
    
# /register
class RegisterView(View):
    """用户注册类视图"""

    def get(self, request):
        """提供注册页面"""
        return render(request, HtmlTemplate.REGISTER_HTML)
    

设计与封装 Cookie 和 Redis 的键(key)

class CookieKey(object):
    """
    Cookie key 常量设计类
    """

    # 登录用户名 cookie key
    USERNAME_KEY = 'username'

    # 购物车信息 cookie key
    CARTS_KEY = 'carts'


class RedisKey(object):
    """
    redis key 常量设计类
    """
    # 图形验证码 key
    IMG_CODE_KEY = 'meiduo:img:code:{uuid}'

    # 短信验证码 key
    SMS_CODE_KEY = 'meiduo:sms:code:{mobile}'

    # 短信发送标记
    SMS_SEND_FLAG_KEY = 'meiduo:sms:send:flag:{mobile}'

    # 省份数据 key
    PROVINCES_KEY = 'meiduo:area:provinces'

    # 市区数据 key
    SUB_AREA_KEY = 'meiduo:sub_area:{area_id}'

    # 用户商品浏览记录
    HISTORY_BROWSE_KEY = 'meiduo:history:{user_id}'

    # 用户购物车数据 key
    USER_CARTS_KEY = 'meiduo:carts:{user_id}'

    # 购物车商品是否勾选 key
    CARTS_SELECTED_KEY = 'meiduo:cart:selected:{user_id}'

Rediskey 的名称,就非常见名知意。

项目名称 业务模块/功能 唯一标识
'meiduo:img:code:{uuid}'
'meiduo:sms:code:{mobile}'
'meiduo:carts:{user_id}'
'meiduo:history:{user_id}'

这里还有一个 settings 配置的常量设置

# redis 缓存 ip/port 信息
REDIS_URI = f"redis://{SERVER_IP}:6379"

# 缓存别名
DEFAULT_CACHE_ALIAS = 'default'
SESSION_CACHE_ALIAS = "session"
VERIFY_CODE_CACHE_ALIAS = 'verify_code'
HISTORY_CACHE_ALIAS = 'history'
CARTS_CACHE_ALIAS = 'carts'

# 缓存
CACHES = {
    # 默认采用0号Redis库。
    DEFAULT_CACHE_ALIAS: {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": f"{REDIS_URI}/0",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    },

    # session, 采用1号Redis库
    SESSION_CACHE_ALIAS: {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": f"{REDIS_URI}/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    },
    
   # 校验码(图片、短信验证码), 采用2号Redis库
    VERIFY_CODE_CACHE_ALIAS: {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": f"{REDIS_URI}/2",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    },
    ...
}


封装前后代码对比

封装前

from django.conf import settings
from django_redis import get_redis_connection
from meiduo_mall.utils.constants import RedisKey

# 创建连接到redis的对象
redis_conn = get_redis_connection('verify_code')

img_code_key = 'meiduo:img:code:' + uuid 

image_code_server = redis_conn.get(img_code_key)

封装后

from django.conf import settings
from django_redis import get_redis_connection
from meiduo_mall.utils.constants import RedisKey

# 创建连接到redis的对象
redis_conn = get_redis_connection(settings.VERIFY_CODE_CACHE_ALIAS)

img_code_key = RedisKey.IMG_CODE_KEY.format(uuid=uuid)

image_code_server = redis_conn.get(img_code_key)

虽然封装的代码量添加了一些,但有助于你更快的了解项目大概做了什么,以及提高可维护性。不用到具体的模块、类、函数中一个个查看,日后更新只需在封装的类中改下即可。


注意:文章中有很多伪代码,主要是体现代码设计与编写的思想。


尾语

✍ 用 Code 谱写世界,让生活更有趣。❤️

✍ 万水千山总是情,点赞再走行不行。❤️

✍ 码字不易,还望各位大侠多多支持。❤️