最近有许多小伙伴后台联系我,说目前想要学习Python,但是没有一份很好的资料入门。一方面的确现在市面上Python的资料过多,导致新手会不知如何选择,另一个问题很多资料内容也很杂,从1+1到深度学习都包括,纯粹关注Python本身语法的优质教材并不太多。
注释
Python中用#表示单行注释,#之后的同行的内容都会被注释掉。
# Python中单行注释用#表示,#之后同行字符全部认为被注释。
使用三个连续的双引号表示多行注释,两个多行注释标识之间内容会被视作是注释。
"""?与之对应的是多行注释
用三个双引号表示,这两段双引号当中的内容都会被视作是注释
"""
基础变量类型与操作符
Python当中的数字定义和其他语言一样:
#获得一个整数
3
#?获得一个浮点数
10.0
我们分别使用+, -, *, /表示加减乘除四则运算符。
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已经不再维护了,可以不用关心其中的细节。
但问题是Python是一个弱类型的语言,如果我们在一个函数当中得到两个变量,是无法直接判断它们的类型的。这就导致了同样的计算符可能会得到不同的结果,这非常蛋疼。以至于程序员在运算除法的时候,往往都需要手工加上类型转化符,将被除数转成浮点数。
在Python3当中拨乱反正,修正了这个问题,即使是两个整数相除,并且可以整除的情况下,得到的结果也一定是浮点数。
如果我们想要得到整数,我们可以这么操作:
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
==?False??#?=>?True
1?==?True???#?=>?True
2?==?True???#?=>?False
-5?!=?False?#?=>?True
我们要小心Python当中的bool()这个函数,它并不是转成bool类型的意思。如果我们执行这个函数,那么只有0会被视作是False,其他所有数值都是True:
bool()?????#?=>?False
bool(4)?????#?=>?True
bool(-6)????#?=>?True
and?2?????#?=>?0
-5?or??????#?=>?-5
Python中用==判断相等,>表示大于,>=表示大于等于,
#?Equality?is?==
1?==?1??#?=>?True
2?==?1??#?=>?False
#?Inequality?is?!=
1?!=?1??#?=>?False
2?!=?1??#?=>?True
#?More?comparisons
1??True
1?>?10??#?=>?False
2??True
2?>=?2??#?=>?True
我们可以用and和or拼装各个比较操作:
#?Seeing?whether?a?value?is?in?a?range
1?
2?
#?Chaining?makes?this?look?nicer
1?
2?
注意not,and,or之间的优先级,其中not > and > or。如果分不清楚的话,可以用括号强行改变运行顺序。
list和字符串
关于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"[]??#?=>?'T'
#?You?can?find?the?length?of?a?string
len("This?is?a?string")??#?=>?16
我们可以在字符串前面加上f表示格式操作,并且在格式操作当中也支持运算。不过要注意,只有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?."?#?=>?"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"?is??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()???#?=>?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
list
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[]???#?=>?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]。
只写一个:,表示全部获取,可以使用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
tuple和list非常接近,tuple通过()初始化。和list不同,tuple是不可变对象。也就是说tuple一旦生成不可以改变。如果我们修改tuple,会引发TypeError异常。
#?Tuples?are?like?lists?but?are?immutable.
tup?=?(1,?2,?3)
tup[]??????#?=>?1
tup[]?=?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))???#?=>?
type((1,))??#?=>?
type(())????#?=>?
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()?#?这是合法的
dict
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和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?
#?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?
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?
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是用来存储不重复元素的容器,当中的元素都是不同的,相同的元素会被删除。我们可以通过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
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
#?Sets?do?not?have?duplicate?elements
filled_set.add(5)??#?it?remains?as?before
set还可以被认为是集合,所以它还支持一些集合交叉并补的操作。
#?Do?set?intersection?with?&
#?计算交集
other_set?=?{3,?4,?5,?6}
filled_set?&?other_set??#?=>
#?Do?set?union?with?|
#?计算并集
filled_set?|?other_set??#?=>
#?Do?set?difference?with?-
#?计算差集
{1,?2,?3,?4}?-?{2,?3,?5}??#?=>
#?Do?set?symmetric?difference?with?^
#?这个有点特殊,计算对称集,也就是去掉重复元素剩下的内容
{1,?2,?3,?4}?^?{2,?3,?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}??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
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?
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?=
while?x?
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")
with操作
在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.
#?=>?{'d',?'e',?'f'}
#?=>
模块
使用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?=
#?An?instance?method.?All?methods?take?"self"?as?the?first?argument
#?类中的函数,所有实例可以调用,第一个参数必须是self
#?self表示实例的引用
def?say(self,?msg):
print(":?".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
领取专属 10元无门槛券
私享最新 技术干货