本文始發於我的公衆號:TechFlow,原創不易,求個關注python
最近有許多小夥伴後臺聯繫我,說目前想要學習Python,可是沒有一份很好的資料入門。一方面的確如今市面上Python的資料過多,致使新手會不知如何選擇,另外一個問題不少資料內容也很雜,從1+1到深度學習都包括,純粹關注Python自己語法的優質教材並不太多。程序員
恰好我最近看到一份不錯的英文Python入門資料,我將它作了一些整理和翻譯寫下了本文。這份資料很是純粹,只有Python的基礎語法,專門針對想要學習Python的小白。web
Python中用#表示單行註釋,#以後的同行的內容都會被註釋掉。面試
# Python中單行註釋用#表示,#以後同行字符所有認爲被註釋。
複製代碼
使用三個連續的雙引號表示多行註釋,兩個多行註釋標識之間內容會被視做是註釋。express
""" 與之對應的是多行註釋 用三個雙引號表示,這兩段雙引號當中的內容都會被視做是註釋 """
複製代碼
Python當中的數字定義和其餘語言同樣:編程
#得到一個整數
3
# 得到一個浮點數
10.0
複製代碼
咱們分別使用+, -, *, /表示加減乘除四則運算符。json
1 + 1 # => 2
8 - 1 # => 7
10 * 2 # => 20
35 / 5 # => 7.0
複製代碼
這裏要注意的是,在Python2當中,10/3這個操做會獲得3,而不是3.33333。由於除數和被除數都是整數,因此Python會自動執行整數的計算,幫咱們把獲得的商取整。若是是10.0 / 3,就會獲得3.33333。目前Python2已經再也不維護了,能夠不用關心其中的細節。api
但問題是Python是一個弱類型的語言,若是咱們在一個函數當中獲得兩個變量,是沒法直接判斷它們的類型的。這就致使了一樣的計算符可能會獲得不一樣的結果,這很是蛋疼。以致於程序員在運算除法的時候,每每都須要手工加上類型轉化符,將被除數轉成浮點數。數組
在Python3當中撥亂反正,修正了這個問題,即便是兩個整數相除,而且能夠整除的狀況下,獲得的結果也必定是浮點數。app
若是咱們想要獲得整數,咱們能夠這麼操做:
5 // 3 # => 1
-5 // 3 # => -2
5.0 // 3.0 # => 1.0 # works on floats too
-5.0 // 3.0 # => -2.0
複製代碼
兩個除號表示取整除,Python會爲咱們保留去除餘數的結果。
除了取整除操做以外還有取餘數操做,數學上稱爲取模,Python中用%表示。
# Modulo operation
7 % 3 # => 1
複製代碼
Python中支持乘方運算,咱們能夠不用調用額外的函數,而使用**符號來完成:
# Exponentiation (x**y, x to the yth power)
2**3 # => 8
複製代碼
當運算比較複雜的時候,咱們能夠用括號來強制改變運算順序。
# Enforce precedence with parentheses
1 + 3 * 2 # => 7
(1 + 3) * 2 # => 8
複製代碼
Python中用首字母大寫的True和False表示真和假。
True # => True
False # => False
複製代碼
用and表示與操做,or表示或操做,not表示非操做。而不是C++或者是Java當中的&&, || 和!。
# negate with not
not True # => False
not False # => True
# Boolean Operators # Note "and" and "or" are case-sensitive True and False # => False False or True # => True 複製代碼
在Python底層,True和False實際上是1和0,因此若是咱們執行如下操做,是不會報錯的,可是在邏輯上毫無心義。
# True and False are actually 1 and 0 but with different keywords
True + True # => 2
True * 8 # => 8
False - 5 # => -5
複製代碼
咱們用==判斷相等的操做,能夠看出來True==1, False == 0.
# Comparison operators look at the numerical value of True and False
0 == False # => True
1 == True # => True
2 == True # => False
-5 != False # => True
複製代碼
咱們要當心Python當中的bool()這個函數,它並非轉成bool類型的意思。若是咱們執行這個函數,那麼只有0會被視做是False,其餘全部數值都是True:
bool(0) # => False
bool(4) # => True
bool(-6) # => True
0 and 2 # => 0
-5 or 0 # => -5
複製代碼
Python中用==判斷相等,>表示大於,>=表示大於等於, <表示小於,<=表示小於等於,!=表示不等。
# Equality is ==
1 == 1 # => True
2 == 1 # => False
# Inequality is != 1 != 1 # => False 2 != 1 # => True # More comparisons 1 < 10 # => True 1 > 10 # => False 2 <= 2 # => True 2 >= 2 # => True 複製代碼
咱們能夠用and和or拼裝各個邏輯運算:
# Seeing whether a value is in a range
1 < 2 and 2 < 3 # => True
2 < 3 and 3 < 2 # => False
# Chaining makes this look nicer
1 < 2 < 3 # => True
2 < 3 < 2 # => False
複製代碼
注意not,and,or之間的優先級,其中not > and > or。若是分不清楚的話,能夠用括號強行改變運行順序。
關於list的判斷,咱們經常使用的判斷有兩種,一種是剛纔介紹的==,還有一種是is。咱們有時候也會簡單實用is來判斷,那麼這二者有什麼區別呢?咱們來看下面的例子:
a = [1, 2, 3, 4] # Point a at a new list, [1, 2, 3, 4]
b = a # Point b at what a is pointing to
b is a # => True, a and b refer to the same object
b == a # => True, a's and b's objects are equal
b = [1, 2, 3, 4] # Point b at a new list, [1, 2, 3, 4]
b is a # => False, a and b do not refer to the same object
b == a # => True, a's and b's objects are equal
複製代碼
Python是全引用的語言,其中的對象都使用引用來表示。is判斷的就是兩個引用是否指向同一個對象,而==則是判斷兩個引用指向的具體內容是否相等。舉個例子,若是咱們把引用比喻成地址的話,is就是判斷兩個變量的是否指向同一個地址,好比說都是沿河東路XX號。而==則是判斷這兩個地址的收件人是否都叫張三。
顯然,住在同一個地址的人必定都叫張三,可是住在不一樣地址的兩我的也能夠都叫張三,也能夠叫不一樣的名字。因此若是a is b,那麼a == b必定成立,反之則否則。
Python當中對字符串的限制比較鬆,雙引號和單引號均可以表示字符串,看我的喜愛使用單引號或者是雙引號。我我的比較喜歡單引號,由於寫起來方便。
字符串也支持+操做,表示兩個字符串相連。除此以外,咱們把兩個字符串寫在一塊兒,即便沒有+,Python也會爲咱們拼接:
# Strings are created with " or '
"This is a string."
'This is also a string.'
# Strings can be added too! But try not to do this. "Hello " + "world!" # => "Hello world!" # String literals (but not variables) can be concatenated without using '+' "Hello " "world!" # => "Hello world!" 複製代碼
咱們可使用[]來查找字符串當中某個位置的字符,用len來計算字符串的長度。
# A string can be treated like a list of characters
"This is a string"[0] # => 'T'
# You can find the length of a string len("This is a string") # => 16 複製代碼
咱們能夠在字符串前面加上f表示格式操做,而且在格式操做當中也支持運算,好比能夠嵌套上len函數等。不過要注意,只有Python3.6以上的版本支持f操做。
# You can also format using f-strings or formatted string literals (in Python 3.6+)
name = "Reiko"
f"She said her name is {name}." # => "She said her name is Reiko"
# You can basically put any Python statement inside the braces and it will be output in the string.
f"{name} is {len(name)} characters long." # => "Reiko is 5 characters long."
複製代碼
最後是None的判斷,在Python當中None也是一個對象,全部爲None的變量都會指向這個對象。根據咱們前面所說的,既然全部的None都指向同一個地址,咱們須要判斷一個變量是不是None的時候,可使用is來進行判斷,固然用==也是能夠的,不過咱們一般使用is。
# None is an object
None # => None
# Don't use the equality "==" symbol to compare objects to None # Use "is" instead. This checks for equality of object identity. "etc" is None # => False None is None # => True 複製代碼
理解了None以後,咱們再回到以前介紹過的bool()函數,它的用途其實就是判斷值是不是空。全部類型的默認空值會被返回False,不然都是True。好比0,"",[], {}, ()等。
# None, 0, and empty strings/lists/dicts/tuples all evaluate to False.
# All other values are True
bool(None)# => False
bool(0) # => False
bool("") # => False
bool([]) # => False
bool({}) # => False
bool(()) # => False
複製代碼
除了上面這些值之外的全部值傳入都會獲得True。
Python當中的標準輸入輸出是input和print。
print會輸出一個字符串,若是傳入的不是字符串會自動調用__str__方法轉成字符串進行輸出。默認輸出會自動換行,若是想要以不一樣的字符結尾代替換行,能夠傳入end參數:
# Python has a print function
print("I'm Python. Nice to meet you!") # => I'm Python. Nice to meet you!
# By default the print function also prints out a newline at the end. # Use the optional argument end to change the end string. print("Hello, World", end="!") # => Hello, World! 複製代碼
使用input時,Python會在命令行接收一行字符串做爲輸入。能夠在input當中傳入字符串,會被當成提示輸出:
# Simple way to get input data from console
input_string_var = input("Enter some data: ") # Returns the data as a string
# Note: In earlier versions of Python, input() method was named as raw_input()
複製代碼
Python中聲明對象不須要帶上類型,直接賦值便可,Python會自動關聯類型,若是咱們使用以前沒有聲明過的變量則會出發NameError異常。
# There are no declarations, only assignments.
# Convention is to use lower_case_with_underscores
some_var = 5
some_var # => 5
# Accessing a previously unassigned variable is an exception. # See Control Flow to learn more about exception handling. some_unknown_var # Raises a NameError 複製代碼
Python支持三元表達式,可是語法和C++不一樣,使用if else結構,寫成:
# if can be used as an expression
# Equivalent of C's '?:' ternary operator
"yahoo!" if 3 > 2 else 2 # => "yahoo!"
複製代碼
上段代碼等價於:
if 3 > 2:
return 'yahoo'
else:
return 2
複製代碼
Python中用[]表示空的list,咱們也能夠直接在其中填充元素進行初始化:
# Lists store sequences
li = []
# You can start with a prefilled list
other_li = [4, 5, 6]
複製代碼
使用append和pop能夠在list的末尾插入或者刪除元素:
# Add stuff to the end of a list with append
li.append(1) # li is now [1]
li.append(2) # li is now [1, 2]
li.append(4) # li is now [1, 2, 4]
li.append(3) # li is now [1, 2, 4, 3]
# Remove from the end with pop
li.pop() # => 3 and li is now [1, 2, 4]
# Let's put it back
li.append(3) # li is now [1, 2, 4, 3] again.
複製代碼
list能夠經過[]加上下標訪問指定位置的元素,若是是負數,則表示倒序訪問。-1表示最後一個元素,-2表示倒數第二個,以此類推。若是訪問的元素超過數組長度,則會出發IndexError的錯誤。
# Access a list like you would any array
li[0] # => 1
# Look at the last element
li[-1] # => 3
# Looking out of bounds is an IndexError li[4] # Raises an IndexError 複製代碼
list支持切片操做,所謂的切片則是從原list當中拷貝出指定的一段。咱們用start: end的格式來獲取切片,注意,這是一個左閉右開區間。若是留空表示所有獲取,咱們也能夠額外再加入一個參數表示步長,好比[1:5:2]表示從1號位置開始,步長爲2獲取元素。獲得的結果爲[1, 3]。若是步長設置成-1則表明反向遍歷。
# You can look at ranges with slice syntax.
# The start index is included, the end index is not
# (It's a closed/open range for you mathy types.)
li[1:3] # Return list from index 1 to 3 => [2, 4]
li[2:] # Return list starting from index 2 => [4, 3]
li[:3] # Return list from beginning until index 3 => [1, 2, 4]
li[::2] # Return list selecting every second entry => [1, 4]
li[::-1] # Return list in reverse order => [3, 4, 2, 1]
# Use any combination of these to make advanced slices
# li[start:end:step]
複製代碼
若是咱們要指定一段區間倒序,則前面的start和end也須要反過來,例如我想要獲取[3: 6]區間的倒序,應該寫成[6:3:-1]。
只寫一個:,表示所有拷貝,若是用is判斷拷貝先後的list會獲得False。可使用del刪除指定位置的元素,或者可使用remove方法。
# Make a one layer deep copy using slices
li2 = li[:] # => li2 = [1, 2, 4, 3] but (li2 is li) will result in false.
# Remove arbitrary elements from a list with "del" del li[2] # li is now [1, 2, 3] # Remove first occurrence of a value li.remove(2) # li is now [1, 3] li.remove(2) # Raises a ValueError as 2 is not in the list 複製代碼
insert方法能夠指定位置插入元素,index方法能夠查詢某個元素第一次出現的下標。
# Insert an element at a specific index
li.insert(1, 2) # li is now [1, 2, 3] again
# Get the index of the first item found matching the argument li.index(2) # => 1 li.index(4) # Raises a ValueError as 4 is not in the list 複製代碼
list能夠進行加法運算,兩個list相加表示list當中的元素合併。等價於使用extend方法:
# You can add lists
# Note: values for li and for other_li are not modified.
li + other_li # => [1, 2, 3, 4, 5, 6]
# Concatenate lists with "extend()" li.extend(other_li) # Now li is [1, 2, 3, 4, 5, 6] 複製代碼
咱們想要判斷元素是否在list中出現,可使用in關鍵字,經過使用len計算list的長度:
# Check for existence in a list with "in"
1 in li # => True
# Examine the length with "len()" len(li) # => 6 複製代碼
tuple和list很是接近,tuple經過()初始化。和list不一樣,tuple是不可變對象。也就是說tuple一旦生成不能夠改變。若是咱們修改tuple,會引起TypeError異常。
# Tuples are like lists but are immutable.
tup = (1, 2, 3)
tup[0] # => 1
tup[0] = 3 # Raises a TypeError
複製代碼
因爲小括號是有改變優先級的含義,因此咱們定義單個元素的tuple,末尾必須加上逗號,不然會被當成是單個元素:
# Note that a tuple of length one has to have a comma after the last element but
# tuples of other lengths, even zero, do not.
type((1)) # => <class 'int'>
type((1,)) # => <class 'tuple'>
type(()) # => <class 'tuple'>
複製代碼
tuple支持list當中絕大部分操做:
# You can do most of the list operations on tuples too
len(tup) # => 3
tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6)
tup[:2] # => (1, 2)
2 in tup # => True
複製代碼
咱們能夠用多個變量來解壓一個tuple:
# You can unpack tuples (or lists) into variables
a, b, c = (1, 2, 3) # a is now 1, b is now 2 and c is now 3
# You can also do extended unpacking
a, *b, c = (1, 2, 3, 4) # a is now 1, b is now [2, 3] and c is now 4
# Tuples are created by default if you leave out the parentheses
d, e, f = 4, 5, 6 # tuple 4, 5, 6 is unpacked into variables d, e and f
# respectively such that d = 4, e = 5 and f = 6
# Now look how easy it is to swap two values
e, d = d, e # d is now 5 and e is now 4
複製代碼
解釋一下這行代碼:
a, *b, c = (1, 2, 3, 4) # a is now 1, b is now [2, 3] and c is now 4
複製代碼
咱們在b的前面加上了星號,表示這是一個list。因此Python會在將其餘變量對應上值的狀況下,將剩下的元素都賦值給b。
補充一點,tuple自己雖然是不可變的,可是tuple當中的可變元素是能夠改變的。好比咱們有這樣一個tuple:
a = (3, [4])
複製代碼
咱們雖然不能往a當中添加或者刪除元素,可是a當中含有一個list,咱們能夠改變這個list類型的元素,這並不會觸發tuple的異常:
a[1].append(0) # 這是合法的
複製代碼
dict也是Python當中常用的容器,它等價於C++當中的map,即存儲key和value的鍵值對。咱們用{}表示一個dict,用:分隔key和value。
# Dictionaries store mappings from keys to values
empty_dict = {}
# Here is a prefilled dictionary
filled_dict = {"one": 1, "two": 2, "three": 3}
複製代碼
dict的key必須爲不可變對象,因此list、set和dict不能夠做爲另外一個dict的key,不然會拋出異常:
# Note keys for dictionaries have to be immutable types. This is to ensure that
# the key can be converted to a constant hash value for quick look-ups.
# Immutable types include ints, floats, strings, tuples.
invalid_dict = {[1,2,3]: "123"} # => Raises a TypeError: unhashable type: 'list'
valid_dict = {(1,2,3):[1,2,3]} # Values can be of any type, however.
複製代碼
咱們一樣用[]查找dict當中的元素,咱們傳入key,得到value,等價於get方法。
# Look up values with []
filled_dict["one"] # => 1
filled_dict.get('one') #=> 1
複製代碼
咱們能夠call dict當中的keys和values方法,獲取dict當中的全部key和value的集合,會獲得一個list。在Python3.7如下版本當中,返回的結果的順序可能和插入順序不一樣,在Python3.7及以上版本中,Python會保證返回的順序和插入順序一致:
# Get all keys as an iterable with "keys()". We need to wrap the call in list()
# to turn it into a list. We'll talk about those later. Note - for Python
# versions <3.7, dictionary key ordering is not guaranteed. Your results might
# not match the example below exactly. However, as of Python 3.7, dictionary
# items maintain the order at which they are inserted into the dictionary.
list(filled_dict.keys()) # => ["three", "two", "one"] in Python <3.7
list(filled_dict.keys()) # => ["one", "two", "three"] in Python 3.7+
# Get all values as an iterable with "values()". Once again we need to wrap it # in list() to get it out of the iterable. Note - Same as above regarding key # ordering. list(filled_dict.values()) # => [3, 2, 1] in Python <3.7 list(filled_dict.values()) # => [1, 2, 3] in Python 3.7+ 複製代碼
咱們也能夠用in判斷一個key是否在dict當中,注意只能判斷key。
# Check for existence of keys in a dictionary with "in"
"one" in filled_dict # => True
1 in filled_dict # => False
複製代碼
若是使用[]查找不存在的key,會引起KeyError的異常。若是使用get方法則不會引發異常,只會獲得一個None:
# Looking up a non-existing key is a KeyError
filled_dict["four"] # KeyError
# Use "get()" method to avoid the KeyError filled_dict.get("one") # => 1 filled_dict.get("four") # => None # The get method supports a default argument when the value is missing filled_dict.get("one", 4) # => 1 filled_dict.get("four", 4) # => 4 複製代碼
setdefault方法能夠爲不存在的key插入一個value,若是key已經存在,則不會覆蓋它:
# "setdefault()" inserts into a dictionary only if the given key isn't present
filled_dict.setdefault("five", 5) # filled_dict["five"] is set to 5
filled_dict.setdefault("five", 6) # filled_dict["five"] is still 5
複製代碼
咱們可使用update方法用另一個dict來更新當前dict,好比a.update(b)。對於a和b交集的key會被b覆蓋,a當中不存在的key會被插入進來:
# Adding to a dictionary
filled_dict.update({"four":4}) # => {"one": 1, "two": 2, "three": 3, "four": 4}
filled_dict["four"] = 4 # another way to add to dict
複製代碼
咱們同樣可使用del刪除dict當中的元素,一樣只能傳入key。
Python3.5以上的版本支持使用**來解壓一個dict:
{'a': 1, **{'b': 2}} # => {'a': 1, 'b': 2}
{'a': 1, **{'a': 2}} # => {'a': 2}
複製代碼
set是用來存儲不重複元素的容器,當中的元素都是不一樣的,相同的元素會被刪除。咱們能夠經過set(),或者經過{}來進行初始化。注意當咱們使用{}的時候,必需要傳入數據,不然Python會將它和dict弄混。
# Sets store ... well sets
empty_set = set()
# Initialize a set with a bunch of values. Yeah, it looks a bit like a dict. Sorry.
some_set = {1, 1, 2, 2, 3, 4} # some_set is now {1, 2, 3, 4}
複製代碼
set當中的元素也必須是不可變對象,所以list不能傳入set。
# Similar to keys of a dictionary, elements of a set have to be immutable.
invalid_set = {[1], 1} # => Raises a TypeError: unhashable type: 'list'
valid_set = {(1,), 1}
複製代碼
能夠調用add方法爲set插入元素:
# Add one more item to the set
filled_set = some_set
filled_set.add(5) # filled_set is now {1, 2, 3, 4, 5}
# Sets do not have duplicate elements
filled_set.add(5) # it remains as before {1, 2, 3, 4, 5}
複製代碼
set還能夠被認爲是集合,因此它還支持一些集合交叉並補的操做。
# Do set intersection with &
# 計算交集
other_set = {3, 4, 5, 6}
filled_set & other_set # => {3, 4, 5}
# Do set union with | # 計算並集 filled_set | other_set # => {1, 2, 3, 4, 5, 6} # Do set difference with - # 計算差集 {1, 2, 3, 4} - {2, 3, 5} # => {1, 4} # Do set symmetric difference with ^ # 這個有點特殊,計算對稱集,也就是去掉重複元素剩下的內容 {1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5} 複製代碼
set還支持超集和子集的判斷,咱們能夠用大於等於和小於等於號判斷一個set是否是另外一個的超集或子集:
# Check if set on the left is a superset of set on the right
{1, 2} >= {1, 2, 3} # => False
# Check if set on the left is a subset of set on the right {1, 2} <= {1, 2, 3} # => True 複製代碼
和dict同樣,咱們可使用in判斷元素在不在set當中。用copy能夠拷貝一個set。
# Check for existence in a set with in
2 in filled_set # => True
10 in filled_set # => False
# Make a one layer deep copy filled_set = some_set.copy() # filled_set is {1, 2, 3, 4, 5} filled_set is some_set # => False 複製代碼
Python當中的判斷語句很是簡單,而且Python不支持switch,因此即便是多個條件,咱們也只能羅列if-else。
# Let's just make a variable
some_var = 5
# Here is an if statement. Indentation is significant in Python! # Convention is to use four spaces, not tabs. # This prints "some_var is smaller than 10" if some_var > 10: print("some_var is totally bigger than 10.") elif some_var < 10: # This elif clause is optional. print("some_var is smaller than 10.") else: # This is optional too. print("some_var is indeed 10.") 複製代碼
咱們能夠用in來循環迭代一個list當中的內容,這也是Python當中基本的循環方式。
""" For loops iterate over lists prints: dog is a mammal cat is a mammal mouse is a mammal """
for animal in ["dog", "cat", "mouse"]:
# You can use format() to interpolate formatted strings
print("{} is a mammal".format(animal))
複製代碼
若是咱們要循環一個範圍,可使用range。range加上一個參數表示從0開始的序列,好比range(10),表示[0, 10)區間內的全部整數:
""" "range(number)" returns an iterable of numbers from zero to the given number prints: 0 1 2 3 """
for i in range(4):
print(i)
複製代碼
若是咱們傳入兩個參數,則表明迭代區間的首尾。
""" "range(lower, upper)" returns an iterable of numbers from the lower number to the upper number prints: 4 5 6 7 """
for i in range(4, 8):
print(i)
複製代碼
若是咱們傳入第三個元素,表示每次循環變量自增的步長。
""" "range(lower, upper, step)" returns an iterable of numbers from the lower number to the upper number, while incrementing by step. If step is not indicated, the default value is 1. prints: 4 6 """
for i in range(4, 8, 2):
print(i)
複製代碼
若是使用enumerate函數,能夠同時迭代一個list的下標和元素:
""" To loop over a list, and retrieve both the index and the value of each item in the list prints: 0 dog 1 cat 2 mouse """
animals = ["dog", "cat", "mouse"]
for i, value in enumerate(animals):
print(i, value)
複製代碼
while循環和C++相似,當條件爲True時執行,爲false時退出。而且判斷條件不須要加上括號:
""" While loops go until a condition is no longer met. prints: 0 1 2 3 """
x = 0
while x < 4:
print(x)
x += 1 # Shorthand for x = x + 1
複製代碼
Python當中使用try和except捕獲異常,咱們能夠在except後面限制異常的類型。若是有多個類型能夠寫多個except,還可使用else語句表示其餘全部的類型。finally語句內的語法不管是否會觸發異常都一定執行:
# Handle exceptions with a try/except block
try:
# Use "raise" to raise an error
raise IndexError("This is an index error")
except IndexError as e:
pass # Pass is just a no-op. Usually you would do recovery here.
except (TypeError, NameError):
pass # Multiple exceptions can be handled together, if required.
else: # Optional clause to the try/except block. Must follow all except blocks
print("All good!") # Runs only if the code in try raises no exceptions
finally: # Execute under all circumstances
print("We can clean up resources here")
複製代碼
在Python當中咱們常常會使用資源,最多見的就是open打開一個文件。咱們打開了文件句柄就必定要關閉,可是若是咱們手動來編碼,常常會忘記執行close操做。而且若是文件異常,還會觸發異常。這個時候咱們可使用with語句來代替這部分處理,使用with會自動在with塊執行結束或者是觸發異常時關閉打開的資源。
如下是with的幾種用法和功能:
# Instead of try/finally to cleanup resources you can use a with statement
# 代替使用try/finally語句來關閉資源
with open("myfile.txt") as f:
for line in f:
print(line)
# Writing to a file # 使用with寫入文件 contents = {"aa": 12, "bb": 21} with open("myfile1.txt", "w+") as file: file.write(str(contents)) # writes a string to a file with open("myfile2.txt", "w+") as file: file.write(json.dumps(contents)) # writes an object to a file # Reading from a file # 使用with讀取文件 with open('myfile1.txt', "r+") as file: contents = file.read() # reads a string from a file print(contents) # print: {"aa": 12, "bb": 21} with open('myfile2.txt', "r+") as file: contents = json.load(file) # reads a json object from a file print(contents) # print: {"aa": 12, "bb": 21} 複製代碼
凡是可使用in語句來迭代的對象都叫作可迭代對象,它和迭代器不是一個含義。這裏只有可迭代對象的介紹,想要了解迭代器的具體內容,請移步傳送門:
當咱們調用dict當中的keys方法的時候,返回的結果就是一個可迭代對象。
# Python offers a fundamental abstraction called the Iterable.
# An iterable is an object that can be treated as a sequence.
# The object returned by the range function, is an iterable.
filled_dict = {"one": 1, "two": 2, "three": 3} our_iterable = filled_dict.keys() print(our_iterable) # => dict_keys(['one', 'two', 'three']). This is an object that implements our Iterable interface. # We can loop over it. for i in our_iterable: print(i) # Prints one, two, three 複製代碼
咱們不能使用下標來訪問可迭代對象,但咱們能夠用iter將它轉化成迭代器,使用next關鍵字來獲取下一個元素。也能夠將它轉化成list類型,變成一個list。
# However we cannot address elements by index.
our_iterable[1] # Raises a TypeError
# An iterable is an object that knows how to create an iterator. our_iterator = iter(our_iterable) # Our iterator is an object that can remember the state as we traverse through it. # We get the next object with "next()". next(our_iterator) # => "one" # It maintains state as we iterate. next(our_iterator) # => "two" next(our_iterator) # => "three" # After the iterator has returned all of its data, it raises a StopIteration exception next(our_iterator) # Raises StopIteration # We can also loop over it, in fact, "for" does this implicitly! our_iterator = iter(our_iterable) for i in our_iterator: print(i) # Prints one, two, three # You can grab all the elements of an iterable or iterator by calling list() on it. list(our_iterable) # => Returns ["one", "two", "three"] list(our_iterator) # => Returns [] because state is saved 複製代碼
使用def關鍵字來定義函數,咱們在傳參的時候若是指定函數內的參數名,能夠不按照函數定義的順序傳參:
# Use "def" to create new functions
def add(x, y):
print("x is {} and y is {}".format(x, y))
return x + y # Return values with a return statement
# Calling functions with parameters add(5, 6) # => prints out "x is 5 and y is 6" and returns 11 # Another way to call functions is with keyword arguments add(y=6, x=5) # Keyword arguments can arrive in any order. 複製代碼
能夠在參數名以前加上*表示任意長度的參數,參數會被轉化成list:
# You can define functions that take a variable number of
# positional arguments
def varargs(*args):
return args
varargs(1, 2, 3) # => (1, 2, 3) 複製代碼
也能夠指定任意長度的關鍵字參數,在參數前加上**表示接受一個dict:
# You can define functions that take a variable number of
# keyword arguments, as well
def keyword_args(**kwargs):
return kwargs
# Let's call it to see what happens keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"} 複製代碼
固然咱們也能夠兩個都用上,這樣能夠接受任何參數:
# You can do both at once, if you like
def all_the_args(*args, **kwargs):
print(args)
print(kwargs)
""" all_the_args(1, 2, a=3, b=4) prints: (1, 2) {"a": 3, "b": 4} """
複製代碼
傳入參數的時候咱們也可使用*和**來解壓list或者是dict:
# When calling functions, you can do the opposite of args/kwargs!
# Use * to expand tuples and use ** to expand kwargs.
args = (1, 2, 3, 4)
kwargs = {"a": 3, "b": 4}
all_the_args(*args) # equivalent to all_the_args(1, 2, 3, 4)
all_the_args(**kwargs) # equivalent to all_the_args(a=3, b=4)
all_the_args(*args, **kwargs) # equivalent to all_the_args(1, 2, 3, 4, a=3, b=4)
複製代碼
Python中的參數能夠返回多個值:
# Returning multiple values (with tuple assignments)
def swap(x, y):
return y, x # Return multiple values as a tuple without the parenthesis.
# (Note: parenthesis have been excluded but can be included)
x = 1 y = 2 x, y = swap(x, y) # => x = 2, y = 1 # (x, y) = swap(x,y) # Again parenthesis have been excluded but can be included. 複製代碼
函數內部定義的變量即便和全局變量重名,也不會覆蓋全局變量的值。想要在函數內部使用全局變量,須要加上global關鍵字,表示這是一個全局變量:
# Function Scope
x = 5
def set_x(num): # Local var x not the same as global variable x x = num # => 43 print(x) # => 43 def set_global_x(num): global x print(x) # => 5 x = num # global var x is now set to 6 print(x) # => 6 set_x(43) set_global_x(6) 複製代碼
Python支持函數式編程,咱們能夠在一個函數內部返回一個函數:
# Python has first class functions
def create_adder(x):
def adder(y):
return x + y
return adder
add_10 = create_adder(10) add_10(3) # => 13 複製代碼
Python中可使用lambda表示匿名函數,使用:做爲分隔,:前面表示匿名函數的參數,:後面的是函數的返回值:
# There are also anonymous functions
(lambda x: x > 2)(3) # => True
(lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5
複製代碼
咱們還能夠將函數做爲參數使用map和filter,實現元素的批量處理和過濾。關於Python中map、reduce和filter的使用,具體能夠查看以前的文章:
# There are built-in higher order functions
list(map(add_10, [1, 2, 3])) # => [11, 12, 13]
list(map(max, [1, 2, 3], [4, 2, 1])) # => [4, 2, 3]
list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7] 複製代碼
咱們還能夠結合循環和判斷語來給list或者是dict進行初始化:
# We can use list comprehensions for nice maps and filters
# List comprehension stores the output as a list which can itself be a nested list
[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
[x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7]
# You can construct set and dict comprehensions as well. {x for x in 'abcddeef' if x not in 'abc'} # => {'d', 'e', 'f'} {x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} 複製代碼
使用import語句引入一個Python模塊,咱們能夠用.來訪問模塊中的函數或者是類。
# You can import modules
import math
print(math.sqrt(16)) # => 4.0
複製代碼
咱們也可使用from import的語句,單獨引入模塊內的函數或者是類,而再也不須要寫出完整路徑。使用from import *能夠引入模塊內全部內容(不推薦這麼幹)
# You can get specific functions from a module
from math import ceil, floor
print(ceil(3.7)) # => 4.0
print(floor(3.7)) # => 3.0
# You can import all functions from a module. # Warning: this is not recommended from math import * 複製代碼
可使用as給模塊內的方法或者類起別名:
# You can shorten module names
import math as m
math.sqrt(16) == m.sqrt(16) # => True
複製代碼
咱們可使用dir查看咱們用的模塊的路徑:
# You can find out which functions and attributes
# are defined in a module.
import math
dir(math)
複製代碼
這麼作的緣由是若是咱們當前的路徑下也有一個叫作math的Python文件,那麼會覆蓋系統自帶的math的模塊。這是尤爲須要注意的,不當心會致使不少奇怪的bug。
咱們來看一個完整的類,相關的介紹都在註釋當中
# We use the "class" statement to create a class
class Human:
# A class attribute. It is shared by all instances of this class # 類屬性,能夠直接經過Human.species調用,而不須要經過實例 species = "H. sapiens" # Basic initializer, this is called when this class is instantiated. # Note that the double leading and trailing underscores denote objects # or attributes that are used by Python but that live in user-controlled # namespaces. Methods(or objects or attributes) like: __init__, __str__, # __repr__ etc. are called special methods (or sometimes called dunder methods) # You should not invent such names on your own. # 最基礎的構造函數 # 加了下劃線的函數和變量表示不該該被用戶使用,其中雙下劃線的函數或者是變量將不會被子類覆蓋 # 先後都有雙下劃線的函數和屬性是類當中的特殊屬性 def __init__(self, name): # Assign the argument to the instance's name attribute self.name = name # Initialize property self._age = 0 # An instance method. All methods take "self" as the first argument # 類中的函數,全部實例能夠調用,第一個參數必須是self # self表示實例的引用 def say(self, msg): print("{name}: {message}".format(name=self.name, message=msg)) # Another instance method def sing(self): return 'yo... yo... microphone check... one two... one two...' # A class method is shared among all instances # They are called with the calling class as the first argument @classmethod # 加上了註解,表示是類函數 # 經過Human.get_species來調用,全部實例共享 def get_species(cls): return cls.species # A static method is called without a class or instance reference @staticmethod # 靜態函數,經過類名或者是實例均可以調用 def grunt(): return "*grunt*" # A property is just like a getter. # It turns the method age() into an read-only attribute of the same name. # There's no need to write trivial getters and setters in Python, though. @property # property註解,相似於get,set方法 # 效率很低,除非必要,不要使用 def age(self): return self._age # This allows the property to be set @age.setter def age(self, age): self._age = age # This allows the property to be deleted @age.deleter def age(self): del self._age 複製代碼
以上內容的詳細介紹以前也有過相關文章,能夠查看:
下面咱們來看看Python當中類的使用:
# When a Python interpreter reads a source file it executes all its code.
# This __name__ check makes sure this code block is only executed when this
# module is the main program.
# 這個是main函數也是整個程序入口的慣用寫法
if __name__ == '__main__':
# Instantiate a class
# 實例化一個類,獲取類的對象
i = Human(name="Ian")
# 執行say方法
i.say("hi") # "Ian: hi"
j = Human("Joel")
j.say("hello") # "Joel: hello"
# i和j都是Human的實例,都稱做是Human類的對象
# i and j are instances of type Human, or in other words: they are Human objects
# Call our class method # 類屬性被全部實例共享,一旦修改所有生效 i.say(i.get_species()) # "Ian: H. sapiens" # Change the shared attribute Human.species = "H. neanderthalensis" i.say(i.get_species()) # => "Ian: H. neanderthalensis" j.say(j.get_species()) # => "Joel: H. neanderthalensis" # 經過類名調用靜態方法 # Call the static method print(Human.grunt()) # => "*grunt*" # Cannot call static method with instance of object # because i.grunt() will automatically put "self" (the object i) as an argument # 不能經過對象調用靜態方法,由於對象會傳入self實例,會致使不匹配 print(i.grunt()) # => TypeError: grunt() takes 0 positional arguments but 1 was given # Update the property for this instance # 實例級別的屬性是獨立的,各個對象各自擁有,修改不會影響其餘對象內的值 i.age = 42 # Get the property i.say(i.age) # => "Ian: 42" j.say(j.age) # => "Joel: 0" # Delete the property del i.age # i.age # => this would raise an AttributeError 複製代碼
這裏解釋一下,實例和對象能夠理解成一個概念,實例的英文是instance,對象的英文是object。都是指類通過實例化以後獲得的對象。
繼承可讓子類繼承父類的變量以及方法,而且咱們還能夠在子類當中指定一些屬於本身的特性,而且還能夠重寫父類的一些方法。通常咱們會將不一樣的類放在不一樣的文件當中,使用import引入,同樣能夠實現繼承。
from human import Human
# Specify the parent class(es) as parameters to the class definition class Superhero(Human): # If the child class should inherit all of the parent's definitions without # any modifications, you can just use the "pass" keyword (and nothing else) # but in this case it is commented out to allow for a unique child class: # pass # 若是要徹底繼承父類的全部的實現,咱們可使用關鍵字pass,表示跳過。這樣不會修改父類當中的實現 # Child classes can override their parents' attributes species = 'Superhuman' # Children automatically inherit their parent class's constructor including # its arguments, but can also define additional arguments or definitions # and override its methods such as the class constructor. # This constructor inherits the "name" argument from the "Human" class and # adds the "superpower" and "movie" arguments: # 子類會徹底繼承父類的構造方法,咱們也能夠進行改造,好比額外增長一些參數 def __init__(self, name, movie=False, superpowers=["super strength", "bulletproofing"]): # add additional class attributes: # 額外新增的參數 self.fictional = True self.movie = movie # be aware of mutable default values, since defaults are shared self.superpowers = superpowers # The "super" function lets you access the parent class's methods # that are overridden by the child, in this case, the __init__ method. # This calls the parent class constructor: # 子類能夠經過super關鍵字調用父類的方法 super().__init__(name) # override the sing method # 重寫父類的sing方法 def sing(self): return 'Dun, dun, DUN!' # add an additional instance method # 新增方法,只屬於子類 def boast(self): for power in self.superpowers: print("I wield the power of {pow}!".format(pow=power)) 複製代碼
if __name__ == '__main__':
sup = Superhero(name="Tick")
# Instance type checks # 檢查繼承關係 if isinstance(sup, Human): print('I am human') # 檢查類型 if type(sup) is Superhero: print('I am a superhero') # Get the Method Resolution search Order used by both getattr() and super() # This attribute is dynamic and can be updated # 查看方法查詢的順序 # 先是自身,而後沿着繼承順序往上,最後到object print(Superhero.__mro__) # => (<class '__main__.Superhero'>, # => <class 'human.Human'>, <class 'object'>) # 相同的屬性子類覆蓋了父類 # Calls parent method but uses its own class attribute print(sup.get_species()) # => Superhuman # Calls overridden method # 相同的方法也覆蓋了父類 print(sup.sing()) # => Dun, dun, DUN! # Calls method from Human # 繼承了父類的方法 sup.say('Spoon') # => Tick: Spoon # Call method that exists only in Superhero # 子類特有的方法 sup.boast() # => I wield the power of super strength! # => I wield the power of bulletproofing! # Inherited class attribute sup.age = 31 print(sup.age) # => 31 # Attribute that only exists within Superhero print('Am I Oscar eligible? ' + str(sup.movie)) 複製代碼
咱們建立一個蝙蝠類:
# Another class definition
# bat.py
class Bat:
species = 'Baty' def __init__(self, can_fly=True): self.fly = can_fly # This class also has a say method def say(self, msg): msg = '... ... ...' return msg # And its own method as well # 蝙蝠獨有的聲吶方法 def sonar(self): return '))) ... (((' if __name__ == '__main__': b = Bat() print(b.say('hello')) print(b.fly) 複製代碼
咱們再建立一個蝙蝠俠的類,同時繼承Superhero和Bat:
# And yet another class definition that inherits from Superhero and Bat
# superhero.py
from superhero import Superhero
from bat import Bat
# Define Batman as a child that inherits from both Superhero and Bat class Batman(Superhero, Bat): def __init__(self, *args, **kwargs): # Typically to inherit attributes you have to call super: # super(Batman, self).__init__(*args, **kwargs) # However we are dealing with multiple inheritance here, and super() # only works with the next base class in the MRO list. # So instead we explicitly call __init__ for all ancestors. # The use of *args and **kwargs allows for a clean way to pass arguments, # with each parent "peeling a layer of the onion". # 經過類名調用兩個父類各自的構造方法 Superhero.__init__(self, 'anonymous', movie=True, superpowers=['Wealthy'], *args, **kwargs) Bat.__init__(self, *args, can_fly=False, **kwargs) # override the value for the name attribute self.name = 'Sad Affleck' # 重寫父類的sing方法 def sing(self): return 'nan nan nan nan nan batman!' 複製代碼
執行這個類:
if __name__ == '__main__':
sup = Batman()
# Get the Method Resolution search Order used by both getattr() and super(). # This attribute is dynamic and can be updated # 能夠看到方法查詢的順序是先沿着superhero這條線到human,而後纔是bat print(Batman.__mro__) # => (<class '__main__.Batman'>, # => <class 'superhero.Superhero'>, # => <class 'human.Human'>, # => <class 'bat.Bat'>, <class 'object'>) # Calls parent method but uses its own class attribute # 只有superhero有get_species方法 print(sup.get_species()) # => Superhuman # Calls overridden method print(sup.sing()) # => nan nan nan nan nan batman! # Calls method from Human, because inheritance order matters sup.say('I agree') # => Sad Affleck: I agree # Call method that exists only in 2nd ancestor # 調用蝙蝠類的聲吶方法 print(sup.sonar()) # => ))) ... ((( # Inherited class attribute sup.age = 100 print(sup.age) # => 100 # Inherited attribute from 2nd ancestor whose default value was overridden. print('Can I fly? ' + str(sup.fly)) # => Can I fly? False 複製代碼
咱們能夠經過yield關鍵字建立一個生成器,每次咱們調用的時候執行到yield關鍵字處則中止。下次再次調用則仍是從yield處開始往下執行:
# Generators help you make lazy code.
def double_numbers(iterable):
for i in iterable:
yield i + i
# Generators are memory-efficient because they only load the data needed to # process the next value in the iterable. This allows them to perform # operations on otherwise prohibitively large value ranges. # NOTE: `range` replaces `xrange` in Python 3. for i in double_numbers(range(1, 900000000)): # `range` is a generator. print(i) if i >= 30: break 複製代碼
除了yield以外,咱們還可使用()小括號來生成一個生成器:
# Just as you can create a list comprehension, you can create generator
# comprehensions as well.
values = (-x for x in [1,2,3,4,5])
for x in values:
print(x) # prints -1 -2 -3 -4 -5 to console/terminal
# You can also cast a generator comprehension directly to a list. values = (-x for x in [1,2,3,4,5]) gen_to_list = list(values) print(gen_to_list) # => [-1, -2, -3, -4, -5] 複製代碼
關於生成器和迭代器更多的內容,能夠查看下面這篇文章:
咱們引入functools當中的wraps以後,能夠建立一個裝飾器。裝飾器能夠在不修改函數內部代碼的前提下,在外面包裝一層其餘的邏輯:
# Decorators
# In this example `beg` wraps `say`. If say_please is True then it
# will change the returned message.
from functools import wraps
def beg(target_function): @wraps(target_function) # 若是please爲True,額外輸出一句Please! I am poor :( def wrapper(*args, **kwargs): msg, say_please = target_function(*args, **kwargs) if say_please: return "{} {}".format(msg, "Please! I am poor :(") return msg return wrapper @beg def say(say_please=False): msg = "Can you buy me a beer?" return msg, say_please print(say()) # Can you buy me a beer? print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :( 複製代碼
裝飾器以前也有專門的文章詳細介紹,能夠移步下面的傳送門:
不知道有多少小夥伴能夠看到結束,原做者的確很是厲害,把Python的基本操做基本上都囊括在裏面了。若是都能讀懂而且理解的話,那麼Python這門語言就算是入門了。
原做者寫的是一個Python文件,全部的內容都在Python的註釋當中。我在它的基礎上作了修補和額外的描述。若是想要得到原文,能夠點擊查看原文,或者是在公衆號內回覆learnpython獲取。
若是你以前就有其餘語言的語言基礎,我想本文讀完應該不用30分鐘。固然在30分鐘內學會一門語言是不可能的,也不是我所提倡的。但至少經過本文咱們能夠作到熟悉Python的語法,知道大概有哪些操做,剩下的就要咱們親自去寫代碼的時候去體會和運用了。
根據個人經驗,在學習一門新語言的前期,不停地查閱資料是免不了的。但願本文能夠做爲你在使用Python時候的查閱文檔。
今天的文章就到這裏,原創不易,須要你的一個關注,你的舉手之勞對我來講很重要。