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. 總結


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM