python 之禪 import this

dongweiming的博客
前言
我這個博客一直都是一些技術分享,show code的地方,我歷來沒有寫過我的生活或者情感雜談,固然我也歷來沒有談論過我對什麼東西的喜惡. 不少人喜歡噴XX語言,喜歡談論XX和YY的優缺,甚至湊了一本不知所云的書…好吧,我以爲沒有使用一門語言超過10年,沒有對一個技術研究個5,6年, 很差意思說本身懂(天才除外).我也以爲我沒有資格討論什麼,也許我有個人觀點見解,可是我懷着懷疑的心態看本身,生怕本身理解錯了. 下文純屬我的吐槽,也許沒有指定路怎麼走,只是但願提個醒…html

使用python2年,可喜的是python被愈來愈多的人接受,甚至前端工程師…可是卻有點爛大街的感受:感受出門不聊幾句python都很差意思和人打招呼.可是你真的懂python嘛?前端

你會python真的不重要
python實在太好學習了,假如你會其它的語言,可能搞本書翻一翻,一週後就能寫很高端的python程序,因爲web框架的普及,你甚至可讓一個網站應用跑起來. 你會我也會,你有什麼競爭力?python

你知道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

假如我是一個入職後的帶新人的引導者
學好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代碼,我也認可裏面是有做者風格的取名或者實現的方式,可是我學到了不少.github

經過看開源代碼,好比django,requests,flask. 我會發現和總結不少別人的用法,思考別人爲啥這樣用.好比項目代碼目錄結構,解決一些問題使用的方式. 還有一些pep8中沒有提到的規範. 好比一些代碼實用的風格,舉個例子:web

咱們的代碼引用其它模塊是這樣的:面試

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是這樣的風格django

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. 總結
相關文章
相關標籤/搜索