編寫高質(zhì)量代碼閱讀筆記

不可變對象

Python中一切皆對象,每一個對象都有一個唯一的標(biāo)示符(id())测秸、類型(type())以及值疤估。對象根據(jù)其值能否修改分為可變對象和不可變對象灾常,其中數(shù)字、字符串铃拇、元組屬于不可變對象钞瀑,字典以及列表、字節(jié)數(shù)組屬于可變對象

字符串屬于不可變對象慷荔,任何對字符串的直接修改都會報錯

那怎么修改呢雕什?通過 array 來進(jìn)行

'''
修改字符串,引入array模塊
'''
a = "nihao"

import array

b = array.array('c', a) # 注意第一個參數(shù)必須是 'c'
# 然后將b按照字符串來修改
b[3] = 'a'
b.tostring() # 即可轉(zhuǎn)換位字符串

==經(jīng)常遇到的錯誤==

class Student(object):
    def __init__(self,name,course=[]):  # 這里傳參有問題O跃А贷岸!
        self.name=name
        self.course=course
    def addcourse(self,coursename):
        self.course.append(coursename)
    def printcourse(self):
        for item in self.course:
            print item
stuA=Student("Wang yi")
stuA.addcourse("English")
stuA.addcourse("Math")
print stuA.name +"'s course:"
stuA.printcourse()
print "-----------------------"
stuB=Student("Li san")
stuB.addcourse("Chinese")
stuB.addcourse("Physics")
print stuB.name +"'s course:"
stuB.printcourse()

運(yùn)行結(jié)果

Wang yi's course:
English
Math
-----------------------
Li san's course:
English
Math
Chinese
Physics

這是由于 init 函數(shù)第二個參數(shù)是默認(rèn)參數(shù),m默認(rèn)參數(shù)在被調(diào)用的時候只初始化一次磷雇。所以兩個對象的 course 是同一個值

列表推導(dǎo)式

比如實(shí)現(xiàn)如下代碼:

words = ['  Are', '  abandon', 'Passion','Business',' fruit  ','quit']
size = len(words)
newlist = []
for i in range(size):
    if words[i].strip().istitle():
        newlist.append(words[i])

print newlist

功能比較簡單偿警,就是遍歷 words 中的每一個元素,然后判斷首字母是不是大寫

如果用列表推導(dǎo)式:

words = ['  Are', '  abandon', 'Passion','Business',' fruit  ','quit']
newlist = [ i for i in words if i.strip().istitle()]

很快就能完成

多重嵌套

>>> nested_list = [['Hello', 'World'], ['Goodbye', 'World']]
>>> nested_list = [[s.upper() for s in xs] for xs in nested_list]
>>> print nested_list
[['HELLO', 'WORLD'], ['GOODBYE', 'WORLD']]
>>>

xs 是一個list唯笙,再對xs中的每一個字符串進(jìn)行操作

多重迭代

>>> [(a,b) for a in ['a','1',1,2] for b in ['1',3,4,'b'] if a != b]
[('a', '1'), ('a', 3), ('a', 4), ('a', 'b'), ('1', 3), ('1', 4), ('1', 'b'), (1,
 '1'), (1, 3), (1, 4), (1, 'b'), (2, '1'), (2, 3), (2, 4), (2, 'b')]
>>>

做笛卡爾積螟蒸, 去掉元素值相等的元組

使用函數(shù)

>>> def f(v):
...     if v%2 == 0:
...         v = v**2
...     else:
...         v = v+1
...     return v
...
>>> [f(v) for v in [2,3,4,-1] if v>0]       #
表達(dá)式可以是函數(shù)
[4, 4, 16]
>>> [v**2 if v%2 ==0 else v+1 for v in [2,3,4,-1] if v>0]#
也可以是普通計算
[4, 4, 16]
>>>

任何可迭代對象都是可以的

fh = open("test.txt", "r")
result = [i for i in fh if "abc" in i]  #文件句柄可以當(dāng)做可迭代對象
print result

函數(shù)傳參

如下例子中,甚至可以直接將一個列表推導(dǎo)式作為參數(shù)傳入其中

>>> def foo(a):
...    for i in a:
...           print i
...
>>> foo([1, 2, 3])
1
2
3
>>> foo(i for i in range(3) if i % 2 == 0)
0
2

字典推導(dǎo)式

互換 key 和 value

person = {'name':'xiaobai','city':'paris'}
person_reverse = {v:k for k,v in person.items()}   #簡單互換key和value的值即可

? 再看一個復(fù)雜點(diǎn)的栗子:統(tǒng)計字母(不分大小寫)出現(xiàn)的次數(shù)

nums = {'a':10,'b':20,'A':5,'B':3,'d':4}

num_frequency  = {k.lower():nums.get(k.lower(),0) + nums.get(k.upper(),0)
                  for k in nums.keys() }  # 注意 get方法中第二個參數(shù)是指定的默認(rèn)值

print(num_frequency)

字典推導(dǎo)式配合枚舉:將list轉(zhuǎn)換位dict

fruit = ['apple','organge','banana','mango','peach']

fruit_positon = {v:i for i,v in enumerate(fruit)}
print(fruit_positon)

Out: {'apple': 0, 'organge': 1, 'banana': 2, 'mango': 3, 'peach': 4}

集合推導(dǎo)式

返回人名

names = [ 'Bob', 'JOHN', 'alice', 'bob', 'ALICE', 'James', 'Bob','JAMES','jAMeS' ]
names_standard = { n[0].upper()+n[1:].lower() for n in names}

print(names_standard)
Out: {'John', 'Bob', 'James', 'Alice'}

綜合運(yùn)用:統(tǒng)計一個文本中的單詞長度大于5并且倒過來也有意義

with open('dictionary.txt') as dictionary_file:
    words = (line.rstrip() for line in dictionary_file)
    words_over_five_letters = [w for w in words if len(w)>5 ]


reversed_words ={
    word[::-1]
    for word in words_over_five_letters
     }

reversible_words = [
    word
    for word in words_over_five_letters
    if word in reversed_words
]

for word in reversible_words[0:20]:
    print(word)

函數(shù)是如何傳參的

先下結(jié)論:函數(shù)的傳參既不是傳值也不是傳引用睁本,更不是有時候傳值有時候傳引用

def change_me(org_list):
    print id(org_list)
    new_list = org_list
    print id(new_list)
    if len(new_list)>5:
        new_list = ['a','b','c']
    for i,e in enumerate(new_list):
        if isinstance(e,list):
                new_list[i]="***"   #將元素為list類型的替換為***


    print new_list
    print id(new_list)

test1 = [1,['a',1,3],[2,1],6]
change_me(test1)
print(test1)
test2=[1,2,3,4,5,6,[1]]
change_me(test2)
print(test2)

運(yùn)行結(jié)果:

64172232
64172232
[1, '***', '***', 6]
64172232
[1, '***', '***', 6]
64121928
64121928
['a', 'b', 'c']
64018440
[1, 2, 3, 4, 5, 6, [1]]

第一個測試可以說是傳引用尿庐,但是第二個測試卻變成了傳值

epub_621966_21.jpg

當(dāng)org_list的長度大于5的時候,new_list =['a','b','c']操作重新創(chuàng)建了一塊內(nèi)存并將new_list指向它呢堰。當(dāng)傳入?yún)?shù)為test2=[1,2,3,4,5,6,[1]]的時候抄瑟,函數(shù)的執(zhí)行并沒有改變該列表的值

因此,對于Python函數(shù)參數(shù)是傳值還是傳引用這個問題的答案是:都不是枉疼。正確的叫法應(yīng)該是傳對象(call by object)或者說傳對象的引用(call-by-object-reference)皮假。函數(shù)參數(shù)在傳遞的過程中將整個對象傳入,對可變對象的修改在函數(shù)外部以及內(nèi)部都可見骂维,調(diào)用者和被調(diào)用者之間共享這個對象惹资,而對于不可變對象,由于并不能真正被修改航闺,因此褪测,修改往往是通過生成一個新對象然后賦值來實(shí)現(xiàn)的。

默認(rèn)參數(shù)

默認(rèn)參數(shù)可能帶來的問題已經(jīng)在 不可變對象 闡述過了

>>> def appendtest(newitem,lista = []):              #默認(rèn)參數(shù)為空列表
...    print id(lista)
...    lista.append(newitem)
...    print id(lista)
...    return lista
...
>>>
>>> appendtest('a',['b',2,4,[1,2]])
39644216
39644216
['b', 2, 4, [1, 2], 'a']
>>>

def在Python中是一個可執(zhí)行的語句潦刃,當(dāng)解釋器執(zhí)行def的時候侮措,默認(rèn)參數(shù)也會被計算,并存在函數(shù)的.func_defaults屬性中乖杠。由于Python中函數(shù)參數(shù)傳遞的是對象分扎,可變對象在調(diào)用者和被調(diào)用者之間共享,因此當(dāng)首次調(diào)用appendtest(1)的時候胧洒,[]變?yōu)閇1]畏吓,而再次調(diào)用的時候由于默認(rèn)參數(shù)不會重新計算墨状,在[1]的基礎(chǔ)上便變?yōu)榱薣1,'a']。我們可以通過查看函數(shù)的func_defaults來確認(rèn)這一點(diǎn)菲饼。

變長參數(shù)

*args**kwargs 代表了變長參數(shù)

一個簡單地示例:

def SumFun(*args):
    result = 0
    for x in args[0:]:
        result += x
    return result
print SumFun(2,4)
print SumFun(1,2,3,4,5)
print SumFun()

變長參數(shù)帶來的問題:

def set_axis(x,y, xlabel="x", ylabel="y", *args, **kwargs):
    pass

以下調(diào)用方式都是對的:

set_axis(2,3, "test1", "test2","test3", my_kwarg="test3")
①
set_axis(2,3, my_kwarg="test3")
set_axis(2,3, "test1",my_kwarg="test3")
②
set_axis("test1", "test2", xlabel="new_x",ylabel = "new_y", my_kwarg="test3")
set_axis(2,"test1", "test2",ylabel = "new_y", my_kwarg="test3")

靜態(tài)方法和類方法

類方法實(shí)例:統(tǒng)計實(shí)例化了多少個對象

思路:每次實(shí)例對象的時候必然會調(diào)用 __init__ 方法肾砂,

class Kls(object):
    num_inst = 0

    def __init__(self):
        Kls.num_inst = Kls.num_inst + 1 # 每實(shí)例化一個對象變量的值就會+1

    @classmethod
    def get_no_of_instance(cls):
        return cls.num_inst


ik1 = Kls()
ik2 = Kls()

print ik1.get_no_of_instance() # 輸出2
print Kls.get_no_of_instance() # 輸出2

書上提到的一個類方法栗子:

class Fruit(object):
    total = 0
    @classmethod
    def print_total(cls):
        print cls.total
        #print id(Fruit.total)
        #print id(cls.total)
    @classmethod
    def set(cls, value):
        #print "calling class_method(%s,%s)"%(cls,value)
        cls.total = value
class Apple(Fruit):
    pass
class Orange(Fruit):
    Pass
app1 = Apple()
app1.set(200)
app2 = Apple()
org1 = Orange()
org1.set(300)
org2 = Orange()
app1.print_total()  #output 200
org1.print_total()  #output 300

但是上面例子中的類方法修改為實(shí)例方法也是可以的,并沒有多大的影響

同時我們可以看下面這個三種方法得對比:

class A(object):
    def instance_method(self,x):
        print "calling instance method instance_method(%s,%s)"%(self,x)
    @classmethod
    def class_method(cls,x):
        print "calling class_method(%s,%s)"%(cls,x)
    @staticmethod
    def static_method(x):
        print "calling static_method(%s)"%x
a = A()
a.instance_method("test")
#輸出calling instance method instance_method(<__main__.A object at 0x00D66B50>,test)
a.class_method("test")
#輸出calling class_method(<class '__main__.A'>,test)
a.static_method("test")
#輸出calling static_method(test)

調(diào)用實(shí)例方法的時候:

[圖片上傳失敗...(image-790e53-1582298210229)]

調(diào)用類方法的時候

[圖片上傳失敗...(image-f2734b-1582298210229)]

淺拷貝和深拷貝

這一段代碼巴粪,模擬了一個客戶到披薩點(diǎn)點(diǎn)餐

import copy
# 披薩店
class Pizza(object):
       def __init__(self,name,size,price):
                 self.name=name
                 self.size=size
                 self.price=price
       def getPizzaInfo(self):
            #①獲取Pizza相關(guān)信息
            return self.name,self.size,self.price
       def showPizzaInfo(self):
            #②顯示Pizza信息
            print "Pizza name:"+self.name
            print "Pizza size:"+str(self.size)
            print "Pizza price:"+str(self.price)
       def changeSize(self,size):
            self.size=size
       def changePrice(self,price):
            self.price=price

# 具體的訂單
class Order(object):
        #③訂單類
    def __init__(self,name):
        self.customername=name
        self.pizzaList=[]
        self.pizzaList.append(Pizza("Mushroom",12,30))
    def ordermore(self,pizza):
        self.pizzaList.append(pizza)
    def changeName(self,name):
        self.customername=name
    def getorderdetail(self):
        print "customer name:"+self.customername
        for i in self.pizzaList:
            i.showPizzaInfo()
    def getPizza(self,number):
            return self.pizzaList[number]

customer1=Order("zhang") # 新客戶 zhang
customer1.ordermore(Pizza("seafood",9,40))
customer1.ordermore(Pizza("fruit",12,35))
print "customer1 order infomation:"
customer1.getorderdetail()
print "-------------------------------"

此時又來了一個顧客通今,訂單和客戶1一樣,只是要將預(yù)定的水果披薩的尺寸和價格進(jìn)行相應(yīng)的修改肛根,于是為了方便直接拷貝了客戶1的訂單

customer2=copy.copy(customer1)  # 注意此處是淺拷貝
print "order 2 customer name:"+customer2.customername
customer2.changeName("li")
customer2.getPizza(2).changeSize(9)
customer2.getPizza(2).changePrice(30)
print "customer2 order infomation:"
customer2.getorderdetail()
print "-------------------------------------"

客戶2的訂單完成了,但是你會發(fā)現(xiàn)客戶1的訂單也被改變了

[圖片上傳失敗...(image-ac75be-1582298210229)]

淺拷貝并沒有復(fù)制 pizza 漏策,導(dǎo)致兩份訂單中的 pizza 指向同一塊內(nèi)存地址

換成 copy.deepcopy 就沒問題了

python字符串

多行字符串技巧

>>> a = ('aaaa'
... 'bbbbb'
... 'ccccc'
... 'ddddd'
... 'eeeee')  # 遇到未閉合的小括號會將所有的字符串連在一起
>>> a
'aaaabbbbbcccccdddddeeeee'

性質(zhì)判定

isalnum()派哲、isalpha()、isdigit()掺喻、islower()芭届、isupper()、isspace()感耙、istitle()褂乍、startswith(prefix[,start[, end]])、endswith(suffix[,start[, end]])

查找和替換

count( sub[, start[, end]])即硼、find( sub[, start[,end]])逃片、index( sub[, start[, end]])、rfind( sub[, start[,end]])只酥、rindex(sub[, start[, end]])

注意find()和index()方法的不同:find()函數(shù)族找不到時返回-1褥实,index()函數(shù)族則拋出ValueError異常。

但是對于判定是否包含字串的判定推薦用 innot in操作符

replace(old, new[,count])用以替換字符串的某些子串裂允,如果指定count參數(shù)的話损离,就最多替換count次,如果不指定绝编,就全部替換

分切與連接

partition()split

split 舉例:

>>> ' hello     world'.split()
['hello', 'world']
>>> ' hello     world'.split(' ')  # 要注意第一種方式和第二種方式不一樣
['', 'hello', '', '', '', '', 'world']
>>> ' hello     world'.split('')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: empty separator
    

>>> ''.split()
[]
>>> ''.split(' ')
['']

變形

lower()僻澎、upper()、capitalize()十饥、swapcase()窟勃、title()

刪減與填充

strip([chars])、lstrip([chars])绷跑、rstrip([chars])

center(width[, fillchar])拳恋、ljust(width[,fillchar])、rjust(width[, fillchar])砸捏、zfill(width)谬运、expandtabs([tabsize])

這些方法中的fillchar參數(shù)是指用以填充的字符隙赁,默認(rèn)是空格。而zfill()中的z是指zero梆暖,所以顧名思義伞访,zfill()即是以字符0進(jìn)行填充,在輸出數(shù)值時比較常用轰驳。expandtabs()的tabsize參數(shù)默認(rèn)為8厚掷,它的功能是把字符串中的制表符(tab)轉(zhuǎn)換為適當(dāng)數(shù)量的空格。

異常處理

基本語法:

try:
<語句>        #運(yùn)行別的代碼
except <名字>:
<語句>        #如果在try部份引發(fā)了'name'異常
except <名字>级解,<數(shù)據(jù)>:
<語句>        #如果引發(fā)了'name'異常冒黑,獲得附加的數(shù)據(jù)
else:
<語句>        #如果沒有異常發(fā)生

如果 try 中發(fā)生了異常,那么根據(jù)發(fā)生的異常進(jìn)入到 except 語句塊中

之后如果沒有異常發(fā)生勤哗,那么 try 完成之后進(jìn)入 else 語句塊

[圖片上傳失敗...(image-8318d9-1582298210229)]

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末抡爹,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子芒划,更是在濱河造成了極大的恐慌冬竟,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件民逼,死亡現(xiàn)場離奇詭異泵殴,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)拼苍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進(jìn)店門笑诅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人映屋,你說我怎么就攤上這事苟鸯。” “怎么了棚点?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵早处,是天一觀的道長。 經(jīng)常有香客問我瘫析,道長砌梆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任贬循,我火速辦了婚禮咸包,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘杖虾。我一直安慰自己烂瘫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坟比,像睡著了一般芦鳍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上葛账,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天柠衅,我揣著相機(jī)與錄音,去河邊找鬼籍琳。 笑死菲宴,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的趋急。 我是一名探鬼主播喝峦,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼宣谈!你這毒婦竟也來了愈犹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤闻丑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后勋颖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嗦嗡,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年饭玲,在試婚紗的時候發(fā)現(xiàn)自己被綠了侥祭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡茄厘,死狀恐怖矮冬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情次哈,我是刑警寧澤胎署,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站窑滞,受9級特大地震影響琼牧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜哀卫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一巨坊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧此改,春花似錦趾撵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽暂题。三九已至,卻和暖如春妈候,著一層夾襖步出監(jiān)牢的瞬間敢靡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工苦银, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啸胧,地道東北人。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓幔虏,卻偏偏與公主長得像纺念,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子想括,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容