python 之禅 import this

dongweiming的博客
前言
我这个博客一直都是一些技术分享,show code的地方,我从来没有写过个人生活或者情感杂谈,当然我也从来没有谈论过我对什么东西的喜恶. 很多人喜欢喷XX语言,喜欢谈论XX和YY的优缺,甚至凑了一本不知所云的书…好吧,我觉得没有使用一门语言超过10年,没有对一个技术研究个5,6年, 不好意思说自己懂(天才除外).我也觉得我没有资格讨论什么,也许我有我的观点看法,但是我怀着怀疑的心态看自己,生怕自己理解错了. 下文纯属个人吐槽,也许没有指定路怎么走,只是希望提个醒…

使用python2年,可喜的是python被越来越多的人接受,甚至前端工程师…但是却有点烂大街的感觉:感觉出门不聊几句python都不好意思和人打招呼.但是你真的懂python嘛?

你会python真的不重要
python实在太好学习了,假如你会其它的语言,可能搞本书翻一翻,一周后就能写很高端的python程序,由于web框架的普及,你甚至可以让一个网站应用跑起来. 你会我也会,你有什么竞争力?

你知道python怎么用嘛?
在什么时候需要使用OOP?
在什么时候使用类装饰器?
你用过元类嘛?
在什么时候用静态方法什么时候使用类方法?
你了解那些管理属性? call , init , __new__都是在什么时候被触发?__getattr__和__getattribute__应用有什么不同?
你知道标准库里面的多少个模块?你能在需要的时候知道这个功能其实标准库里面已经实现了?
什么时候用回调?
什么时候用signal?假如你会django你知道django的signal是什么?你了解orm嘛?
asyncore,contextlib, functools, collections, heapq,itertools, SocketServer, weakref,operator(知道3个就算)这些你会几个?
python的多态是什么?
在什么场景可以尝试python的设计模式中的XX(能想到2个场景就算)?
在什么时候可以使用Mixin?
在什么时候可以使用python的闭包?
你曾经用过yield嘛?生成器和迭代器的区别和应用场景是什么?
在什么可以使用python的函数式编程?
__future__模块里面都有什么定义的用法?
提笔想了这上面16点我认为体现python的东西,假如你不能有效的回答上面1/4, 好吧不要和我说你原来是会python的,踏实下来..你的路还很长.假如你回答不超过一半,我提醒你-你只是刚入行而已(这是我的角度)

假如我是一个入职后的带新人的引导者
学好git… 呵呵
假如新人还不熟悉python,python_koans是和不错的入门选择
首先就是严格的代码规范,加上团队的文化以及风格.
我会给一个任务,比如一周内写个多线程的socket命令行聊天程序,支持群组,加好友,群聊,发送文件等功能,看新人能力而定
而后把项目一部分略棘手的工作教给他,注意这里是生产环境,在他完成任务的过程中会熟悉我们的上线/code review/代码风格等东西
我希望整个团队一起贡献一个基础的公共库,包含一些常用的功能,然后新人首先学习这些东西,以后就不需要浪费时间造轮子,但是可以修改完善公共库, 这个公共库可以在新服务器部署时候直接使用pypi或者ubuntuPPA安装进来
什么算是好的python代码?
假如你的代码没使用pep8检验过,你已经无敌了. 最差你也要使用autopep8格式化差劲的代码吧?如果你想对自己的代码质量有要求,我强烈建议你了解什么是pythonic:

doughellmann 的作者 an-introduction-to-the-zen-of-python
be-pythonic
代码易懂但是堆和代码难懂但是精炼的取舍
我想很多对代码有追求的人都发现一件事情?看见项目中存在大量,没有被重用的函数,似曾相似的方法甚至方法的名字… 我是极为见不得ugly或者华而不实的代码的人, 但是有个问题. 我封装的代码很不直观,难懂..原来的代码貌似极为好懂.每个人都有自己的理解吧.就象我的团队里面有人说django代码太难懂,因为它们有django项目组的文化… celery代码写的不好这样的安慰似的评论…但是我不这样认为,我还在读celery代码,我也承认里面是有作者风格的取名或者实现的方式,但是我学到了很多.

通过看开源代码,比如django,requests,flask. 我会发现和总结很多别人的用法,思考别人为啥这样用.比如项目代码目录结构,解决一些问题使用的方式. 还有一些pep8中没有提到的规范. 比如一些代码实用的风格,举个例子:

我们的代码引用其它模块是这样的:

from test import long_long_long_test1
from test import long_long_long_test2
form test import long_long_long_test3
省略20多行,很闹残吧? 有一种风格是

from test import long_long_long_test1, long_long_long_test2, long_long_long_test3
说一个技巧:当我不知道该用什么,去看很NB项目怎么用 结果django和requests是这样的风格

from test import (long_long_long_test1,
long_long_long_test2,
long_long_long_test3)
怎么样进步?不是闭门造车..先去看看别人是怎么用的..

比如我以前拼接一个文件路径都是这样:

'{0}/{1}'.fotmat(dir, filename)
其实人家本来有:

os.path.join(dir, filename)
很惭愧.然后花了半个小时,把以前我这样用的地方全改了

这是我说的重要的一点: 知道了什么是对的 就要改….

对于这个主题我的答案: 我喜欢难懂但是精炼的代码. 境界就是你看的懂就能写的出来. 假如你连这点代码都看不懂.你看不了开源项目的做法.你会一直是个堆代码的码农..你会一直在堆着垃圾的代码.你会增加未来接手人的维护成本

怎么样提高python可读性和质量
以下是我的想法

首先给函数/类/方法取个好懂的名字(我这点很失败,英语太烂…是不是应该加一个学好英语)
当一个差不多的操作出现了三次,不要继续堆代码,要抽象出来
我倾向于写FIXME,TODO, 写文件/函数的用途的注释,在不是很好理解的代码上面注释作用,标明输入和输出都是什么(如果不是要修改维护你的代码,没人在乎你的算法多NB)
上面说的,请不要让别人需要仔细研究你的代码才明白是什么意思.. 我写代码很有压力,因为我不想接受我带嘛的人骂我.
不要炫技,请不要乱用函数式编程/闭包.我在乎的是性能和简单粗暴的实现功能
多用标准库的实现,如果不知道有这个功能实现前先google.
多读有名的项目,github上面有很多.思考别人为什么这样用
….

我们是封装开源项目还是直接修改开源代码给自己用
其实我这样描述,比如有个项目因为历史原因是一个很早的版本.但是和其它新的版本组件有兼容问题以及我们业务的特殊需要.我看了源码发现需要改动几个地方. 问题改动后就需要自己维护这个项目,对于新部署的环境甚至其它版本我还继续需要这个变动. 还有一种声音是”你不能修改XX源码”,你要在上面封装出一个新的东西, 也就是不直接调用XX,而是在我的自己的项目对XX有了个封装YY,然后我们的调用YY.

我觉得这个东西自己部署是一个可行的方案,首先这个修改不是一个patch,不是主流的修改.只能算是我们业务的二次开发而已,封装只是在掩耳盗铃. 着让我想起一个问题:为什么中国鲜有好的开源项目:中国人不缺好的idea?是因为中国人觉得这件事情做不了,是因为它们觉得别人实现的就是很牛比的, 自己改了就会有问题…其实这是自卑..首先是代码就会有bug,tornado/flask/requests不还是在开发和解决问题嘛?bug一直在只是你没有发现和注意. 我觉得开源项目的代码看懂了,了解了就可以修改..没什么可担心的…我指的是角度.我觉得每个人学了一门语言看了某个项目的源码只要你有胆量, 你有一个怀疑的善于发现和思考的心,那么你都能贡献你的代码,做你的二次开发.

和本文相关: 如果你没有做过这件事,你怎么可以说你会python?

我的感想
我不赞同”做好工作就好了”的调调.对你个人来说你明年今天做的事情和现在是一样的,不同的是你老了一岁. 如果是为什么完成工作而完成工作. 其实你这个代码就是线上运行的代码,并且是以后很长时间再用的版本,你随意的一些代码会在很久之后很难的变动.. 我也不同意一上来就把你的程序写的能承受千万级PV的架构.我认为对于现在项目状态,我要思考大约未来一年可能的发展,它如何简单的扩展就好了..

前言

对我来说,以前每次面试是我审视自己,检验自己的一种方式。每次准备面试,以及被面试官问住的时候才会发现,其实我python我学的还不够好。工作中也是,可以从其他的同事那里获得成长。但是我今天说的是,我也在自己总结和思考最佳实践这件事。

我想很多人都会有意识的去读一些PEP(Python Enhancement Proposals)。了解语言设计者当时的考虑,这些文案也是经过很长时间的讨论最后才实施的。既然想用好这门语言,必然需要理解设计之美。比如我听说gvanrossum使用emacs作为编辑器,我也使用emacs,就是希望我可以更贴近一些python。

本文根据 The Best of the Best Practices (BOBP) Guide for Python 和 Khan’s style-guides中对于开发中一些事物的理解和看法,有出至PEP,也有一些python界知名开发者,我加入了一些我自己的理解和看法。

价值观
“Build tools for others that you want to be built for you.” – Kenneth Reitz (Requests等知名库作者)
你自己都不想用的东西做出来有什么意义呢?

“Simplicity is alway better than functionality.” – Pieter Hintjens (ZeroMQ)
我对函数式编程的看法一直是看场景,甚至于我经常会对比性能,义无反顾的使用性能最好的,但是代码又不难懂和繁琐的

“Fit the 90% use-case. Ignore the nay sayers.” – Kenneth Reitz
程序员都有完美主义情怀,但是其实往往我们是在偏激的看事情 – 用户其实不case

“Beautiful is better than ugly.” – PEP 20
开发参考
“Explicit is better than implicit” – PEP 20
不要留坑,我经常看到一些复杂的代码,这些代码的作者写的时候明显知道自己在做什么,但是别人很难维护和看懂.
所以我对自己的职业的基本要求就是: 那天我离职了,后来接手的人不会经常骂我

“Readability counts.” – PEP 20
“Anybody can fix anything.” – Khan’s style-guides
我现在更多不是代码炫技,我经常思考的怎么让最少的代码,最简单的设计结构满足当前需求,也能给未来一段时间里也有扩展性

Fix each broken window (bad design,wrong decision,or poor code) as soon as it is discovered.
我们改bug有个原则 – 测试要覆盖到出bug的地方。每个人内心都有很高的代码质量的要求

“Now is better than never.” – PEP 20
明日复明日,明日何其多。我们在代码review的时候,问题需要在提出的时候就去改,永远不会说下一次再说,因为下一次大多时候是没有下一次了

Test ruthlessly. Write docs for new features.
Even more important that Test-Driven Development–Human-Driven Development
一些细节
PEP8
很多人是排斥的,假如你想让未来部门有自己的风格,习惯。让新人马上上手接受,PEP8是一个非常明智的选择

文件开头
新的文件的开头需要加一些docstring。描述文件的作用,编辑者,修改原因和日期等帮助阅读者的描述.

不要添加#!/usr/bin/python(除非这个文件未来是一个可执行的文件),copyright,__author__或者其他内容.

第一行建议添加# coding-utf-8

命名
Variables,functions,methods,packages,moduleslower_case_with_underscores
Classes and ExceptionsCapWords
Protected methods and internal functions_single_leading_underscore(self,…)
Private methods__double_leading_underscore(self,…)
ConstantsALL_CAPS_WITH_UNDERSCORES
Avoid one-letter variables (esp. l,O,I).永远不要使用没有意义的单字符作为变量名
PS: 这点可以折中,假如一个代码块代码逻辑很清晰,而 这个短的便令也只是过程中的一个间接变量之类的情况下是可以接受的

Good or Bad
列举一些正确和错误的用法.

Avoid redundant labeling.
复制代码

Good

import audio

core=audio.Core()
controller=audio.Controller()

Bad

import audio

core=audio.AudioCore()
controller=audio.AudioController()
复制代码

不要使用重复意义的标签

Prefer “reverse notation”.
复制代码

Good

elements=...
elements_active=...
elements_defunct=...

Bad

elements=...
active_elements=...
defunct_elements...
复制代码
Avoid getter and setter methods.

Good

person.age=42

Bad

person.set_age(42)

Indentation
永远不要Tab和空格混用。使用4个空格作为python缩进

Imports
Import entire modules instead of individual symbols within a module.

PS: 这个时候可以参考tornado的代码用法.

比如现在有这样一个包

$tree
└──canteen
├──init.py
├──sessions.py
复制代码

Good

import canteen
import canteen.sessions
from canteen import sessions

Bad

from canteen import get_user # Symbol from canteen/init.py
from canteen.sessions import get_session # Symbol from canteen/sessions.py
复制代码

PS: 除非这个第三方模块的文档显式的要求这些写

Splitting tricky lines
复制代码

Bad:

badge_name=badges.topic_exercise_badges.TopicExerciseBadge.name_for_topic_key_name(self.key().name())

Good:

badge_name=(badges.topic_exercise_badges.TopicExerciseBadge
.name_for_topic_key_name(self.key().name()))

Bad:

self.redirect("/class_profile?selected_graph_type=%s
复制代码

我添加的规则
from … import …
复制代码

Bad

from aa import alonglonglonglonglong,alonglonglonglonglonglonglonglonglong,
alonglonglonglonglonglong

Good

from aa import(alonglonglonglonglong,alonglonglonglonglonglonglonglonglong,
alonglonglonglonglonglong)
from aa import(alonglonglonglonglong,alonglonglonglonglonglonglonglonglong,
alonglonglonglonglonglong,alonglonglonglonglonglonglong,
alonglonglonglonglonglong2) # Good。 当引入的函数/类/变量很多时,也可以选择空 4 个空格的方式,而不需要和首行的左括号后对齐
复制代码
相对引用(relative import) 和 绝对引用(absolute import)
复制代码
$cat xx/models/user/consts.py # 如果想引用这个变量
TMP=1

$cat xx/views/user.py
from xx.models.user.consts import TMP # recommended。

假如模块层级>=3。 比如 xx/models/user/consts.py 就在根目录下的第 3 级。 如果其他当前目录下源文件需要调用它的内容。 也可以选择相对引用

$cat xx/models/user/main.py # 需要和 consts.py 在一个目录下才可以
from consts import TMP # Bad
from.consts import TMP # Good

而且只能在包内相对引用。 包外都需要绝对引用

复制代码

我Python 最佳实践指南
quoniammm
quoniammm
3 人赞了该文章
阅读这份指南我所学到的

  1. 代码风格

pip install pycodestyle
pycodestyle .py

pip install autopep8
autopep8 --in-place optparse.py

不包含 --in-place 标志将会使得程序直接将更改的代码输出到控制台,以供审查。

--aggressive 标志则会执行更多实质性的变化,而且可以多次使用以达到更佳的效果

my_very_big_string = (
"For a long time I used to go to bed early. Sometimes, "
"when I had put out my candle, my eyes would close so quickly "
"that I had not even time to say “I’m going to sleep.”"
)

行的延续

  1. Python Basics

嵌套函数与闭包

文件读取与写入 "a" "w" "r"

yield lambda 函数(即一种匿名函数)

面向对象编程 (属性与方法)

init(self, *arg) # 构造函数
str(self) #@override return str_name
static attribute # 定义在 init 函数外 所有类实例共享

继承与多态

class son(Parent):
pass
# super().method_name # 调用父类方法

注释

Pypi

调试 (vscode 大法好)

创建可执行文件 (pyinstaller)

setup 文件 requirements 文件

ansible???

python fg (终端)

/ or //

int float NoneType bool

str 在 python 里是 immutable sequences of unicode codepoints

bytes 在 python 里是 immutable sequences of bytes

.encode() .decode()

list 在 python 里是 mutable sequences of objects

dict 在 python 里是 mutable mappings of keys to values

Special attributes in Python are delimited by double underscores

"""
name gives us the means for our module to detect whether it has been run
as a script or imported into another module or the REPL.
"""
print(name)
if name == 'main':
function()

sys.argv[1]

advanced command line argument parsing:

Python Standard Library: argparse

Many third-party options such as docopt

docstrings 的使用方式

"""description

Args:
description

可选

Raises:
IOError: ......

Returns:
description
"""

#! 符号

!/use/bin/env python3

注意: Module code is executed exactly once, on first import 即上面的 print 函数只会执行一次

value equality vs. identity (使用 is)

一个容易出错的地方

a = [1, 2]
def replace(f):
f = [4, 5]
replace(a) # 结果: a 的值还是 [1, 2] 这其实还是一种闭包 (closure)

即 Function arguments are passed by object-reference (使用 id() 可以验证)

dir() 查看属性 name doc

          #      Static    #   Dynamic

Strong    #                #   Python

 Weak     #                #   JavaScript

解释上图:

1.In a dynamic type system object types are only resolved at runtime

2.In a strong type system there is no implicit(隐式)type conversion

作用域

Local Enclosing Global Built-in(LEGB)

一个容易出错的地方

count = 0

def show_count():
print("count = ", count)

def set_count(c):
global count # 不加这一行会出错
count = c

Everything is an Object(一切皆对象)

we follow patterns Not to kill complexity But to master it

Special cases aren't special enough to break the rules

Python Collections(str/list/dict/tuple/range/set)

1.tuple

heterogeneous(各种各样的) immutable sequence
("www", 123, True) # in or not in

2. string

homogeneous(同类的,同性质的) immutable sequence of Unicode codepoints(characters)
.split() .join()
.partition() # divide a string into three around a seperator:

prefix, separator, suffix

3. range

arithmetic(算数,算法) progression of integers

4. List

heterogeneous mutable sequence
.index(item) # ValueError if not found
.insert(index, item)
.extend(list)
.reverse()
.sort() # reverse=True

built-in function

sorted(list)
list(reversed(list))

5. Dict

{}
dict([(), ()])
dicr(a=b, c=d)
.copy()
.update()
.values() # 忽略 keys
.keys() # 同上
.items() # 同上
from pprint import pprint as pp # pretty print 美化作用

6. Set

unordered collection of unique, immutable objects
{1, 4, 67, 8999}
s = set([list])
.remove()
.discard()
.copy()
.union() # 并集
.intersection() # 交集
.difference() # 交集的补集
.symmetric_difference() # 补集
.issubset() # 子集
.issuperset() # 父集
.isdisjoint() # 不相交

Handle Exception (觉得用不到哎 大部分时候)

Rasie/Handle/Unhandled exceptions/Exception objects
try:
except ValueError: # except (ValueError, TypeError) as e:
# str(e)
(finally)
return

Indentation Error/ SyntaxError/ NameError

Iterable Objects(可迭代对象)

List/Set/Dict Comprehension(递推式构造列表)

iter() # 获得 iterator
next() # 获得当前元素

generator 通关 yeild 生成

from itertools import islice, count
any()
zip()

unittest(单元测试)

unittest

debugging

pdb

distribute your program

in the face of ambiguity, refuse the temptation to guess(这句话很有道理)

You can pass -m to your Python command to have it run a module as a script

浅拷贝

  1. Python 进阶

3.1 Python 包(Package)与模块(Module)

简单理解包和模块的区别是:包是一组模块的集合

sys.path.append

export PYTHONPATH=path_name

包的结构

reader/init.py
reader/reader.py

touch reader/init.py
import reader
print(type(reader))
reader.__file__ # 结果: './reader/init.py'

子包(Subpackages)

reader/compressed/init.py
reader/compressed/bzipped.py
reader/compressed/gzipped.py

import reader
import reader.compressed
import reader.compressed.bzipped

absoulte imports 和 relative imports

.b (当前路径下的module)

..a (上一路径下的module)

from ..a import A
from . import common

命名空间包

namespace packages (packages split across several directories)

useful for spliting large packages into multiple parts

namesapce packages have no init.py

This avoids complex initialization ordering problems

sys.path.extend(['path1', 'path2'])

main.py 可执行的文件夹 包 在终端

layout

project_name/
project_name/main.py
project_name/project_name/init.py
project_name/project_name/subpackage/init.py
project_name/project_name/test/init.py
project_name/setup.py
3.2 深入理解 Python 函数

call() # 一个 built_in 的函数 理念是 class 可以像 function 一样被执行

即 Callable instances

简洁表达

result = true_value if condition else false_value

lambda 函数

callable() # bulit_in 函数 检测是否可调用

*args **agrs (参数的映射)

extended() (对应展开)

t = (11, 12, 13, 14)
f(*t)

f(arg1, arg2, *arg3)

trace(f, *args, **args)

int('ff', base=16) # <=>
trace(int, "ff", base=16)

transpose tables

tansposed = list(zip(*daily)) # 神奇 cool

local function(区域函数 decorator closure)

def sort_by_last_letter(strings):
x = 'clo'
def last_letter(s): # 每次的区域函数并不相同,没有 cahe
return s[-1] + x
return sorted(strings, key=last_letter)

sort_by_last_letter.last_letter(s)
test = sort_by_last_letter('ert')
test.__closure__l

function factory : function that returns new, specialized functions(闭包的应用)

def raise_to(exp):
def raise_to_exp(x):
return pow(x, exp)
return rasie_to_exp

LEGB does not apply when making new bindings.

global: introduce names from global namespace into the local namespace

how can you do the same for name bindings in enclosing scopes?(所以有了 nonlocal)

nonlocal: introduce names from the enclosing namespace into the local namespace

cool~ 继续加油

decorator(装饰器): modify or enhance fucntions without changing their definition

implemented as callables that take and return other callables

replace, enhance, or modify existing functions

def escape_unicode(f):
def wrap(*args, **kwargs):
x = f(*args, **kwargs)
return ascii(x)

return wrap

@escape_unicode
def china_city():
return '西安'

用作装饰器的对象必须是 callable

class objects as decorators

class My_class:
def init(self, f):
self.f = f
self.count = 0
def call(self, *args, **kwargs):
self.count += 1
return self.f(*args, **kwargs)

@My_class
def hello(name):
print('Hello, {}'.format(name))

hello.count

class instances as decorators

class Trace:
def init(self):
self.enabled = True
def call(self, f):
def wrap(*args, **kwargs):
if self.enabled:
print('Calling {}'.format(f))
return f(*args, **kwargs)
return wrap

tracer = Trace()

@tracer
def rolate_list(l):
return l[1:] + [l[0]]

多个装饰器

@tracer
@escape_unicode

def china_island_maker(name):
return name + '岛'

class 里使用装饰器

class IslandMaker:
def init(self, suffix):
self.suffix = suffix

@tracer
def make_island(self, name)
    return name + self.suffix

之前使用装饰器存在的问题: Naive decorators can lose important metadata

import functools
@functools.wraps()

例子: Validating Arguments

def check_non_negative(index):
def validator(f):
def wrap(args):
if args[index] < 0:
raise ValueError(
'Argument {} must be non-negative.'.format(index))
)
return f(
args)
return wrap
return validator

@check_non_negative(1)
def create_list(value, size):
return [value] * size
3.3 深入理解 Python 面向对象编程

class attr(better not) vs. instance attr

static methods with the @staticmethod decorator ()

class methods with the @classmethod decorator (cls)

static methods 的继承

class methods 的继承

没什么特别之处 与普通的 methods 继承方法一样 (同样可以 override)

encapsulation(包装,包裹,封装) using the @property decorator

第一次接触以上概念 道理都懂 什么时候用啊 可以看懂程序就好 吧?!

@property

getter 函数

def attr1(self):
return self._attr1

@attr1.setter

setter 函数

def attr1(self, value):
self._attr1 = value

知乎的编辑器难用的更翔一样

狗币知乎 自动保存十分的恶心

Method Resolution Order(mro)

class-bound

instance-bound

(这部分内容有遗失,抽空补上)

多继承

class subClass(Base1, Base2, ...):
pass

method resolution order(MRO) determines name lookup in all cases

className.__bases__
className.__mro__ (.mro()) # 见下图

C3 algorithm for calculating MRO in python

super() 感觉这个蛮重要的

super() returns a proxy object which routes method calls

Bound proxy: bound to a specific class or instance (更主要)

Unbound proxy: not bound to a class or instance

代理绑定分为: instance-bound and class-bound

下面 介绍 instance-bound proxy

super(ClassName, self).__init__() <=> super().__init()

即 look for a method on the base class

这也是一种实例绑定

calling super without arguments

3.4 深入理解 Python 语言特性

Exceptions and Errors

Exceptions are arranged in an inheritance hierarchy # assert

assert 5 > 2, "This is a error"
raise("some words")
except ValueError as e:
print("payload:", e.args)

chaining exception

traceback

Defining Context Managers

an object designed to be used in a with-statement

A context-manager ensures that resources are properly and automatically managed

Python introspection(自省)

很牛逼的属性 基本用不到 为什么用不到 因为你还不够牛逼

3.5 单元测试(Python 测试)

测试很重要 应该了解一下

unittest pytest doctest

python3 -m unittest -v

setup teardown

pytest

比 unittest 使用方便不少

就是导入你想要 test 的类

然后定义函数 以及一堆 assert 表达式

with pytest.raises(KeyError):
className.method(*arg)

pytest.skip("")

test fixture (setup 和 teardown)

@pytest.fixture
def phonebook(request):
phonebook = Phonebook()
def cleanup_phonebook():
phonebook.clear()
request.add_finalizer(cleanup_phonebook)
return phonebook

doctest

test double (目测暂时用不到 跳过)

the coverage and parameterized test(参数化测试)

1.measuring coverage of tests

2.using code coverage metrics when adding test cases

using a custom assert to reduce duplication

pip install coverage
pip install pytest-cov

python3 -m pytest --cov-report term-missing --cov tennis
python3 -m pytest --cov-report html --cov tennis

  1. Python 应用 (关于 Flask)

microframework

templates: Jinja 2 / Http and routing: Werkzeug / (Model), View, Controller

Blueprints

Development server + debugger

Unit testing support

  1. 总结

转载于:https://www.cnblogs.com/Frank99/p/9268843.html

Python中的"import this"命令可以让我们获得Python之禅的指导原则。Python之禅是由Tim Peters撰写的,其中包含了一些关于编写优秀Python代码的原则。这些原则包括:优美胜于丑陋,明了胜于晦涩,简洁胜于复杂,复杂胜于凌乱,扁平胜于嵌套,间隔胜于紧凑,可读性很重要,不要包容所有错误,除非你确定需要这样做,当存在多种可能时,不要尝试去猜测,而是尽量找一种明显的解决方案,如果你无法向人描述你的方案,那肯定不是一个好方案,命名空间是一种绝妙的理念,我们应当多加利用。\[1\]\[2\]\[3\]所以,当我们在Python中执行"import this"命令时,我们可以获得这些指导原则,这些原则对于编写优秀的Python代码非常重要。 #### 引用[.reference_title] - *1* [python学习笔记 —— " import this ](https://blog.csdn.net/qq_45077143/article/details/96404455)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [python——this](https://blog.csdn.net/niu1024/article/details/105103224)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值