Цель этой статьи
«Динамический тип — это круто какое-то время, крематорий рефакторинга кода», то есть: динамический язык относительно крут на начальном этапе разработки, но его сложнее поддерживать на более позднем этапе. Как один из динамических языков, Python, естественно, имеет такие недостатки. На самом деле "крематорий" - это не так уж и серьезно, при строгом соблюдении набора спецификаций его тоже можно "рефакторить, это же круто".
Нормы, естественно, очень важны, а в динамических языках они особенно важны (многие люди пишут скрипты на Python, в основном пишу их по своему желанию, что, естественно, сложно потом поддерживать). Так называемые «ставки и кони идут первыми», мы должны проделать достаточно «поверхностной работы» перед написанием кода.
Что не охватывает эта статья
Не делайте: «Документ читает машину». В Pep 8 это было, и не повторим, повторите некоторые из «ниже (мы все знаем)« Содержание », ничего не знаком.
Не верьте авторитету, здесь имеется в виду "Руководство по Python для Google", которое является спецификацией, подходящей для Google, а не спецификацией сообщества. На самом деле, я думаю, что эта спецификация не является полной, и в то же время это всего лишь какой-то «известный» контент, который не рекомендуется.
Не занимайтесь религиозными убеждениями, льстите прагматизму. Например, типичное «импортировать это», мне одному кажется, что это просто куча пустой чепухи? не достигнуто. Каждый раз, когда в различных статьях (недобросовестных маркетинговых статьях, с различными учебными заведениями в качестве основной части) упоминается это, мне становится очень неловко и неловко (написание кода — это очень инженерно и серьезно, зачем заниматься такой метафизикой? ).
Область применения и принципы
- Python 2.7 — Python 3.x. Хотя официально заявлено, что срок жизни Python 2 — 2020 год, и похоже, что Python 3 сейчас стал мейнстримом. Но одноклассники, устаревший код не убрать, Python 2 еще долго будет существовать. Кроме того, есть ли у Python 3 «убойная функция» по сравнению с Python 2?
- Создан по образцу PEP 8, тесно объединенный вокруг PEP 8. Любая неофициальная документация предназначена только для справки (аналогично, эта статья тоже своего рода справочная).
- Не повторяйте то, что уже есть в PEP 8.
Спецификация
[Обязательно + Обязательно] [Выберите инструмент «Статическая проверка» и используйте его строго от начала до конца]
简单来说,就是:
1. Pylint
2. Flake8
3. pytest
一开始就要使用,并且从严使用(发点时间了解这几个工具,带来的收益是无限的,如果你是比较正式的项目的话)。
【Обязательно+】【Множественная запись UT】
其他编程语言,同理。
有一份UT在手,重构起来,心里放心很多。
Python的话,只需要了解unittest就够了,pytest也可以。
【Обязательно】【Кодировка файлов и Юникод】
PS:Следующие пункты могут помочь вам избежать многих скучных проблем с кодированием и декодированием, поэтому я думаю, что это очень важно.
- Отступ с 4 пробелами, отключите любые символы вкладок
- Исходные файлы используют формат кодировки UTF-8 без спецификации.
- Всегда используйте символы новой строки в стиле Unix \n
- В заголовке каждого файла py добавьте следующее:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# 只导入 future 空间的这两个特性就够了,其他特性容易造成其他方面的『不兼容』,没有使用的必要性。
from __future__ import (absolute_import, unicode_literals)
所以,你需要了解 editorconfig 这个东西,从根源上统一规范,不符合规范的,直接拒绝 PUSH or MERGE
###【Обязательно】【Имя】
- Как назвать класс и функцию, я не буду вдаваться в подробности, просто строго следуйте PEP8, не думайте слишком много.
- Глобальные переменные (глобальные переменные, как правило, константы, мы думаем: все глобальные переменные являются константами) всегда должны использовать все заглавные буквы, например:
GLOBAL_PUBLIC = "G1"
_GLOBAL_PRIVATE = "G2"
class Person:
_GLOBAL_IN_CLASS = 'G3'
按照这条要求,其实很多库or开源库,都是不符合要求的。为什么这么强硬呢?
Python中的变量定义,是不分『声明』、『定义』、『初始化』、『赋值』这几个概念的,所以一个
a = 1
如果没有上下文,你是很难确定其作用域的,也很难确定 这到底是初始化还是赋值(a已经存在过),
如果全局变量还不用全大写,带来的麻烦只会更多。
如果始终坚持这个原则,将会给代码的可读性带来极大提升。
[Обязательно] Определите перечисление, всегда добавляйте суффикс Enum; определяйте исключение, всегда добавляйте суффикс исключения; определяйте миксин, всегда добавляйте суффикс миксина, например
class DirectionEnum:
UP = 1
DOWN = 2
class MyException(Exception):
pass
class MyError(Exception):
pass
class SomeMixin:
pass
[Обязательно] [Усилить понятие частного]
即:最小知识原则,对外暴露的东西越少越好
翻译成大白话就是:
1. 实例属性,一般定义成private的
2. class,对外提供的方法越少越好
3. module,对外提供的接口越少越好
4. package,对外提供的 module 越少越好
翻译成代码就是:
1. 项目布局
package/
__init__.py
_private_mod.py
public_mod.py
2. 某模块内容
public_mod.py
PUBLIC_GLOBAL = 'G1'
_PRIVATE_GLOBAL = 'G2'
class _Class:
pass
class PublicClass:
_PRIVATE_GLOBAL = 'G3'
def __init__(self, name,age):
self._name = name
self._age = age
def public_method(self):
pass
def _private(self):
pass
所有东西,一开始就要定义成私有的,等到确实需要开放访问了,才开放出去。
[Обязательно и важно] [Сосредоточьтесь на сложности общедоступных интерфейсов]
最好的接口是这样的,调用者无脑使用
def interface():
pass
次等接口是这样的
def interface(param1):
pass
次次等接口是这样的
def interface(p1, p2):
pass
最大忍受限度的接口是这样的
def interface(p1, p2, p3='SOME DEFAULT'):
pass
def interface(p1, *args):
pass
不可接受的接口是这样的
def interface(p1, p2, **kwargs):
pass
令人无语的接口是这样的
def interface(*args, **kwargs):
# 尽量不要使用 **kwargs, 某些流行库有这样的毛病,我是觉得:极大地增加了调用者的心理负担,反映了接口设计者的懒惰
pass
一直觉得,**kwargs只适用于极少数明确的场合,并且需要辅以很明确的文档说明(解释为什么要使用),然而现实是,这个
特性已经被大家滥用了,有必要单独说明之。
PS: Я всегда чувствую, что злоупотребление API **kwargs — это почти не очень хороший API, который незаметно увеличивает психологическую нагрузку.
[Рекомендация] [Создавайте пространства имен с помощью пакетов, а не модулей]
【Рекомендация】【Знайте следующее】
__init__.py 的作用
__main__.py 的作用
if __name__ == '__main__': 的作用
Python的命名空间加载机制,即:sys.path sys.modules 的内容
[рекомендуется] [разумная структура каталогов дизайн-проекта]
如果是使用某种框架(如Django),那么按照框架的规范来;如果是“非框架”项目,则按照如下结构
project
project/
__init__.py
core/
utils/
constants/
__main__.py
tests/
docs/
examples/
README.md
.pylintrc
.flake8