Python3 學習筆記

寫在前面的話

代碼中的# > 表示的是輸出結(jié)果

輸入

  • 使用input()函數(shù)
  • 用法
str = input('請輸入內(nèi)容:')
print(str)
#>>    此時控制臺上打印的一定是你輸入的字符串
  • 注意
    • input函數(shù)輸出的均是字符串烦绳,如需要接收其他類型的變量,就需要使用強制類型轉(zhuǎn)換配紫。
    • 例如:將字符串轉(zhuǎn)換為數(shù)字類型的變量
num = input('請輸入數(shù)字:')
print(type(num))
#    >>    <class 'str'>
#此時可以看見径密,就算輸入數(shù)字類型的變量,num接收的值依然是一個字符串類型
num = int(num)   #強制轉(zhuǎn)換為int類型
print(type(num))
#    >>     <class 'int'>
#此時控制臺返回的是num變量的類型,可以看到,類型已經(jīng)是int了

輸出

  • 使用print()函數(shù)
  • 用法
#常用用法
print('Hello World!')
# 自定義用法
print(value,sep = ' ',end = '\n')
value表示需要打印的值
sep表示打印多個值之間的分隔符衡蚂,默認是一個空格
end表示打印結(jié)束后的分隔符,默認是\n

變量伪很、函數(shù)戚啥、類命名規(guī)則

  • 可以使用數(shù)字奋单、字母、下劃線
  • 不可以用數(shù)字開頭
  • 不可以使用關(guān)鍵字和保留字
  • 推薦駝峰命名法
    • 類名使用大駝峰猫十,如MyFirst
    • 變量览濒、函數(shù)使用小駝峰,如myFirst
  • 也可使用posix寫法拖云,如my_first

常用操作

  • type()函數(shù)贷笛,查看當前變量類型
  • id()函數(shù),查看當前變量地址
  • help()函數(shù)宙项,查找?guī)椭臋n

變量進行賦值

  • 單獨賦值
a = 5
b = 'hh'
  • 一起賦值
a , b = 5 , 'hh' 
  • 兩個變量之間的互換
a , b = 5 , 10

#如果遇到JAVA程序員乏苦,會這樣寫
int temp = a 
a = b
b = temp

#但是在python中,只需要進行簡單交換即可
a , b = b , a
#通過這種方式就完成了兩個變量值的交換

變量的類型

數(shù)字型(number)

  • 整數(shù)(int)
    • 二進制
    • 八進制
    • 十進制
    • 十六進制
  • 浮點小數(shù)(float)
    • 一般采用的是科學計數(shù)法,以e表示10汇荐,e上面為次方
  • 布爾值(boolean)
    • True洞就,可用數(shù)字表示,除了0以外的數(shù)字都為True
    • False掀淘,可用數(shù)字0表示
  • 復(fù)數(shù)(complex)
    • 一般不會涉及到

字符串型(string)

  • 用單引號旬蟋,雙引號或者是三引號進行表示
a = 'Jack'
b = "Jack"
c = "Bob,'haha',Jack"
print(c)

#其結(jié)果為Bob,'haha',Jack
  • 格式化的兩種方式
    • 利用%

      %s : 格式化字符串

      %d : 格式化整數(shù)

n = '我是XX'
print('你好,%s'%n)
  • 利用format()函數(shù)進行格式化
n = '我是XX'
print('你好,{0}'.format(n))
#還可以這么使用
age = 18
name = 'Bob'
print('我是{0},我今年{1}歲,你也{1}歲'.format(name,age))
  • 字符串的轉(zhuǎn)義
    • 用"\"表示

    • 最簡單的一種方法就是字符串前面加上"r",表示的是原始字符:字符串中的所有轉(zhuǎn)義字符都不進行轉(zhuǎn)義

    • 使用轉(zhuǎn)義字符

      \\ : 表示\

      \n : 表示換行

      \t : 表示制表符

      \r : 表示回車

   ```
   print(r'\\')
   #打印出的為\\
   
   print('\\\\')
   #這樣也可以打印出\\
   ```
  • 常用函數(shù)

    capitalize() : 將字符串的第一個字母大寫,其他小寫

    strip() : 去掉字符串兩邊的空格

    replace() : 替換字符串

    lower() : 全部小寫

    upper() : 全部大寫

    encode() : 編碼

    decode() : 解碼

    s1 = ' abc '
    
    s2 = 'aBc'
    
    s1.strip() # > abc
            
    s2.capitalize() # > Abc
    
    s2.lower() # > abc
    
    s2.upper() # > ABC
    
    s2.encode('utf-8') # > b'aBc'
    
    b'aBc'.decode('utf-8') # > aBc
    
    s2.replace('B','*') # > a*c
    
    

列表(list)

  • 創(chuàng)建列表的方式

    list = [1,2,3,4,5]
    
  • 列表屬于一個可迭代對象,可用于迭代

    • 使用for對列表中的元素進行迭代

      for item in list:
         print(item)
      #此時會輸出
      # > 1
      # > 2
      # > 3
      # > 4
      # > 5
      
      #item表示的是列表中的元素
      
    • 使用下角標進行操作革娄,但是一般不會這么使用

      for i in range(len(list)):
        print(list[i])
      
      #len()函數(shù)表示測量某個迭代序列的長度倾贰,返回int
      #range()函數(shù)用于組成從0數(shù)字到給定值的序列
      
  • 可使用成員判斷符 in

    print(1 in list)
    
    # > True
    
  • 可使用 * ,表示一個列表重復(fù)N次拦惋,并組成一個新的列表

    print(list * 5)
    
    # > [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
    
  • 可使用 + 匆浙,表示兩個列表相加,組成一個新列表

    print(list + [6.7,8])
    
    # > [1, 2, 3, 4, 5, 6,7,8]
    
  • 常用函數(shù)

    del: 刪除列表

    len(): 長度

    max()厕妖、min():最大吞彤、最小值

    list() : 將可迭代的序列轉(zhuǎn)化為list

    append() : 在列表末尾添加元素

    index() : 返回列表中某個元素的引索值

    remove() : 移除列表中的某個元素

    pop() :移除列表中引索值為XX的元素

    insert() : 向列表中引索值為XX的位置添加一個元素

    reverse() : 反向列表元素

    copy() : 復(fù)制一份列表到新的列表中

    list = [1,2,3,4,5]
    
    del list # > 刪除list
    
    len(list) # > 5
    
    max(list) # > 5
    
    min(list) # > 1
    
    list.append(6) # > [1,2,3,4,5,6]
    
    list.index(1)  # > 0
    
    list.remove(6) # > [1,2,3,4,5]
    
    list.pop(0) # > [2, 3, 4, 5]
    
    list.insert(0,7) # > [7, 1, 2, 3, 4, 5]
    
    list.reverse() # > [5, 4, 3, 2, 1]
    
    l = list.copy # > [1,2,3,4,5]
    
  • 列表生成式

    • 可操作列表中的單個元素,并迭代整個列表組成一個新列表

    • 使用方法:list2 = [i for i in list1 if ....]

      list1 = [1,2,3,4,5,6,7,8,9]
      
      #下面我們使用列表生成式挑選偶數(shù)組成一個新的列表
      
      list2 = [i for i in list1 if i % 2 == 0] 
      
      # > [2, 4, 6, 8]
      
      # i for i in list1 表示遍歷list1列表中的元素
      
      # if i % 2 == 0 表示挑選出所有能整除2的元素
      
    • 列表生成式的嵌套

      list1 = [1,2]
      list2 = [3,4]
      
      list3 = [x+y for x in list1 for y in list2] # > [4, 5, 5, 6]
      
      #可以看出叹放,新的列表的結(jié)果是list1中的每個元素加上list2中每個元素的結(jié)果
      #組成是[list1[0]+list2[0],list1[0]+list2[1],list1[1]+list2[0],list1[1]+list2[1]]
      

元組(tuple)

  • 創(chuàng)建元組的方式

    tuple = (1,2,3)
    
  • 元組具有l(wèi)ist中的部分屬性饰恕,但只可以進行讀取操作,不能進行寫入操作

  • 可以將一個list列表轉(zhuǎn)化為一個元組tuple

    t = tuple(list)
    

字典(dict)

  • 字典的創(chuàng)建方式

    dict = {'jack':24,'bob':18}
    #或者是
    d = dict(jack = 24,bob = 18)
    
  • 字典是一組鍵——值對應(yīng)序列井仰,它是一個無序的對象埋嵌。

  • 遍歷字典

    • 使用item()方法遍歷

      for key,value in dict.items():
        print(key,value)
      
      #jack 24
      #bob 18
      
    • 直接遍歷

      for i in dict:
        print(i,dict[i])
      
      #jack 24
      #bob 18
      
  • 注意,一旦使用dict[key]查找value值俱恶,當key的值不存在時雹嗦,就會報錯,推薦使用get()方法

  • 常用方法

    get() : 查找對應(yīng)鍵的值合是,當鍵不存在時不會報錯

    keys() : 將字典所有key組成一個可迭代的序列

    values() : 將字典所有value組成一個可迭代的序列

    items() : 將字典的每組key和value組成一個元組了罪,并將所有組組成一個序列,序列的類型是dict_items

    fromkeys() : 將一個列表作為key值傳入,并指定默認的value值

    dict.get('jack') # > 24
    
    dict.keys() # > dict_keys(['jack', 'bob'])
    
    dict.values() # > dict_values([24, 18])
    
    dict.items() # > dict_items([('jack', 24), ('bob', 18)])
    
    list = ['jack', 'bob']
    
    d = dict.fromkeys(list , 18)  # > {'jack': 18, 'bob': 18}
    

集合(set)

  • 定義方式

    list = [1,2,3,4,4]
    s = set(list)
    # > {1, 2, 3, 4}
    
    #或者是
    s = {1,2,3,4}
    
  • 注意:不要與dict字典搞混淆聪全,字典也是{}定義的泊藕,但是卻是由key-value組成的一對

  • set集合中數(shù)據(jù)也是無序的,且不包含重復(fù)元素难礼,必須是可哈希數(shù)據(jù)

  • 常用函數(shù)

    add() : 添加單個數(shù)據(jù)

    update : 添加可迭代數(shù)據(jù)

    remove() : 移除集合中某個值娃圆,一旦值不存在,便會報錯

    discard() : 移除集合中某個值蛾茉,就算值不存在讼呢,也不會報錯

    clear() : 清空集合數(shù)據(jù)

    intersection() : 求交集

    difference() : 求差集

    union() : 求并集

    issubset() : 檢查一個集合是否是另一個集合的子集

    issuperset() : 檢查一個集合是否是另一集合的超集

    s = {1,2,3,4,5}
    
    s1 = {4,5,6,7,8}   
    
    list = [5,6,7,8,9]
    
    s.add(6) # > {1,2,3,4,5,6}
    
    s.update() # > {1, 2, 3, 4, 5, 6, 7, 8, 9}
    
    s.remove(5) # > {1,2,3,4}
    
    s.discard(5) # > {1,2,3,4}
    
    s.clear()
    
    s.intersection(s1) # > {4, 5}
    
    s.difference(s1) # > {1, 2, 3}
    
    s.union(s1) # > {1, 2, 3, 4, 5, 6, 7, 8}
    
    

運算符

算數(shù)運算符

  • 加法運算符 +

    • 在數(shù)字中表示兩個數(shù)字相加

      print(2+5) # > 7
      
    • 在字符串中表示兩個字符串相連

      print('hello'+'world') # > helloworld
      
    • 在列表中表示兩個列表首尾相連

      l1 = [1,2,3]
      l2 = [3,4,5]
      l = l1 + l2
      # > [1,2,3,3,4,5]
      
  • 減法運算符 -

     print(5 - 3) # > 2
    
  • 乘法運算符 *

    • 當對象為數(shù)字型時,執(zhí)行乘法運算

      print(5 * 2) # > 10
      
    • 當對象為非數(shù)字型時谦炬,打印N次,并組成一個新對象

      print('a'*3) # > aaa
      print([1,2,3] * 2) # > [1, 2, 3, 1, 2, 3]
      
  • 除法運算符 /

    print(6 / 2) # > 3
    
  • 取余運算符 %

    • 計算兩個數(shù)字的余數(shù)
      print(3 % 2) # > 1
      
  • 整除運算符 //

    • 計算兩個數(shù)整除的數(shù)字悦屏,不會保留小數(shù)點

      print( 3 // 2 ) # > 1
      
  • 冪運算符 **

    • 次方運算

      print(2 ** 3) # > 8
      

比較運算符

  • 注意:返回的都為布爾值類型

  • 等于 ==

    print(1 == 1) # > True
    
  • 不等于 !=

    print(1 != 1) # > False
    
  • 小于 <

    print(1 < 1) # > False
    
  • 小于等于 <=

    print(1 <= 1) # > True
    
  • 大于 >

    print(1 > 1) # > False
    
  • 大于等于 >=

    print(1 >= 1) # > True
    

賦值運算符

  • 等于 =

邏輯運算符

  • and 與
    print(True and False) # > False
    
  • or 或
    print(True and False) # > True
    
  • not 非
    s = 'abc'
    print('d' not in s)
    # > True
    

成員運算符

  • 注意:成員運算符需要判斷的對象是一個可以迭代的類型

  • in 在里面

    print('a' in 'abc') # > True
    
  • not in 不在里面

    print('a' not in 'abc')
    # > False
    
    

身份運算符

  • 注意,身份運算符是比較兩個對象內(nèi)存地址是否相同
  • is 是
  • not is 不是

運算符的優(yōu)先級

  • 永遠記住,括號里面的最先開始運算础爬,具有最高優(yōu)先級

程序結(jié)構(gòu)

順序結(jié)構(gòu)

  • 按照代碼編寫的方式逐行進行

分支散劫、判斷結(jié)構(gòu)

  • if...else語句
    a = 10
    b = 5
    if a > b:
        print(a,'>',b)
    else:
        print(a,'<',b)
    # > 10 > 5 
    
  • if..elif..else語句
    • 注意,以上代碼并不嚴謹幕帆,缺少相等的時候
    a = 10
    b = 10
    if a > b:
        print(a,'>',b)
    elif:
        print(a,'=',b)
    else:
        print(a,'<',b)
    # > 10 = 10
    

循環(huán)結(jié)構(gòu)

  • 使用for進行循環(huán)(知道具體循環(huán)次數(shù)的時候)
    s = 'abcdefg'
    for i in s:
        print(i)
    
    # > a
    # > b
    # > c
    # > d
    # > e
    # > f
    # > g
    
  • 使用while進行循環(huán)(不知道具體循環(huán)次數(shù))
    • while
      n = 0
      while n < 10:
        print(n)
        n = n + 1
      # > 0
      # > 1
      # > 2
      # > 3
      # > 4
      # > 5
      # > 6
      # > 7
      # > 8
      # > 9
      
  • break 跳出整個循環(huán)
    • 當需要跳出整個循環(huán)的時候可以用break
      n = 1
      while n < 10:
      print(n)
      n = n + 1 
      if n == 3:
        break
      
      # > 1
      # > 2
      
  • continue 結(jié)束本次循環(huán)
    • 當某些條件時获搏,跳過本次循環(huán)
      n = 0
      while n < 10:
          n = n + 1
          if n == 3:
            continue
          print(n)
      # > 1
      # > 2
      # > 4
      # > 5
      # > 6
      # > 7
      # > 8
      # > 9
      # > 10
      

函數(shù)

定義函數(shù)

  • 使用def進行定義,后面跟著方法名和()

    def func():
        print('hello')
    

調(diào)用,傳入函數(shù)

  • 調(diào)用函數(shù)時失乾,用函數(shù)名加括號
    #調(diào)用函數(shù)
    
    func()
    
    # > hello
    
  • 傳參時常熙,只用函數(shù)名
    #如tk框架中綁定按鈕事件
    
    button = Button(text = '按鈕' ,command = func)
    
    #如使用help函數(shù)
    
    print(help(print))
    
    
    # > Help on built-in function print in module builtins:
    
    # > print(...)
    # > print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    # > Prints the values to a stream, or to sys.stdout by default.
    # > Optional keyword arguments:
    # > file:  a file-like object (stream); defaults to the current sys.stdout.
    # > sep:   string inserted between values, default a space.
    # > end:   string appended after the last value, default a newline.
    # > flush: whether to forcibly flush the stream.
    
    # > None
    

函數(shù)的參數(shù)

  • 位置參數(shù)

    • 根據(jù)定義函數(shù)時參數(shù)的位置,自動進行參數(shù)傳遞碱茁,此時裸卫,必須嚴格按照參數(shù)的順序進行傳參
      def func(name,age):
        print('my name is {0},I am {1} years old.'.format(name,age))
      
      func('jack',24)
      # > my name is jack,I am 24 years old.
      # 此時傳遞參數(shù)的順序必須是name,age纽竣,否則參數(shù)就會傳遞不正確墓贿,嚴重時,會報錯
      
  • 關(guān)鍵字參數(shù)

    • 根據(jù)指定的關(guān)鍵字進行傳遞參數(shù)蜓氨,傳參的順序是否正確聋袋,不會影響函數(shù)的參數(shù)傳遞
      
      def func(name,age):
        print('my name is {0},I am {1} years old.'.format(name,age))
      
      func(age = 24,name = 'jack')
      # > my name is jack,I am 24 years old.
      
  • 默認參數(shù)

    • 在定義函數(shù)時,就傳遞默認值穴吹,被傳遞默認值的參數(shù)如果不進行再次傳參幽勒,就會使用默認值
      def func(name,age = 0):
        print('my name is {0},I am {1} years old.'.format(name,age))
      
      func('jack')
      # > my name is jack,I am 0 years old.
      func('jacl',24)
      # > my name is jack,I am 24 years old.
      
  • 可變參數(shù)

  • 解包:是將可迭代的對象變?yōu)閱蝹€元素

    • 明確一個概念,可迭代的對象可以進行解包操作港令,而且可以不使用解包的操作符號

      list = [1,2,3]
      a , b , c = list
      # > 1
      # > 2
      # > 3
      #可以看出啥容,對于一個知道長度的可迭代對象我們可以用賦值的方式將其解包
      
    • 使用*對可迭代的對象進行解包

      #但如果對于一個我們不知道長度的列表如何進行解包呢?
      #這就是*的用法
      list = [1,2,3,4]
      print(*list)
      # > 1 2 3 4 
      #可以看出顷霹,此時列表list已經(jīng)被用*解包為單個元素
      
    • 使用**對字典進行解包

      #首先我們使用*對dict解包咪惠,看能得到什么?
      dict = {'jack':24 , 'bob':18}
      print(*dict) 
      # > jack bob
      # 結(jié)論:使用*進行解包時淋淀,我們只是得到了字典的key值
      # 那我們試試**吧
      print(**dict)
      # > TypeError: 'jack' is an invalid keyword argument for this function
      # 百度后得知print()函數(shù)不支持打印**對象
      # 那就試試打印出key對應(yīng)的值
      print('{jack},{bob}'.format(**dict))
      # > 24,18
      #參考網(wǎng)上資料遥昧,**dict解包之后應(yīng)該是這樣的
      **dict = Jack = 24 , bob = 18 
      #現(xiàn)在你想到了什么?
      
  • 壓包绅喉,將幾個不同的可迭代對象的單個元素按順序用元組的形式結(jié)合成一個列表

    • 使用zip()函數(shù)進行壓包
      list1 = [1,2,3]
      list2 = ['a','b','c']
      list3 = ['one','two','three']
      for i in zip(list1,list2,list3):
          print(i)
      # > (1, 'a', 'one')
      # > (2, 'b', 'two')
      # > (3, 'c', 'three')
      # 可以看出這里對每個列表的第一元素渠鸽、第二個元素叫乌、第三個元素柴罐,都進行了組合,使之成為了了一個新的元組
      a = zip(list1 ,list2 ,list3 )
      print(list(a)) 
      # > [(1, 'a', 'one'), (2, 'b', 'two'), (3, 'c', 'three')]
      #可以看出憨奸,將三個序列壓包后革屠,每個序列中下標相同的元素,重新組成了一個元組,而這些元組都構(gòu)成了一個列表
      
  • 可變參數(shù)函數(shù)

    • 了解了*解包之后我們就可以明白函數(shù)的可變參數(shù)是怎么回事了
    • 定義一個可變參數(shù)的函數(shù)
       #注意:這里args可以是任何變量似芝,但為了程序的可讀性那婉,我們需要遵循傳統(tǒng),寫上args党瓮,讓其他人一看就知道這里應(yīng)該是可變參數(shù)
      
      def func(*args):              
        print(args)
      func('jack','hello',28,41) # >('jack', 'hello', 28, 41)
      
      #可以看出我們不論寫多少參數(shù)详炬,函數(shù)就會接收多少個參數(shù),看到這里你也許會說寞奸,這并沒有什么用扒好铡?
      #是的枪萄,但是你想想如果我們需要將一個列表的元素都傳入函數(shù)中去的時候要怎么辦隐岛?
      #總不能用list[0],list[1]...一個一個進行傳參吧?
      
      list = ['name','age','sex','birth']
      func(*list) # > ('name', 'age', 'sex', 'birth')
      
      #可以看出瓷翻,*list確實是將單個元素傳入了函數(shù)中
      
    • 可變參數(shù)的關(guān)鍵字函數(shù)
       #剛才對字典解包后得出**dict = Jack = 24 , bob = 18
       #仔細一想聚凹,如果把**dict當成參數(shù),這不就是一個關(guān)鍵字參數(shù)嘛 
      
    • 定義一個可變參數(shù)的關(guān)鍵字函數(shù)
      def func(**kwargs):
         print('我的名字是{0},我今年{1}齐帚,我是{2}妒牙,我的生日是{3}'.format(kwargs.get('name'),kwargs.get('age'),kwargs.get('sex'),kwargs.get('birth')))
      
      func(name = 'jack',age = 24 ,sex = 'male',birth = '1980-10-10')
      
      # > 我的名字是jack,我今年24,我是male对妄,我的生日是1980-10-10
      
      #定義一個字典傳入函數(shù)中
      
      dict = {'name':'jack','age':24}
      func(**dict)
      
      # > 我的名字是jack,我今年24单旁,我是None,我的生日是None        
      # 可以看出饥伊,即使有些參數(shù)是不填的函數(shù)也可以正常運行象浑,這是不可變參數(shù)函數(shù)所不能達到的效果
      
  • 參數(shù)混用

    • 需要遵照函數(shù)(位置函數(shù),關(guān)鍵字函數(shù)琅豆,可變參數(shù)函數(shù)愉豺,可變參關(guān)鍵字函數(shù))的順序進行
      def func(name , age = 24 , *args , **kwargs):
        pass
      

函數(shù)的返回值

  • 所有函數(shù)都有返回值,表示函數(shù)調(diào)用已經(jīng)結(jié)束
  • 定義函數(shù)返回值,使用return
    def func(a):
        return a+10
    
    b = func(1) # > 11
    
  • 即使沒有定義return茫因,解釋器也會自動加上 return None

函數(shù)文檔

  • 當使用help()函數(shù)時蚪拦,顯示的幫助文檔

  • 也可以使用doc調(diào)用文檔

  • 當你在不知道怎么使用函數(shù)或者是類時,都可以調(diào)用幫助文檔冻押,里面會給你詳細說明各種用法

  • 自定義函數(shù)幫助文檔驰贷,在開頭加上''' '''即可,如果使用的ide洛巢,會自動給你加上其他參數(shù)

    def func(x,y):
    '''
    這個函數(shù)什么也不做
    :param x: 傳參x
    :param y: 傳參y
    :return: None
    '''
        pass
    
    print(help(func))
    
    # > Help on function func in module __main__:
    
    # > func(x, y)
    # > 這個函數(shù)什么也不做
    # > :param x: 傳參x
    # > :param y: 傳參y
    # > :return: None
    
    # > None
    
    print(func.__doc__)
    
    # > 這個函數(shù)什么也不做
    # > :param x: 傳參x
    # > :param y: 傳參y
    # > :return: None
    

高階函數(shù)

  • 指該函數(shù)的參數(shù)中傳入另一個函數(shù)

  • map()函數(shù)括袒,映射操作,將傳入的函數(shù)作用于可迭代對象的每個元素上,返回一個可以迭代的map對象

    list = [1,2,3,4]
    
    def func(x):
        return x+1
    
    a = map(func,list)
    
    for i in a:
        print(i)
    
    # > 2
    # > 3
    # > 4
    # > 5
    
  • reduece()函數(shù),歸并操作,將列表的兩個值經(jīng)過函數(shù)計算后與列表中的第三個值再次進行相同計算稿茉,直到列表元素完成循環(huán)锹锰。

    • 簡單的用公式表達就是這樣芥炭,f(f(f(x1,x2)恃慧,x3)园蝠,x4)....

      #計算列表中所有元素的乘積
      
      from functools import reduce
      
      def func(x,y):
          return x*y
      
      list = [2,3,4]
      
      print(reduce(func,list))        
          
      # > 24
      
  • filter()函數(shù),過濾操作,用于篩選列表中的元素

    #篩選出列表中的偶數(shù)
    
    def func(x):
       if x % 2 == 0:
           return True
       else:
           return False
    
    list = [2,3,4]
    
    for i in filter(func,list):
       print(i)
    
    # > 2
    # > 4
    
  • sorted()函數(shù)痢士,排序操作,可以使用自定義的函數(shù)進行排序

    • 默認排序

      list = [5,4,3,9,8]
      
      l = sorted(list)
      
      print(l)
      
      # > [3, 4, 5, 8, 9]
      
    • 關(guān)鍵字排序

      • 關(guān)鍵字彪薛, key = 函數(shù)名

      • 反向排序,傳入reverse = True

      #將列表的元素按絕對值大小進行排序并倒序      
      
      list = [5,-11,6,9,1]
      
      l = sorted(list, key=abs,reverse = True)
      
      print(l)
      
      # > [-11, 9, 6, 5, 1]
      
  • zip()函數(shù)怠蹂,壓縮操作陪汽,將多個傳入的列表每個下標相同的元素組成一個新的元組,再將這些元組組成一個可迭代的zip對象褥蚯,返回zip對象

    • 注意 : 如果傳入列表的長度不一致挚冤,那么zip操作只會取最短的那個列表的長度,組成zip對象
    l1 = [1,2,3,4]
    
    l2 = ['a','b','c','d']
    
    l3 = ['one','two','three','four']
    
    l = zip(l1,l2,l3)
    
    for i in l:
       print(i)
    
    # > (1, 'a', 'one')
    # > (2, 'b', 'two')
    # > (3, 'c', 'three')
    # > (4, 'd', 'four')
    
    # 如果用列表生成式會怎么樣赞庶?
    list = [i for i in l]
    print(list)
    
    # > [(1, 'a', 'one'), (2, 'b', 'two'), (3, 'c', 'three'), (4, 'd', 'four')]
    
    #長度不一致時
    
    l4 = ['jack','bob']
    
    l5 = zip(l1,l4)
    
    list = [i for i in l5]
    print(list)
    
    # > [(1, 'jack'), (2, 'bob')]
    
  • enumerate()函數(shù)训挡,將列表中每個引索值和其對應(yīng)的元素組成一個新的元組,再將這些元組組成一個enumerate對象歧强,返回enumerate對象

    l = ['a','b','c','d']
    em = enumerate(l)
    list = [i for i in em]
    print(list)
    
    # > [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]
    

返回函數(shù)

  • 將函數(shù)作為返回結(jié)果

    def hello():
       
       def say():
           print('hello')
       return say
    
    f = hello()
    print(f)
    # > <function hello.<locals>.say at 0x00000233A6EF8A60>
    
    f()
    # > hello
    
  • 閉包,當一個函數(shù)定義在另一個函數(shù)的內(nèi)部時,使用外部函數(shù)的變量或者參數(shù),當這個內(nèi)部函數(shù)被當做返回值時,外部函數(shù)的所有參數(shù)和變量都保存在返回的函數(shù)中時,就叫做閉包

    def hello(n):
       def say():
           print(n)
       return say 
    
    f = hello('hello')
    f()
    # > hello
    
  • 注意:在返回函數(shù)中不能引用循環(huán)變量,如果確實需要引用循環(huán)變量時,需要在內(nèi)部函數(shù)外面再包裹一層函數(shù),該函數(shù)以參數(shù)的形式接受循環(huán)變量,內(nèi)部函數(shù)就可以安全使用循環(huán)變量

    def func():
       list = []
       for i in range(1,4):
           def funb():
               return   i * i
           list.append(funb)
       return list
    
    list = func()
    print(list)
    
    # > [<function func.<locals>.funb at 0x000001F1CE5A8A60>, <function func.<locals>.funb at 0x000001F1CE5A8AE8>, <function func.<locals>.funb at 0x000001F1CE5A8B70>]
    
    for i in list:
       print(i())
    
    # > 9
    # > 9
    # > 9
    
    #此時可以看出,循環(huán)變量并沒有正確的引入返回函數(shù)中去.
    
    #正確的寫法應(yīng)該是使用funb將funa包裹,然后通過funb 返回fana 的返回值
    
    def func():
       def funb(i):
           def funa():
               return i * i
            return funa
       list = []
       for i in range(1,4):
           list.append(funb(i))
        return list
     
    list = func()
    print(list)
    
    # > [<function func.<locals>.funb.<locals>.funa at 0x000001E2944C8AE8>, <function func.<locals>.funb.<locals>.funa at 0x000001E2944C8B70>, <function func.<locals>.funb.<locals>.funa at 0x000001E2944C8BF8>]
    
    for i in list:
       print(i())
    
    # > 1
    # > 4
    # > 9
    

匿名函數(shù)

  • lambda澜薄,用于自定義一個函數(shù),此函數(shù)沒有名稱摊册,比如可以向高級函數(shù)中傳遞這樣一個匿名函數(shù)肤京,而不必去定義它
#將每個元素的前面加上hello
list = ['jack','bob','luce','alice']
l = map(lambda x:'hello'+x,list)
for i in l:
  print(i)

# > hellojack
# > hellobob
# > helloluce
# > helloalice

偏函數(shù)

  • 偏函數(shù),將一個函數(shù)中的參數(shù)固定住茅特,然后創(chuàng)建一個新的函數(shù)忘分,這就是偏函數(shù)

  • 定義偏函數(shù):偏函數(shù)名 = functools.partial(原函數(shù),固定值)

  #假設(shè)白修,我們有'jack','bob','luce','alice'妒峦,這4個人,他們的年齡都是24歲
  # 此時有一個函數(shù)say,是為了介紹自己兵睛,需要傳入name和age兩個參數(shù)
  # 希望在不改變say函數(shù)的情況下肯骇,簡化操作,此時我們就可以使用偏函數(shù)了
  
  import functools
  
  list = ['jack','bob','luce','alice']
  
  def say(name,age):
      print('My name is {0},age is {1}'.format(name,age))
  
  say24 = functools.partial(say,age = 24)
  
  for person in list:
      say24(person)
  
  # > My name is jack,age is 24
  # > My name is bob,age is 24
  # > My name is luce,age is 24
  # > My name is alice,age is 24
  

遞歸函數(shù)

  • 函數(shù)內(nèi)部自己調(diào)用自己的情況叫做遞歸函數(shù)
  #遍歷一個盤符下的所有文件(包括子文件夾祖很、文件)
  
  import os

  def getFile(path):
      try:
          filelist = os.listdir(path) #得到該文件夾下的所有文件
          for file in filelist:
              file = os.path.join(path,file) #將文件名和路徑結(jié)合起來
              if os.path.isdir(file):
                  getFile(file)  #在這里如果判斷一個文件是文件夾笛丙,那么就會再次調(diào)用自己
              else:
                  print(file)
      except:
          print('出錯,跳過')
  
  getFile(r'd:/')

裝飾器

  • 對原函數(shù)進行擴展功能但是不改變原函數(shù)

  • 使用@+裝飾器名進行裝飾,具有固定格式

  • 使用@裝飾時假颇,執(zhí)行函數(shù)時胚鸯,相當于執(zhí)行行了裝飾器函數(shù)(原函數(shù))

    #首先我們思考一下,接收一個無參數(shù)的函數(shù)啊终,并且擴展功能后返回這個函數(shù)
    import time
    
    
    def printTime(f):
        print('Time: ', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
        return f
    
    
    def hello():
        print('hello')
    
    
    print(printTime(hello)()) 
    
    # > Time:  2018-08-09 08:45:25
    # > hello
    # > None  
    
    # 這時,我們可以看到定義了一個printTime函數(shù)愧哟,并且執(zhí)行打印時間后返回原函數(shù)甘改,這可以說是一個最簡單的裝飾器了榄融。
    # 為什么會返回一個None跌前?我認為是hello函數(shù)后系統(tǒng)自己添加了一個return None后導(dǎo)致的田弥,我們將hello函數(shù)手動添加return 5后試試辜妓,結(jié)果返回的是5
    
    
    
    # 如果我們需要接收一個帶參數(shù)的函數(shù)呢?
    import time
    
    def printTime(f):
       
       def wrapper(*args,**kwargs):
           print('Time: ',time.strftime('%Y-%m-%d %H:%M:%S',time.localtime()))
           return f(*args,**kwargs)
        return wrapper
    
    @printTime 
    def hello():
       print('hello')
    
    hello()
    
    # > Time:  2018-08-08 20:21:26
    # > hello
    
    # printTime函數(shù)接收一個函數(shù),返回一個wrapper函數(shù)
    # wrapper函數(shù)接收可變參數(shù)硫戈,然后將這些參數(shù)賦值給printTime接收到的函數(shù)释牺,最后再返回這個函數(shù)。 
    

高級特性

切片 slice

  • 切片操作是對一個可迭代的對象進行切割,并組成一個新的迭代對象

  • 方式:切片對象[開始引索:結(jié)束引索:步長]

  • 注意:切片操作中包含開始引索验游,不包含結(jié)束引索伞鲫,如果開始引索是0,可以省略甫何,如果步長是1,也可以省略

  • 開始引索也可以是負數(shù)霎迫,當為負數(shù)時斋枢,則從最后開始計算

  list = [1,2,3,4,5,6,7,8,9,10]
  
  #挑選出所有奇數(shù)
  print(list[:9:2])
  # > [1, 3, 5, 7, 9]
  
  #取前4個數(shù)
  print(list[:4])
  # > [1, 2, 3, 4]
  
  #取后2個數(shù)
  print(list[-2:])
  # > [9, 10]
  
  #取3~7
  print(list[2:7])
  # > [3, 4, 5, 6, 7]

迭代

  • 使用for進行迭代

列表生成式

  • 見list列表中

generator生成器

  • 存疑

思想

  • OO面向?qū)ο?/li>
  • OOA面向?qū)ο蟮姆治?/li>
  • OOD面向?qū)ο蟮脑O(shè)計
  • OOI面向?qū)ο蟮膶崿F(xiàn)
  • OOP面向?qū)ο蟮木幊?/li>

類和對象

    • 類是一個抽象的名詞,是共性事物

    • 類有成員屬性女气,是表明事物的特征杏慰,可以被讀取测柠,寫入炼鞠,刪除

    • 類有成員函數(shù)蹋砚,表明事物的功能或者動作

  • 對象

    • 對象是一個具體的名詞平匈,是一個具體事物

    • 對象是類的實例化

  • 說明:我們都是人拄踪,這就是類芜果;但我們有男人俐芯,也有女人量愧,每個人高矮胖瘦都不一樣柑土,我們每個人就是對象慢哈,是類的實例化

  • 類和對象的對成員訪問順序

    • 首先訪問對象中的成員

    • 對象沒有成員的會訪問類中的成員

    • 類中沒有成員會訪問父類中的成員

    • 依次向上遞推

定義類

  • class 類名(繼承類):定義

  • 類中只允許出現(xiàn)成員屬性和成員方法

  • 定義類之后榛斯,會在內(nèi)存中專門劃分一塊地方儲存類和類的成員观游;當實例化類之后,繼承的成員會指向內(nèi)存中的這塊地方

  class Person(object):
      
      #定義屬性
      name = 'NoName'
      age = 0
     
      #定義函數(shù)
      def say(self):
          print('say')
      def eat(self):
          print('eat')
      def sleep():
          print('sleep')
  • self

    • self不是一個關(guān)鍵字驮俗,可以是任何一個變量代替懂缕,表示的是當前對象本身,當調(diào)用方法時,對象會將自己傳入到方法中去

    • 有self的函數(shù)稱為非綁定方法王凑,可以通過對象進行訪問

      • 使用實例化對象訪問

        p = Person()
        p.say()
        # > say
        
      • 使用類().方法訪問

        Person().say()
        # > say
        
      • 使用類.方法(類())訪問

        Person.say(Person())
        # > say
        
      • 實質(zhì)是都是需要實例化一個對象搪柑,并傳入非綁定方法中去

    • 無self的函數(shù)稱為綁定方法,只能通過類進行訪問

      p = Person()
      p.sleep
      # > TypeError: sleep() takes 0 positional arguments but 1 was given
      #可以看出索烹,綁定方法不可以用對象進行訪問工碾,因為方法中沒有定義傳入對象本身的參數(shù),所以出現(xiàn)了sleep函數(shù)不需要參數(shù)百姓,但傳入了一個參數(shù)渊额,傳入的參數(shù)就是對象本身
      Person.sleep()
      # > sleep
      
      • 如果一定要使用對象訪問,可用對象.__class__.方法訪問
        p.__class__.sleep()
        # > sleep
        
  • super

    • super也不是一個關(guān)鍵字,但他是一個類

    • 作用是獲取MRO列表中的第一個類

    • 可以使用類.__mro__獲取類的MRO列表

    • 在單繼承中旬迹,表示父類

    • 在多繼承中焦读,代表了了MRO列表中的第一個元素代表的類

面向?qū)ο?/h2>
  • 封裝,對類的成員訪問進行限制

    • public 公開

      • 公開成員舱权,都可以進行訪問
    • protected 受保護

      • 受保護成員矗晃,只能在類、子類宴倍、對象中進行訪問

      • 定義:使用_成員進行定義

      class Person():
      
         _name = 'NoName'
         _age = 24
      
      class Student(Person):
          pass
      
      s = Student()
      print(s._name,s._age)
      
      # > NoName 24
      #可以看出张症,子類和子類的對象訪問都是沒有問題的
      
    • private 私有

      • 私有成員,只能在當前類中進行訪問

      • 注意:子類不繼承私有成員

      • 定義:使用__成員進行定義

      class Person():
      
        __name = 'NoName'
        __age = 24
      
      class Student(Person):
        pass
      
      p = Person()
      print(p.__name, p.__age)
      # > AttributeError: 'Person' object has no attribute '__name'
      s = Student()
      print(s.__name, s.__age)
      # > AttributeError: 'Student' object has no attribute '__name'
      #可以看出鸵贬,子類并沒有繼承父類中的私有屬性,而且對象也不允許使用私有成員
      
  • 繼承

    • 類成員擴充俗他,當子類繼承了父類時,就擁有了父類除私有成員以外的所有其他成員阔逼,這相當于將子類成員指向父類成員的地址兆衅,同時,還可以繼續(xù)添加相應(yīng)的屬性和函數(shù)

      class Person():
        
        def talk(self):
            print('talk')
      
      class Student(Person):
        
        def study(self):
            print('study')
      s = Student()
      s.talk()
      
      # > talk
      
      s.study()
        
      # > study
      
    • 子類擴充父類函數(shù)方法

      • 使用self嗜浮,其中self指的是子類本身

        class Person():
          
          def talk(self):
              print('talk')
        
        class Student(Person):
          def talk(self):
             Person.talk(self) 
             print('擴充函數(shù)')
        
        s = Student()
        s.talk()
        
        # > talk
        # > 擴充函數(shù)
        
      • 使用super羡亩,指的是父類

        class Person():
          
          def talk(self):
              print('talk')
        
        class Student(Person):
          def talk(self):
             super().talk() 
             print('擴充函數(shù)')
        
        s = Student()
        s.talk()
        
        # > talk
        # > 擴充函數(shù)
        
    • MRO鉆石繼承\(zhòng)菱形繼承(繼承順序)

      • 子類永遠在父類前面

      • 根據(jù)括號內(nèi)繼承的順序存放

      • 繼承的多個類中,有共同的父類危融,子類只會繼承括號中第一個父類的父類

    • 單繼承

      • 單繼承隱患少畏铆,但不利于擴展功能

      • 子類如果沒有構(gòu)造函數(shù),則會查找父類的構(gòu)造函數(shù)吉殃,如果都沒有辞居,那么就一直向上查找。按照MRO順序

      class Person():
      
      def talk(self):
          print('talk')
      
      
      class Student(Person):
      
          def talk(self):
              super().talk()
              print('asdasd')
      
      print(Student.mro())
      
      # > [<class '__main__.Student'>, <class '__main__.Person'>, <class 'object'>]
      
      #可以看出蛋勺,Student類的MRO順序為Student瓦灶、Person、object
      
    • 多繼承

      • 擴展類的功能方便但隱患多

      • 繼承方式按照MRO順序

      class Animal():
        def sleep(self):
            print('sleep')
      
      class Person():
          def talk(self):
              print('talk')
      
      class Student(Person,Animal):
          pass
      
      s = Student()
      s.talk()
      s.sleep()
      
      # > talk
      # > sleep 
      
      print(Student.mro())
      
      #[<class '__main__.Student'>, <class '__main__.Person'>, <class '__main__.Animal'>, <class 'object'>]
      
      #可以看出繼承順序遵照MRO順序
      
    • Mixin設(shè)計模式

      • 我認為主要是為了避免繼承關(guān)系的混亂抱完,為了讓代碼可以進行更改的維護贼陶,已經(jīng)實現(xiàn)類中方便的功能增減

      • Mixin類中必須定義單一功能

      • 子類不繼承Mixin類,只是缺少某項功能乾蛤,但不影響子類的正常使用

      • Mxin功能不依賴子類進行實現(xiàn)

       class TalkMixin():
          def talk(self):
              print('talk')
       
       class EatMixin():
           def eat(self):
               print('eat')
       
       class SleepMixin():
           def sleep(self):
               print('sleep')
       
       class Person(TalkMixin,EatMixin,SleepMixin):
           pass
       
       p  = Person()
       p.talk()
       p.eat()
       p.sleep()
      
       # >talk
       # >eat
       # >sleep
      
  • 多態(tài)

    • 同一對象在不同狀態(tài)的不同功能

    • 注意:在Python中沒有對應(yīng)的語法

類的實例化

  • 方法:變量 = 類名()

訪問類

  • 檢查類中的所有成員每界,使用類名.__dict__

  • 訪問類的成員屬性,使用類名.屬性

  • 訪問類的成員函數(shù)家卖,使用類名.函數(shù)名()

類的函數(shù)

  • 魔法函數(shù)(不需要自己進行調(diào)用眨层,但滿足某些特定條件時,會自動調(diào)用)

    • __init__ 構(gòu)造方法

      • 在實例化類的時候可以向其中傳遞參數(shù)

      • 在將類實例化對象時上荡,會自動調(diào)用

      • 此函數(shù)也可以進行擴充

      class Person():
      
        def __init__(self,name,age):
            self.name = name
            self.age = age
        
        def say(self):
            print('My name is {0},I am {1} years old.'.format(self.name,self.age))
      
      p = Person('jack',24)
      p.say()
      # > My name is jack,I am 24 years old.
      p.name = 'bob'
      p.age = 18
      p.say()
      # > My name is bob,I am 18 years old.
      
    • __call__ 方法

      • 將對象當做函數(shù)執(zhí)行時調(diào)用
      class Person():
      
        def __init__(self,name,age):
            self.name = name
            self.age = age
      
        def __call__(self, *args, **kwargs):
            print('為什么要執(zhí)行我趴樱?')
      
      p = Person('jack',24)
      p()
      
      # > 為什么要執(zhí)行我馒闷?
      
    • __str__ 方法

      • 將對象打印時,輸出的方法
      class Person():
        def __str__(self):
            return '打印了一個Person類的實例'
      
      p = Person()
      print(p)
      # > 打印了一個Person類的實例
      
  • 實例方法

    • 也就是非綁定方法叁征,只有當類實例化后纳账,才可以使用的方法

    • 詳情參照self-非綁定方法

  • 靜態(tài)方法

    • 采用@staticmethod裝飾

    • 里面沒有self參數(shù)

    • 注意,這里和綁定方法有區(qū)別

      • 綁定方法捺疼,只能通過類名.方法名()調(diào)用疏虫,如果采用對象調(diào)用就會報錯

      • 靜態(tài)方法,既可以通過類來調(diào)用啤呼,也可以通過對象調(diào)用

    class Person():
    
    @staticmethod
    def say():
        print('say')
    
    p = Person()
    
    Person.say()
    # > say
    p.say()
    # > say
    
  • 類方法

    • 采用@classmethod裝飾

    • 不需要實例化就可以使用

    • 方法中傳入的是cls卧秘,也就是類對象

    class Person():
    
        @classmethod
        def say(cls):
            print('say')
    
    p = Person()
    
    Person.say()
    p.say() 
    
  • 總結(jié):無論是實例方法、靜態(tài)方法官扣、類方法都可以使用對象進行調(diào)用翅敌,但是實例方法必須實例化后才可以使用;靜態(tài)方法惕蹄、類方法可以直接用類名進行調(diào)用

  • 注意:靜態(tài)方法不是綁定方法

  • property

    • 主要是將對函數(shù)的訪問裝飾起來變?yōu)閷傩缘脑L問
    #例如蚯涮,我們需要定義一個Person類,但是需要對Person類中傳入的幾個屬性進行檢查卖陵,那么這時候property就派上用場了
    
    class Person():
       _name = 'Noname'
       _age = 0
        
    #此時遭顶,我們想對age的值進行檢查,不允許小于0
    #我們就可以定義一個property的裝飾器赶促,將函數(shù)偽裝為變量進行訪問
    
    • 調(diào)用Property裝飾器

      @property
      def age(self):
         print('調(diào)用get')
         return self._name
      
      @age.setter
      def age(self,value):
          print('調(diào)用set')
          if value > 0:
              self._age = value
          else:
              print('不允許負值')
      
      @age.deleter
      def age(self):
          print('調(diào)用del')
          del (self._age) 
      
      p = Person()
      p.age = -15
      
      # > 調(diào)用get
      # > 不允許負值
      
    • 調(diào)用property方法屬性 = property( fget, fset, fdel, doc)

       def get_age(self):
          print('調(diào)用get_age')
          return self._age
      
      def set_age(self,value):
          print('調(diào)用set_age')
          if value > 0:
              self._age = value
          else:
              print('不允許是負值')
      
      def del_age(self):
          print('調(diào)用del_age')
          del self._age
      
      age = property(get_age,set_age,del_age)
      
      p = Person()
      p.age = -15
      
      # > 調(diào)用get
      # > 不允許是負值
      
  • 類的描述符

    • 只要包含了__get__液肌、__set____del__三個方法中的一個就是描述符

    • 描述符的作用鸥滨,對類的屬性進行限制操作

    • __get__(self,instance,owner)方法和__set__(self, instance, value)方法

      class Dscrip():
      
        def __init__(self,property_name):
            self.property_name = property_name
      
        def __get__(self, instance, owner):
            print('調(diào)用了get方法')
            print('self:%s'%self)
            print('*'*20)
            print('instance:%s'%instance)
            print('*' * 20)
            print('owner:%s'%owner)
            print('-'*20)
      
        def __set__(self, instance, value):
            print('調(diào)用了set方法')
            print('self:%s' % self)
            print('*' * 20)
            print('instance:%s' % instance)
            print('*' * 20)
            print('value:%s'%value)
            print('-' * 20)
      
      class Person():
      
          name = 'Noname'
          age = Dscrip('age')
      
          def __init__(self,name,age,sorce):
              self.name = name
              self.age = age
              self.sorce =sorce
      
      p = Person('jack',24,60)
      p.age
      print('p:%s'%p) 
      
      # > 調(diào)用了set方法
      # > self:<__main__.Dscrip object at 0x000001F71AD78EF0>
      # > ********************
      # > instance:<__main__.Person object at 0x000001F71AD78F60>
      # > ********************
      # > value:24
      # > --------------------
      # > 調(diào)用了get方法
      # > self:<__main__.Dscrip object at 0x000001F71AD78EF0>
      # > ********************
      # > instance:<__main__.Person object at 0x000001F71AD78F60>
      # > ********************
      # > owner:<class '__main__.Person'>
      # > --------------------
      # > p:<__main__.Person object at 0x000001F71AD78F60>
      
      #在這里我們我們打印了get、set方法中的self谤祖、instance婿滓、owner的值
      
      #可以看出self 指的是一個Dscrip類,在Person類中粥喜,指的就是age變量
      #instance 和我們打印對象p的地址一致凸主,instance就是指的對象p
      #owner 是一個名為Person的類    
      #value 就是我們傳入對象p中age的值
      
    • 總結(jié):

      1. 在get和set方法中,self指的就是我們定義的類描述符的實例對象额湘,也就是類中的屬性

      2. 在get和set方法中卿吐,instance指的是包含了該實例對象的實例化類對象

      3. 在set方法中,value就是傳入該類對象的值

    • 使用類的描述符進行多個類屬性檢查

      #上面學習了如何使用property對屬性進行檢查
      #現(xiàn)在如果我想要將Person類中新定義一個sorce锋华,并且也進行檢查嗡官,此時如果使用property就會顯得異常繁雜
      #這時候就可以使用類的描述符了
      
      class Desc():
      
      def __init__(self, propertyname):
          self.propertyname = propertyname
      
      def __get__(self, instance, owner):
          if instance is None:
              return self
          return instance.__dict__[self.propertyname]
      
      def __set__(self, instance, value):
          if value < 0:
              print('不允許是負值')
          else:
              instance.__dict__[self.propertyname] = value
      
      def __del__(self):
         del self.propertyname
      
      
      class Person():
      
         age = Desc('age')
         sorce = Desc('sorce')
      
         def __init__(self, name, age, sorce):
             self.name = name
             self.age = age
             self.sorce = sorce
      
         p = Person('jack',18,60)
         p.sorce = -5
      
      # > 不允許是負值
      
      #這樣就檢查了兩個屬性age、sorce,從而避免了寫多個property
      
  • 類的常用函數(shù)

    • __dict__ : 獲取類和對象中的所有成員屬性

    • hasattr : 檢測某類中是否有某屬性

    • issubclass : 檢測某類是否是另一個類的子類

    • isinstance : 檢測某個對象是否是一個類的實例

    • getattr : 獲取某個對象的某個屬性值

    • __getattribute__ :獲取某個對象的某個屬性值

    • setattr : 設(shè)置某個對象的某個屬性值

    • delattr : 刪除某個對象的某個屬性

    • __slots__ : 在類的開頭定義一個slots的元組毯焕,實例化對象后衍腥,對象只能添加元組中定義的屬性

      • 如果子類中沒有定義slots,那么子類不存在slots限制

      • 如果子類中定義了slots,那么子類中slots的限制是子類和父類元組相加的限制

屬性和函數(shù)的動態(tài)綁定

  • 對類的實例對象進行動態(tài)綁定

    • 動態(tài)綁定屬性,使用對象.屬性 = 值綁定

      class Person():
        pass
      
      p = Person()
      p.name = 'jack'
      
    • 動態(tài)綁定函數(shù)婆咸,使用對象.方法名 = types.MethodType(方法名竹捉,對象)綁定

      import types
      
      class Person():
          pass
      
      def say():
          print('say')
      
      p = Person()
      p.say = types.MethodType(say, p)
      
    • 注意:此時綁定的方法只對綁定的該實例對象有效,如果重新定義一個對象尚骄,此方法就失效了

  • 對類進行動態(tài)綁定

    • 類.方法名 = 方法名綁定

      class Person():
          pass
      
      def say():
          print('say')
      
      Person.say = say
      
      Person.say()
      
    • 類名.方法名 = types.MethodType(方法块差,類名)綁定

      • 用法參照對象綁定

抽象類

  • 定義抽象類是為了讓其子類必須實現(xiàn)抽象類中的屬性或者方法,對子類進行規(guī)范化倔丈,設(shè)定子類的標準

  • 抽象類只能被繼承使用憾儒,不可以進行實例化

  • 定義抽象使用class 抽象類名(metaclass = abc.ABCMeta)

  • 定義抽象方法使用@abc.abstractclassmethod

import abc

class Man(metaclass= abc.ABCMeta):
   
    @abc.abstractmethod
    def say(self):
        pass

    @abc.abstractmethod
    def eat(self):
        pass


class Person(Man):
'''
    def say(self):
        pass
    def eat(self):
        pass
'''
  pass
p = Person()


# > TypeError: Can't instantiate abstract class Person with abstract methods eat, say
#如果子類中不定義抽象方法就會報錯

  • 包的結(jié)構(gòu)

    • __init__.py 包的標志文件

    • 模塊

    • 子包

  • 導(dǎo)入包

    • import 包名

    • import 包名.模塊名

    • 導(dǎo)入后可以使用__init__.py中定義的文件

      • __init__.py里如果定義了__all__,就只能使用__all__里面定義的內(nèi)容

      • __init__.py里如果沒有定義__all__乃沙,就可以使用全部文件

  • 模塊

    • 定義模塊的規(guī)范

      • 函數(shù)起趾,單一功能

      • 測試代碼

      • if __name__ = 'main': 代表此模塊作為主線程執(zhí)行時就執(zhí)行以下內(nèi)容

    • 導(dǎo)入模塊

      • import 模塊名

      • from 模塊名 import 類名

      • import 模塊名 as 別名

    • 模塊、包的查找路徑

      • 默認路徑警儒,可使用sys.path查看

      • 添加路徑训裆,sys.path.append(),也就是向列表中添加一個新元素

    • 模塊的加載順序

      • 內(nèi)存中已經(jīng)加載好的模塊

      • Python中內(nèi)置的模塊

      • 按順序查找sys.path中的內(nèi)容

異常

  • 異常是一個類蜀铲,可以進行處理和使用

  • 常見異常錯誤類

    • AssertErro 斷言語句失敗

    • AttributeErro 嘗試方問未知的對象屬性

    • FloatingPointErro 浮點計算錯誤

    • ImportErro 導(dǎo)入模塊失敗

    • IndexErro 下標引索值超出序列的范圍

    • KeyErro 字典中查找一個不存在的關(guān)鍵字

    • NameErro 嘗試訪問一個不存在的變量

    • RuntimeErro 運行錯誤

    • OSErro 操作系統(tǒng)產(chǎn)生異常

    • SynataxErro 語法錯誤

    • IndentationErro 縮進錯誤

    • TypeErro 不同類型間的無效操作

  • 異常處理

     try:
        問題語句
     except 異常類 as e:  #將異常類實例化為e
        print(e)
     else:
        不出錯執(zhí)行語句
     finally:
        無論是否出錯都執(zhí)行的語句
    
  • 手動引發(fā)異常

    raise 異常類
    

    注意:推薦使用自定義異常边琉,并且標注清楚。方便別人或者自己進行查看和快速定位

  • 自定義異常類

    • 自定義異常必須是系統(tǒng)異常的子類

    • 拋出異常時的文字提示

    • 異常發(fā)生的行數(shù)

常用模塊

calendar 日歷模塊

  • calendar() 以字符串形式返回某年的日歷

  • isleap() 判斷某年是否是閏年

  • leapdays() 獲取指定年份之間的閏年個數(shù)

  • month() 以字符串形式返回某年某月的日歷

  • monthrange() 獲取某年某月第一天是周幾和某月的天數(shù)记劝,返回的是一個元組

  • monthcalendar() 返回某年某月以二維列表組成的矩陣变姨,其中每周組成一個列表

  • weekday() 獲取某年某月某日是周幾

import calendar

c = calendar.calendar(2018)
print(c)

                                  2018

   January                   February                   March
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
1  2  3  4  5  6  7                1  2  3  4                1  2  3  4
8  9 10 11 12 13 14       5  6  7  8  9 10 11       5  6  7  8  9 10 11
15 16 17 18 19 20 21      12 13 14 15 16 17 18      12 13 14 15 16 17 18
22 23 24 25 26 27 28      19 20 21 22 23 24 25      19 20 21 22 23 24 25
29 30 31                  26 27 28                  26 27 28 29 30 31

    April                      May                       June
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
                1          1  2  3  4  5  6                   1  2  3
2  3  4  5  6  7  8       7  8  9 10 11 12 13       4  5  6  7  8  9 10
9 10 11 12 13 14 15      14 15 16 17 18 19 20      11 12 13 14 15 16 17
16 17 18 19 20 21 22      21 22 23 24 25 26 27      18 19 20 21 22 23 24
23 24 25 26 27 28 29      28 29 30 31               25 26 27 28 29 30
30

     July                     August                  September
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
                1             1  2  3  4  5                      1  2
2  3  4  5  6  7  8       6  7  8  9 10 11 12       3  4  5  6  7  8  9
9 10 11 12 13 14 15      13 14 15 16 17 18 19      10 11 12 13 14 15 16
16 17 18 19 20 21 22      20 21 22 23 24 25 26      17 18 19 20 21 22 23
23 24 25 26 27 28 29      27 28 29 30 31            24 25 26 27 28 29 30
30 31

   October                   November                  December
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
1  2  3  4  5  6  7                1  2  3  4                      1  2
8  9 10 11 12 13 14       5  6  7  8  9 10 11       3  4  5  6  7  8  9
15 16 17 18 19 20 21      12 13 14 15 16 17 18      10 11 12 13 14 15 16
22 23 24 25 26 27 28      19 20 21 22 23 24 25      17 18 19 20 21 22 23
29 30 31                  26 27 28 29 30            24 25 26 27 28 29 30
                                                 31


 print(calendar.isleap(2018))   
    
 # > False
 
 print(calendar.leapdays(1990,2018))
 
 # > 7
 
 m = calendar.month(2018,8)
 print(m)
 
 # >     August 2018
     Mo Tu We Th Fr Sa Su
            1  2  3  4  5
      6  7  8  9 10 11 12
     13 14 15 16 17 18 19
     20 21 22 23 24 25 26
     27 28 29 30 31
 
 week,day = calendar.monthrange(2018,8)
 print(week)
 print(day)
 
 # > 2
 # > 31
 
 
 list = calendar.monthcalendar(2018,8)
 for i in list:
     print(i)
     
 # > [0, 0, 1, 2, 3, 4, 5]
 # > [6, 7, 8, 9, 10, 11, 12]
 # > [13, 14, 15, 16, 17, 18, 19]
 # > [20, 21, 22, 23, 24, 25, 26]
 # > [27, 28, 29, 30, 31, 0, 0]
 
 print(calendar.weekday(2018,8,7))
 
 # > 1
 

time 時間模塊

  • time() 指一個時間戳,是從1970年1月1日0時到至今所經(jīng)歷的秒數(shù)

      import time 
    
      print(time.time())
      
      # > 1533604231.9603899
    
  • 時間元組厌丑,是一個包含時間內(nèi)容的元組定欧,組成由(年,月怒竿,日砍鸠,時,分耕驰,秒爷辱,周幾,年的第幾天朦肘,夏令時)

  • localtime() 獲取當前時間的元組

      import time
      
      print(time.localtime())
      
      # > time.struct_time(tm_year=2018, tm_mon=8, tm_mday=7, tm_hour=9, tm_min=14, tm_sec=51, tm_wday=1, tm_yday=219, tm_isdst=0)
      
    
  • timezone 標準時區(qū)與當前時區(qū)相差的秒數(shù)

    import time
    
    print(time.timezone)
    
    # > -28800
    #中國是東8區(qū)饭弓,相比于國際時間,要快8小時媒抠,28800/60/60 = 8
    
  • asctime() 返回系統(tǒng)格式化后的時間

    import time
    
    print(time.asctime())
    
    # > Tue Aug  7 09:20:40 2018
    
  • ctime() 返回系統(tǒng)格式化后的時間

    import time
    
    print(time.ctime)
    
    # > Tue Aug  7 09:21:37 2018
    
  • maketime() 將時間元組變成時間戳

    import time
    
    t = time.localtime()
    s = time.mktime(t)
    print(s)
    
    # > 1533605096.0
    
  • sleep() 使程序休眠指定秒數(shù)后繼續(xù)執(zhí)行

    import time
    
    for i in range(1,11):
        time.sleep(1)
        print(i)
    
    # > 1
    # > 2
    # > ....
    
  • strftime() 自定義格式化時間弟断,作用于時間元組

    • %Y 完整年份

    • %m 月份

    • %d 每月中的第幾天

    • %H 24小時制

    • %M 分鐘 60

    • %S 秒 60

    import time
    
    t = time.localtime()
    
    st = time.strftime('%Y-%m-%d %H:%M:%S',t)
    
    print(st)
    
    # > 2018-08-07 09:41:23
    

    注意:

    • print(time.strftime('%Y年%m月%d日 %H時%M分%S秒',time.localtime()))

    • 同樣方法,在windows下報錯UnicodeEncodeError: 'locale' codec can't encode character '\u5e74' in position 2: Illegal byte sequence

    • 在ubuntu下正常執(zhí)行领舰,返回2018年08月06日 20時28分31秒

  • strptime() 將時間字符串格式化為時間元組

    import time
    
    st = '2018-8-7 12:00:00'
    
    t = time.strptime(st,'%Y-%m-%d %H:%M:%S')
    
    print(t)    
    
    
    # > time.struct_time(tm_year=2018, tm_mon=8, tm_mday=7, tm_hour=12, tm_min=0, tm_sec=0, tm_wday=1, tm_yday=219, tm_isdst=-1)        
    

datetime 理想的日期和時間模塊

  • date類 提供一個理想的日期

    • year 屬性

    • month 屬性

    • day 屬性

    • today() 返回當前日期

    • fromtimestamp() 從一個時間戳中獲得日期

    • strftime() 自定義格式化日期

    import datetime
    
    dt = datetime.datetime(2018,8,7)   #將2018.8.7實例化為datetime類
    
    print(dt.year)
    # > 2018
    
    print(dt.month)
    # > 8
    
    print(dt.day)
    # > 7
    
    dt = datetime.datetime.today()
    print(dt)
    # > 2018-08-07 13:49:04.943500
      
    import time
    
    t = time.time()   #獲取當前時間的時間戳
    dt = datetime.datetime.fromtimestamp(t)
    print(dt)
    # > 2018-08-07 13:51:44.969500
    
    print(dt.strftime('%Y.%m.%d'))
    # > 2018.08.07
    
  • datetime類 提供理想的日期和時間

    • year 屬性

    • month 屬性

    • day 屬性

    • hour 屬性

    • minute 屬性

    • second 屬性

    • mircosecond 屬性

    • today() 獲取當前日期和時間

    • fromtimestamp() 從時間戳中獲取日期和時間

  • timedelta類 提供日期和時間的計算

    • 可以通過days = 天數(shù) 夫嗓, hours = 小時數(shù) 迟螺, minutes = 分鐘數(shù)進行實例化

    • timedelta類 + date類或者datetime類 = date類或者datetime類

    • date類或者datetime類 - date類或者datetime類 = timedelta類

    import  datetime
    
    dt1 = datetime.date(2018,6,15)
    dt2 = datetime.date(2018,8,7)
    td = dt2 - dt1
    print(td)
    # > 53 days, 0:00:00
    print(type(td))
    # > <class 'datetime.timedelta'>
    
    
    dt3 = datetime.datetime(2018,6,15,8,30,15)
    dt4 = datetime.datetime(2018,8,7,14,4)
    td = dt4 - dt3 
    print(td)
    # > 53 days, 5:33:45
    
    
    td = datetime.timedelta(days=10,hours=15,minutes=30)
    dt = datetime.datetime.now()
    temp = dt + td
    print(type(temp))
    # > <class 'datetime.datetime'>
    print(temp)
    # > 2018-08-18 05:37:51.464770
    

timeit 代碼時間測試模塊

  • timeit(smlt = 測試代碼,setup = 運行環(huán)境 舍咖,number = 重復(fù)次數(shù)) 測試代碼時間

     #現(xiàn)在我們測試一下列表生成式和循環(huán)加入列表中的兩個代碼誰執(zhí)行的快
     import timeit
     
     st1 = '[i for i in range(1000)]'
     
     st2 = '''
     list = []
     for i in range(1000):
         list.append(i)
     '''
     
     t1 = timeit.timeit(stmt = st1,number = 100000)
     
     t2 = timeit.timeit(stmt = st2,number = 100000)
     
     print(t1)
     # > 3.6470414876165864
     
     print(t2)
     # > 9.188953135455993
     
     
     
     #當測試帶參數(shù)的函數(shù)的寫法
    import timeit
    
    c = '''
    def func(num):
        for i in range(num):
            print('repeat for {}'.format(i))
    '''
    
    t = timeit.timeit(stmt='func(num)', setup = c + 'num=2', number=100000)
    print(t)
    
    # > repeat for 1
    # > repeat for 0
    # > ....
    # > 1.1565270608769294
    

os 系統(tǒng)操作模塊

  • 絕對路徑 總是從根目錄上開始

    D:\360安全瀏覽器下載\chromeinstall-8u151.exe

  • 相對路徑 以當前所在工作目錄開始

    \360安全瀏覽器下載\chromeinstall-8u151.exe

    • os.curdir 當前目錄,用‘ . ’表示

    • os.pardir 父親路徑矩父,用‘ .. ’表示

    • os.sep 系統(tǒng)分隔符

      • windows下用‘ \ ’

      • linux下用‘ / ’

    • os.linesep 系統(tǒng)的換行符號

      • windows下用‘ \r\n ’

      • linux下用‘ \n ’

    • os.name 系統(tǒng)名稱

      • windows下用‘ nt ’

      • linux下用‘ posix ’

  • 函數(shù)

    • getcwd() 返回當前工作目錄

    • chdir() 改變工作目錄

    • listdir() 顯示路徑下所有文件和文件夾,返回一個列表

    • makedirs() 創(chuàng)建一個空文件夾

    • rename() 重命名文件

    • removedirs() 刪除空文件夾

    • system() 運行系統(tǒng)shell命令

    • getenv() 獲取當前系統(tǒng)環(huán)境變量值

    • putenv() 添加環(huán)境變量

    • exit() 退出當前程序

  • path類中的函數(shù)

    • abspath() 將路徑轉(zhuǎn)化為絕對路徑

    • basename() 獲取路徑中的文件名部分

    • dirname() 返回路徑中的文件夾部分

    • split() 將路徑切割為文件夾和文件名組成的元組

    • splittext() 將路徑切割為文件和后綴名組成的元組

    • join() 將兩個路徑拼接成一個路徑

    • exists() 判斷文件或文件夾是否存在

    • isfile() 判斷是否為文件

    • isdir() 判斷是否為文件夾

    • getsize() 返回文件大小

    • getatime() 返回文件或文件夾最后讀取時間

    • ghetmtime() 返回文件或文件夾最后修改時間

shutil 文件操作模塊

  • copy() 復(fù)制文件排霉,還可以將文件重命名

  • copy2() 盡可能保留元數(shù)據(jù)的情況下復(fù)制文件

  • copyfile() 講一個文件里的內(nèi)容復(fù)制到另一個文件中

  • copytree() 復(fù)制文件夾里所有內(nèi)容

  • move() 移動文件或文件夾

  • rmtree() 刪除文件或文件夾下的所有文件

  • make_archive(壓縮后的名稱窍株,壓縮類型,需要壓縮的文件) 壓縮文件攻柠,返回壓縮文件的路徑

  • unpack_archive(壓縮包路徑球订,解包之后的路徑) 解壓文件

collections 模塊

  • namedtuple類

    • 是一個可以命名的元組類型

    • 定義方式類名 = collections.namedtuple(類類型,屬性組成的列表)

     import collections
     
     Point = collections.namedtuple('Point',['x','y'])
     
     p = Point(15,22)
     
     print(p)     
     
     # > Point(x=15, y=22)   
    
  • deque類

    • 解決頻繁插入瑰钮、刪除帶來的效率問題

    • 定義方式:對象 = collections.deque(列表)

    import collections
    
    d = collections.deque([1,2,3,4,5])
    
    d.appendleft(10)
    # > deque([10, 1, 2, 3, 4, 5])
    
  • defaultdict類

    • 當讀取一個不存在的key時冒滩,返回一個默認值

    • 定義方式:對象 = collections.defaultdict(帶有返回值的函數(shù))

      import collections
      
      def pr():
          return '默認值'
      
      d = collections.defaultdict(pr)
      
      d['a'] = 1
      d['b'] = 2
      
      print(d)
      
      # > defaultdict(<function pr at 0x028AB6F0>, {'a': 1, 'b': 2})
      
      print(d['dd'])
      
      # > 默認值
      
  • Counter類

    • 主要是統(tǒng)計元素在迭代對象中出現(xiàn)的次數(shù),以元素:次數(shù)的字典形式返回
    import collections
    
    s = 'afjkasdhfklashgkjash'
    
    dict = collections.Counter(s)
    
    print(dict) 
    
    # > Counter({'a': 4, 'k': 3, 's': 3, 'h': 3, 'f': 2, 'j': 2, 'd': 1, 'l': 1, 'g': 1})
    
    import collections
    
    s = ['ss','jack','alice','bob','jack','jack','jack']
    
    dict = collections.Counter(s)
    
    print(dict)  
    
    # > Counter({'jack': 4, 'ss': 1, 'alice': 1, 'bob': 1})  
    

pickle 持久化模塊

  • dump(數(shù)據(jù),句柄)浪谴,將數(shù)據(jù)持久化到文件

    import pickle
    
    file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
    
    l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    with open(file, 'wb') as f:
        pickle.dump(l,f)
        
    #將數(shù)據(jù)以二進制方式寫入到b.txt文件中
    
  • load(句柄)开睡,將持久化的數(shù)據(jù)提取到程序中

    import pickle
    
    file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
    
    with open(file, 'rb') as f:
        l = pickle.load(f)
    print(l)
    
    # > [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    #將b.txt文件中儲存的數(shù)據(jù)讀取到程序中
    

shelve 持久化模塊

  • 將數(shù)據(jù)以字典的形式寫入文件中

  • shelve只能允許一個句柄進行寫入,但可以允許多個句柄進行讀取

  • writeback = Ture在關(guān)閉文件時苟耻,檢查更改篇恒,并將數(shù)據(jù)寫入文件

import shelve

file = r'C:\Users\wudi.HAPMMAGNA\Desktop\a'

sv = shelve.open(file,writeback= True)

sv['one'] = 1
sv['two'] = 2
sv['three'] = 3

sv.close()

# 此時桌面上出現(xiàn)了三個文件,為a.dat凶杖、a.bak胁艰、a.dir
  • 讀取文件
import shelve

file = r'C:\Users\wudi.HAPMMAGNA\Desktop\a'

sv = shelve.open(file)

print(sv['one'])

sv.close()

# > 1

IO文件模塊

  • 文件是一種長久保存信息數(shù)據(jù)的集合,保存在磁盤上

  • 文件一旦被打開智蝠,就需要進行關(guān)閉操作腾么,否則可能造成文件信息的丟失

  • 常用操作

    • 讀寫模式

      • r 只讀,指針在文件開頭

      • w 只寫寻咒,指針在文件開頭

      • x 創(chuàng)建文件并只進行寫入哮翘,如果文件已經(jīng)存在則會報錯,指針在文件開頭

      • a 追加寫入毛秘,指針在文件末尾

      • b 以二進制方式

      • t 以文本方式

      • + 讀寫

    • open(文件地址,讀寫模式) 打開文件阻课、close() 關(guān)閉文件

      file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
      f = open(file)
      f.close()
      
    • with 語句

      • 使用上下文管理協(xié)議技術(shù)

      • 自動關(guān)閉已經(jīng)不再使用的文件

      • 推薦一定文件讀寫一定要使用with語句

      file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
      with open(file,'wb') as f:
        pass
      
    • 讀取操作

      • read(字符數(shù)) 如果不使用字符數(shù)叫挟,那么read將會將所有字符讀取出來,如果指定字符限煞,就按照指定字符數(shù)進行讀取

      • readline() 按行讀取文件內(nèi)容

      • list(句柄) 將文件所有內(nèi)容讀取出來抹恳,以列表形式進行保存

      • 使用while 數(shù)據(jù)進行讀取,當數(shù)據(jù)不為空時署驻,就會一直循環(huán)下去奋献,如果數(shù)據(jù)為空時健霹,當前循環(huán)就會停止

      # b.txt中有以下內(nèi)容
      # 關(guān)雎
      # 關(guān)關(guān)雎鳩,在河之洲瓶蚂。窈窕淑女糖埋,君子好逑。
      # 參差荇菜窃这,左右流之瞳别。窈窕淑女,寤寐求之杭攻。
      # 求之不得祟敛,寤寐思服。悠哉悠哉兆解,輾轉(zhuǎn)反側(cè)馆铁。
      # 參差荇菜,左右采之锅睛。窈窕淑女埠巨,琴瑟友之。
      # 參差荇菜乖订,左右芼之。窈窕淑女具练,鐘鼓樂之乍构。
      
      
      
      file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
      with open(file, 'r') as f:
          data = f.read(1024)
          while data:
              print(data)
              data = f.read(1024)
        
      # > 關(guān)雎
      # > 關(guān)關(guān)雎鳩,在河之洲扛点。窈窕淑女哥遮,君子好逑。
      # > 參差荇菜陵究,左右流之眠饮。窈窕淑女,寤寐求之铜邮。
      # > 求之不得仪召,寤寐思服。悠哉悠哉松蒜,輾轉(zhuǎn)反側(cè)扔茅。
      # > 參差荇菜,左右采之秸苗。窈窕淑女召娜,琴瑟友之。
      # > 參差荇菜惊楼,左右芼之玖瘸。窈窕淑女腹鹉,鐘鼓樂之哮肚。
      
       with open(file, 'r') as f:
          data = f.readline()
          while data:
              print(data)
              data = f.readline()  
            
      # > 關(guān)雎
      # > 
      # > 關(guān)關(guān)雎鳩岛抄,在河之洲挨队。窈窕淑女,君子好逑屯断。
      # > 
      # > 參差荇菜文虏,左右流之。窈窕淑女殖演,寤寐求之氧秘。
      # > 
      # > 求之不得,寤寐思服趴久。悠哉悠哉丸相,輾轉(zhuǎn)反側(cè)。
      # > 
      # > 參差荇菜彼棍,左右采之灭忠。窈窕淑女,琴瑟友之座硕。
      # > 
      # > 參差荇菜弛作,左右芼之。窈窕淑女华匾,鐘鼓樂之映琳。
      
      with open(file,'r') as f:
        list3 = list(f)
      for i in list3:
        print(i) 
      
      # > 結(jié)果同readline() ,為什么會出現(xiàn)這種情況蜘拉? 使用read時萨西,中間沒有隔行,而使用其他時就會有隔行呢旭旭?
      #我們來做個試驗谎脯,將所有讀取到的內(nèi)容添加到列表,看他們在列表中是如何組成的
      file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
      list1 = []
      list2 = []
      
      with open(file, 'r') as f:
          data = f.read(1024)
          while data:
              list1.append(data)
              data = f.read(1024)
      
      
      with open(file, 'r') as f:
          data = f.readline()
          while data:
              list2.append(data)
              data = f.readline()
      
      with open(file,'r') as f:
          list3 = list(f)
      
      print(list1)
      print('@'*30)
      print(list2)
      print('@'*30)
      print(list3)
      
      # > ['關(guān)雎\n關(guān)關(guān)雎鳩持寄,在河之洲源梭。窈窕淑女,君子好逑稍味。\n參差荇菜咸产,左右流之。窈窕淑女仲闽,寤寐求之。\n求之不得僵朗,寤寐思服赖欣。悠哉悠哉屑彻,輾轉(zhuǎn)反側(cè)。\n參差荇菜顶吮,左右采之社牲。窈窕淑女,琴瑟友之悴了。\n參差荇菜搏恤,左右芼之。窈窕淑女湃交,鐘鼓樂之熟空。']
      # > @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
      # > ['關(guān)雎\n', '關(guān)關(guān)雎鳩,在河之洲搞莺。窈窕淑女息罗,君子好逑。\n', '參差荇菜才沧,左右流之迈喉。窈窕淑女,寤寐求之温圆。\n', '求之不得挨摸,寤寐思服。悠哉悠哉岁歉,輾轉(zhuǎn)反側(cè)得运。\n', '參差荇菜,左右采之刨裆。窈窕淑女澈圈,琴瑟友之。\n', '參差荇菜帆啃,左右芼之瞬女。窈窕淑女,鐘鼓樂之努潘。']
      # > @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
      # > ['關(guān)雎\n', '關(guān)關(guān)雎鳩诽偷,在河之洲。窈窕淑女疯坤,君子好逑报慕。\n', '參差荇菜,左右流之压怠。窈窕淑女眠冈,寤寐求之。\n', '求之不得,寤寐思服蜗顽。悠哉悠哉布卡,輾轉(zhuǎn)反側(cè)。\n', '參差荇菜雇盖,左右采之忿等。窈窕淑女,琴瑟友之崔挖。\n', '參差荇菜贸街,左右芼之。窈窕淑女狸相,鐘鼓樂之薛匪。']
      
      # 可以看出,read中整個列表只有一個元素卷哩,也就是遇到'\n'時會自動進行換行蛋辈,而在其他函數(shù)中,列表中有多個元素将谊,遇到n時會換一次行冷溶,而單次打印內(nèi)容時也會換一次行。
      
    • 寫入操作

      • write(數(shù)據(jù)) 將單次數(shù)據(jù)寫入文件中

      • writelines(數(shù)據(jù)序列) 將一個可迭代的數(shù)據(jù)序列按順序?qū)懭胛募?/p>

      data = '我是數(shù)據(jù)'
      with open(file,'w') as f:
        f.write(data)
      
      # > 文件中的內(nèi)容是我是數(shù)據(jù)
      
      data = ['關(guān)關(guān)雎鳩尊浓,在河之洲逞频。窈窕淑女,君子好逑栋齿。\n', '參差荇菜苗胀,左右流之。窈窕淑女瓦堵,寤寐求之基协。\n']
      with open(file,'w') as f:
        f.writelines(data)
      
      # > 關(guān)關(guān)雎鳩,在河之洲菇用。窈窕淑女澜驮,君子好逑。
      # > 參差荇菜惋鸥,左右流之杂穷。窈窕淑女,寤寐求之卦绣。
      
    • 指針操作 seek(指針偏移量耐量,參照物)

      • 指針偏移量

        • 以字節(jié)byte為單位,和read函數(shù)有巨大區(qū)別滤港,read是字符為單位

        • 不同編碼中漢字所占的字節(jié)數(shù)有所不同

      • 參照物

        • 0 表示在文件開頭

        • 1 表示指針當前位置

        • 2 表示在文件末尾

    # b.txt中有以下內(nèi)容:阿富汗喀什的法律可攻可受的復(fù)合弓  
    
    #注意:需要保存為utf-8編碼
        
    # 如果我們需要讀取文件末尾兩個字符廊蜒,就需要
    
    file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
    with open(file, 'rb') as f:
        f.seek(-6,2) 
        data = f.read(1024)
        while data:
            print(data.decode())
            data = f.read(1024)
    
    # > 合弓
    
    # seek中的含義為以文件末尾為指針位置,向左移動6個字節(jié)的位置,然后向后讀取
    

logging 日志模塊

  • 主要是將文件運行的信息保存在磁盤文件上

  • logging不要頻繁進行IO讀寫劲藐,運行過程中八堡,只需要保存重要信息和錯誤信息

  • 作用

    • 程序調(diào)試

    • 了解軟件運行狀況

    • 分析定位問題

  • 日志應(yīng)包含信息

    • 時間

    • 地點

    • 級別

    • 內(nèi)容

  • 日志級別

    • DEBUG

    • INFO

    • WARNING

    • ERROR

    • CRITICAL

  • 直接使用系統(tǒng)定制的logging

    • logging.debug(msg) 創(chuàng)建一條debug日志

    • logging. info(msg) 創(chuàng)建一條info日志

    • logging.warning(msg) 創(chuàng)建一條warning日志

    • logging.error(msg) 創(chuàng)建一條error日志

    • logging.critical(msg) 創(chuàng)建一條critical日志

    • logging.basicConfig(file=文件名,format=格式化字符串聘芜,level=輸出的最低級別) 配置log

      • level對照以上日志級別作為參數(shù),默認為warning

      • format的相應(yīng)參數(shù)

        • %(asctime)s 時間和日期

        • %(levelname)s 日志級別

        • %(message)s 日志內(nèi)容

        • %(filename)s 程序名

        • %(pathname)s 程序路徑

        • %(funcName)s 當前函數(shù)

        • %(lineno)d 當前行數(shù)

        • %(thread)s 當前線程ID

        • %(ThreadName)s 當前線程名

        • %(process)s 當前進程ID

        import logging
        
        logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s',level=logging.DEBUG)
        
        logging.debug('我是一條DEBUG日志')
      
        # > 2018-08-10 15:10:09,089 - DEBUG - 我是一條DEBUG日志
      
  • 使用四大組件進行定制

    • Logger類 日志器 產(chǎn)生日志

      • getLogger(日志器名稱) 創(chuàng)建一個日志器對象

      • setlevel(日志級別) 設(shè)置處理日志的最低級別

      • addHandler(處理器對象),removeHandler() 添加、刪除一個處理器對象

      • addFilter(過濾器對象)缝龄,removeFilter() 添加汰现、刪除一個過濾器對象

      • debug()、info()叔壤、.....創(chuàng)建一條日志

    • Filter類 過濾器 存疑

      • 可被Logger瞎饲、Handler使用
    • Formatter類 格式器 格式化輸出日志

      • 可以直接實例化使用

      • Formatter(fmt,datefmt)

        • fmt 格式化字符串

        • datefmt 格式化時間和日期字符串

    • Handler類 處理器 將日志輸出到相應(yīng)位置

      • Handler是基類,不能直接使用炼绘,需要使用其子類

        • StreamHandler() 向控制臺輸出

        • FileHandler(file=文件) 向文件寫入日志

        • handlers.RotatingHandler(file=文件嗅战,maxBytes=大小,backupCount=日志保留個數(shù)) 向文件寫入日志俺亮,如果超過指定大小驮捍,則新建日志文件

        • handlers.TimeRotatingFileHandler(file=文件, when=時間脚曾, interval=間隔东且, backupCount=保留日志個數(shù)) 向文件寫入日志,按時間進行分割

          • when的參數(shù)

            • 'S'

            • 'M'

            • 'H'
              - 'D'
              - 'midnight' 每日午夜12:00
              - 'W0-W6' 周一 ~ 周日

        • handlers.HTTPHandler 發(fā)送給一個HTTP服務(wù)器

        • handlers.SMTPHandler 發(fā)送給一個指定的郵件地址

    • setlevel(日志級別) 設(shè)置最低需要寫入日志的級別

    • setFormatter(格式器對象) 添加一個格式器對象本讥,用來控制輸出的日志格式

    • addFilter(過濾器對象)珊泳、removeFilter()

    #定義記錄兩個日志,每天記錄一次
    #一個日志all.log拷沸,所有級別的日志都被記錄色查,格式為“日期和時間 - 級別 - 內(nèi)容”
    #一個日志error.log,error以上的的日志都被記錄撞芍,格式為“日期和時間 - 級別 - 文件名【:行號】 - 內(nèi)容”
    
    
    import logging
    import logging.handlers
    import datetime
    
    #定義Logger
    logger = logging.getLogger('mylogger')
    logger.setLevel(logging.DEBUG)
    
    #定義debughandler格式器
    formatter1 = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    
    #定義記錄所有日志的debughandler
    file1 = r'C:\Users\wudi.HAPMMAGNA\Desktop\all.log'
    debughandler = logging.handlers.TimedRotatingFileHandler(file1, when='midnight', interval=1, backupCount=3000)
    debughandler.setFormatter(formatter1)
    
    #定義errorhandler格式器
    formatter2 = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s[:%(lineno)d] - %(message)s')
    
    #定義記錄error以上級別的日志errorhandler
    file2 = r'C:\Users\wudi.HAPMMAGNA\Desktop\error.log'
    errorhandler = logging.handlers.TimedRotatingFileHandler(file2, when='midnight', interval=1, backupCount=3000)
    errorhandler.setFormatter(formatter2)
    errorhandler.setLevel(logging.ERROR)
    
    #為日志器添加處理器
    logger.addHandler(debughandler)
    logger.addHandler(errorhandler)
    
    
    logger.debug('我是debug日志')
    logger.info('我是info日志')
    logger.warning('我是warning日志')
    logger.error('我是error日志')
    logger.critical('我是critical日志')
    
    • 總結(jié)思路

      • 實例化一個Logger對象

      • 依照不同的日志文件實例化不同處理方式的Handler

      • 給每個Hadnler對象添加實例化的Formatter格式器對象

      • 輸出

queue 同步隊列模塊

  • Queue類 先進先出隊列

  • LifoQueue 后進先出隊列

  • PriorityQueue 優(yōu)先級隊列

  • 常用方法

    • qsize() 返回隊列長度

    • put() 將數(shù)據(jù)放入隊列中

    • get() 從隊列中取出數(shù)據(jù),并刪除

    • empty() 檢測隊列是否為空

    • full() 檢測隊列是否已滿

import queue

que = queue.Queue()
for i in range(1,11):
    que.put(i)

print(que.get())

# > 1

print(que.empty())

# > False

threading 多線程模塊

  • 首先明確幾個概念

    • 阻塞: 程序在等待某個操作完成期間,自身無法干其他事情,處于掛起狀態(tài)

    • 非阻塞: 程序在等待某個操作完成期間,自身不被阻塞,還可以繼續(xù)干其他事情,是為了提高程序的整體執(zhí)行效率,讓程序在IO過程中執(zhí)行其他計算任務(wù)

    • 并行: 利用富余的資源(多核)加速完成某個任務(wù) 多進程

    • 并發(fā): 利用有限的資源使多個任務(wù)被實時或者近似實時的執(zhí)行,讓多個任務(wù)都有機會被盡快執(zhí)行,不一定能加快進度 多線程

    • 異步: 不同程序單元執(zhí)行過程中不需要通信也能完成某個任務(wù),高效的組織非阻塞任務(wù)的方式,異步意味著無序

    • 同步: 不同程序單元為了完成某個任務(wù),在執(zhí)行過程中需要靠通信進行步調(diào)一致,同步就意味著有序

  • 定義線程的兩種方式

    • 通過傳入函數(shù)來啟動線程

      import threading    
      
      def func():
         while True:
            pass
      
      t = threading.Thread(target=func,args=())
      t.setDaemon(True)
      t.start()
      print(threading.enumerate())
      # > [<_MainThread(MainThread, started 7176)>, <Thread(Thread-1, started daemon 9260)>]
      # > 可以看出開啟了兩個線程,一個是主線程,另一個是子線程
      
    • 通過繼承threading.Thread類,重寫其init和run方法定義

      import threading
      import time
      
      
      class myThread(threading.Thread):
      
            def __init__(self):
                super().__init__()
          
            def run(self):
                print('{0} say hello'.format(self.name))
                time.sleep(5)
      
      for i in range(5):
            t = myThread()
            t.start()
            t.join()
      
      print('over')
      
      # > Thread-1 say hello
      # > Thread-2 say hello
      # > Thread-3 say hello
      # > Thread-4 say hello
      # > Thread-5 say hello
      # > over
      
  • 注意: 主線程執(zhí)行完畢后,子線程并不會關(guān)閉,而是會等到子線程中的函數(shù)執(zhí)行完畢后再關(guān)閉

  • 線程常用的方法

    • start() 啟動線程
    • join() 阻塞線程,等待該線程執(zhí)行完畢
    • active_Count() 返回當前活動的線程數(shù)量
    • current_thread() 返回當前正在活動的線程
    • enumerate() 返回當前活動的線程對象列表
  • 守護線程

    • 當A線程是B線程的守護線程時,一旦B關(guān)閉,A線程不論是否已經(jīng)完成,都會隨著B線程而關(guān)閉

    • setDaemon(True) 設(shè)置一個線程為守護線程

  • GIL 全局解釋器鎖

    • 在多線程中,每個線程都會在執(zhí)行之前申請一把鎖,這把鎖就是GIL,但是這個鎖只有一把,也就是只有等一個線程釋放鎖之后,其他線程才能申請這個鎖,同一時間,線程只能并發(fā),卻不能并行.
  • 多線程安全

    • 在多線程中,對變量的讀操作,并不會影響線程安全

    • 在多線程中,對變量的寫操作,很有可能會引起線程安全的問題

    • 不安全線程的例子

      import threading
      import time
      
      num = 0
      loop = 1000000
      
      def funa(loop):
          global num
          for i in range(loop):
              num += 1
          print('funa done')
      
      def funb(loop):
          global num
          for i in range(loop):
              num -= 1
          print('funb done')
      
      t1 = threading.Thread(target=funa,args=(loop,))
      t2 = threading.Thread(target=funb,args=(loop,))
      
      t1.start()
      t2.start()
      
      time.sleep(2)
      
      print(num)
      
      # > 281811
      # > 結(jié)果并不是固定的,每次執(zhí)行都會產(chǎn)生不同的結(jié)果
      
    • 這是因為有可能在線程中,多個線程可能在同時更改這個變量,造成結(jié)果錯誤

    • 為了解決共享變量沖突的問題

    • Lock 類

      • 只能執(zhí)行一次鎖定,鎖定完成后必須釋放鎖,才能進行下一次鎖定

      • 可以使用上下文管理協(xié)議

      • acqurie() 上鎖

      • release() 解鎖

      • 還是上一個例子,如果將全局變量加鎖,同一時間,只能允許一個線程進行讀寫操作,這時候結(jié)果就一定為0

        import threading
        import time
        
        lock = threading.Lock()
        num = 0
        loop = 1000000
        
        def funa(loop):
            global num
            for i in range(loop):
                with lock:
                    num += 1
            print('funa done')
        
        def funb(loop):
            global num
            for i in range(loop):
                lock.acquire()
                num -= 1
                lock.release()
            print('funb done')
        
        t1 = threading.Thread(target=funa,args=(loop,))
        t2 = threading.Thread(target=funb,args=(loop,))
        
        t1.start()
        t2.start()
        
        time.sleep(2)
        
        print(num)
        
        # > funa done
        # > funb done
        # > 0
        
    • Rlock 類 可重入鎖

      • 與Lock相同用法,但是可以實現(xiàn)鎖內(nèi)再次上鎖
      # 使用Lock 實現(xiàn)兩次上鎖
      
      import threading
      
      lock = threading.Lock()
      
      def funa():
          lock.acquire()
          print('第一道鎖上鎖')
          lock.acquire()
          print('第二道鎖上鎖')
          lock.release()
          print('釋放第二道鎖')
          lock.release()
          print('釋放第一道鎖')
      
      t = threading.Thread(target=funa,args=())
      
      t.start()
      t.join()
      print('done')
      
      # > 第一道鎖上鎖
      # 可以看出,此時,一直是在等待解鎖過程中,出現(xiàn)阻塞狀態(tài),后面的代碼永遠不會執(zhí)行
      
      # 使用Rlock 實現(xiàn)兩次上鎖
      
      import threading
      
      lock = threading.RLock()
      
      def funa():
          lock.acquire()
          print('第一道鎖上鎖')
          lock.acquire()
          print('第二道鎖上鎖')
          lock.release()
          print('釋放第二道鎖')
          lock.release()
          print('釋放第一道鎖')
      
      t = threading.Thread(target=funa,args=())
      
      t.start()
      t.join()
      print('done')
      
      # > 第一道鎖上鎖
      # > 第二道鎖上鎖
      # > 釋放第二道鎖
      # > 釋放第一道鎖
      # > done
      
      #可以看出,程序按照預(yù)想的執(zhí)行了
      
    • Condition 類 條件鎖

      • 當某一事件觸發(fā)后線程進行等待或者執(zhí)行操作

      • 相比于Lock,Condition有一個等待池和一個鎖定池,運行時處于鎖定池中,阻塞時,處于等待池中

      • 可使用上下文管理協(xié)議

      • 常用方法

        • acqurie() 上鎖

        • release() 解鎖

        • notify(線程數(shù)量) 通知指定數(shù)量的線程運行

        • notify_all() 通知所有線程開始執(zhí)行

        • wait() 使本線程處于阻塞狀態(tài),等待條件

      • 案例

      import threading
      import time
      
      con = threading.Condition()
      
      num = 0
      
      class A(threading.Thread):
      
          def run(self):
              global num
              with con:
                  while True:
                      if num >20:
                          print('產(chǎn)品大于20個了,我不生產(chǎn)了')
                          con.notify()
                          con.wait()
                      num += 1
                      time.sleep(0.5)
                      print('產(chǎn)品總數(shù)為:{0}'.format(num))
      
      
      class B(threading.Thread):
      
          def run(self):
              global num
              with con:
                  while True:
                      if num < 5:
                          print('產(chǎn)品小于5了,我不消費了')
                          con.notify()
                          con.wait()
                      num -= 1
                      time.sleep(0.5)
                      print('產(chǎn)品總數(shù)為:{0}'.format(num))
      
      
      
      
      a = A()
      b = B()
      
      a.start()
      b.start()
      
      # > 結(jié)果太長不寫了
      
    • Semaphore 類 信號量

      • 該類主要控制線程對資源的最大使用數(shù)量,當線程超過指定數(shù)量時,就變?yōu)榈却隣顟B(tài),一旦空出線程,其他線程就會接著執(zhí)行

      • 當一個線程申請時,信號量就會-1 ,一旦變?yōu)樨撝?其他線程就不允許申請了.當一個線程被放出時,信號量就會+1,一旦不是負值,其他線程就可以申請.

      import threading
      import time
      
      st = 'st'
      
      se = threading.Semaphore(2)
      
      class A(threading.Thread):
      
          def run(self):
              with se:
                  for i in range(3):
                      print('我是{0},我被{1}訪問了'.format(st, self.name))
                      time.sleep(1)
                      print(threading.current_thread())
      
      for i in range(20):
          t = A()
          t.start()
      
    • Event 類 事件信號燈

      • 相當于設(shè)置一個紅綠燈,當紅綠燈為True時,線程才會向下執(zhí)行,否則就會一直等待信號

      • 常用方法

        • set() 設(shè)置信號燈為True

        • clear() 設(shè)置信號燈為False

        • wait() 本線程等待信號燈

      import threading
      import time
      
      event = threading.Event()
      
      class A(threading.Thread):
      
          def run(self):
              print('等待信號燈')
              event.wait()
              print('信號燈通過')
              print('hello')
              
      
      a = A()
      a.start()
      
      time.sleep(2)
      
      event.set()
      
      a.join()
      
      print('done')
      
      # > 等待信號燈
      # > #2秒后
      # > 信號燈通過
      # > hello
      # > done
      
    • Timer 類 定時器

      • Timer(間隔秒數(shù),執(zhí)行的函數(shù),函數(shù)的參數(shù))

      • 指定多少秒后以一個線程執(zhí)行某函數(shù)

      import threading
      
      def func():
          print('hello')
      
      timer = threading.Timer(2,func)
      
      timer .start() 
      
      # > #2秒后
      # > hello     
      
  • 生產(chǎn)者消費者模型

    • 生產(chǎn)者只負責向隊列中寫入任務(wù),而消費者只向隊列中拿出任務(wù)
    import threading, queue, time
    
    class Producer(threading.Thread):
        def __init__(self,queue):
            super().__init__()
            self.queue = queue
    
        def run(self):
            num = 0
            while True:
                num += 1
                self.queue.put(num)
                print('向倉庫中放入%s'%num)
                time.sleep(0.5)
    
    class Consumer(threading.Thread):
        def __init__(self,queue):
            super().__init__()
            self.queue = queue
    
        def run(self):
            while True:
                data = self.queue.get()
                print('{0}消費了{1}'.format(self.name,data))
                time.sleep(1.5)
    
    
    que = queue.Queue()
    
    p = Producer(que)
    p.start()
    
    for i in range(2):
        c = Consumer(que)
        c.start()
      
    # > 向倉庫中放入1
    # > Thread-2消費了1
    # > 向倉庫中放入2
    # > Thread-3消費了2
    # > 向倉庫中放入3
    # > Thread-2消費了3
    # > 向倉庫中放入4
    # > Thread-3消費了4
    # > 向倉庫中放入5
    # > 向倉庫中放入6
    

多進程

  • 推薦使用多進程,因為多進程中沒有GIL鎖,可以并行執(zhí)行

  • 在使用多進程時,主函數(shù)必須在 if __name__ == '__main__:'下執(zhí)行

  • 實現(xiàn)多進程的方式

    • Process 類

      • 通過實例化Process類,將函數(shù)傳入?yún)?shù)中

        import multiprocessing
        
        def func():
          print('hello')
        t = multiprocessing.Process(target=func,args=())
        t.start()
        
      • 通過繼承Process類,并重寫init和run方法

        import multiprocessing
        
        class A(multiprocessing.Process):
        
              def run(self):
                  print('hello')
        
        a = A()
        a.start()
        
    • 使用os.fork() 僅在Unix系統(tǒng)下有效

    • 使用Pool 進程池

      • pool池可以指定并行最大進程執(zhí)行的數(shù)量,我認為和線程中的Semaphore信號量相似,同樣有一個等待池和一個工作池,當工作池中的進程空出來時,等待池的其它線程就會頂替上去執(zhí)行

      • 可使用上下文管理協(xié)議

      • 常用函數(shù)

        • apply(函數(shù)名,參數(shù)) 向工作池提交任務(wù),阻塞的等待任務(wù)完成,并返回結(jié)果.

        • apply_async(函數(shù)名,參數(shù)) 向工作池提交任務(wù),返回消息對象,等待進程池所有任務(wù)執(zhí)行完畢后,再拿回任務(wù)執(zhí)行的結(jié)果

          • 因為apply_async是并行的,所以需要申明一個list用來保存消息對象,等待所有的任務(wù)完成后再列表中的單個消息對象返回結(jié)果

          • get() 返回結(jié)果

          • ready() 如果調(diào)用完成,則返回True

          • successful() 如果調(diào)用沒有引發(fā)異常秧了,返回True

          • wait() 等待結(jié)果執(zhí)行完畢

          • terminate() 立即終止該工作進程

        • close() 關(guān)閉進程池

        • join() 阻塞,直到進程池所有任務(wù)完成

        • terminate() 立即終止進程池進程

      • 阻塞式進程池

        import multiprocessing
        import random
        import time
        
        
        def getresult(x):
            return x * random.randint(1, 10)
        
        
        if __name__ == '__main__':
        
            pool = multiprocessing.Pool(2)
        
            for i in range(1, 5):
                res = pool.apply(getresult, (i,))
                time.sleep(1)
                print(res)
        
        # > 4
        # > 10
        # > 9
        # > 4
        
      • 異步線程池

        import multiprocessing
        import random
        
        
        def getresult(x):
            return x * random.randint(1, 10)
        
        
        if __name__ == '__main__':
        
            pool = multiprocessing.Pool(2)
        
            list = []
            for i in range(1, 5):
                res = pool.apply_async(getresult, (i,))
                list.append(res)
            
            p.close()
            p.join()
                
            print(list)
        
            for i in list:
                print(i.get())
                
        
        
        # > [<multiprocessing.pool.ApplyResult object at 0x02C78630>, <multiprocessing.pool.ApplyResult object at 0x02C78690>, <multiprocessing.pool.ApplyResult object at 0x02C786F0>, <multiprocessing.pool.ApplyResult object at 0x02C78750>]
        # > 7
        # > 12
        # > 3
        # > 20
        
  • 進程常用方法

    • start() 啟動進程

    • join() 阻塞,知道本進程執(zhí)行完畢

    • daemon = True 設(shè)置守護進程

    • terminate() 強制關(guān)閉進程

    • close() 關(guān)閉進程

    • is_alive() 返回進程是否存活

    • name 返回進程名稱

    • pid 返回進程ID

    • active_chrildren() 返回活動的進程列表

    • cpu_count() 返回電腦CPU核心數(shù)

  • 進程之間的同步

    • 多進程中,同步并不是向多線程那樣重要,因為多使用IPC通信

    • 其用法與多線程中相同類的用法一樣

    • Condition類 條件變量

    • Event類 事件信號燈

    • Semaphore類 信號量

    • Lock 鎖

    • Rlock 可重入鎖

  • IPC通信 多進程之間的通信

    • 源自于同一父進程

      • Queue類 先入先出隊列

        • put() 放入元素

        • get() 取出元素

        • qsize() 返回隊列長度

        • empty() 檢測隊列是否為空

        • full() 檢測隊列是否已滿

      • JoinableQueue隊列

        • 每當一個任務(wù)完成后,可手動調(diào)用task_done,告訴系統(tǒng)一個任務(wù)已經(jīng)執(zhí)行完成,當所有任務(wù)執(zhí)行完成后,將取消join的阻塞,向下執(zhí)行代碼

        • 常用函數(shù)

          • Queue隊列的其它方法

          • task_done() 任務(wù)已完成

          • join() 阻塞,直到本隊列中的所有元素被task_done

        import multiprocessing,time
        
        def func(queue):
            while True:
                if queue.empty():
                    break
                data = queue.get()
                print('取出%s'%data)
                queue.task_done()
                time.sleep(0.5)
        
        if __name__ == '__main__':
        
            que = multiprocessing.JoinableQueue()
        
            for i in range(20):
                que.put(i)
        
            p = multiprocessing.Process(target=func, args=(que,))
        
            p.start()
        
            que.join()
        
            print('當隊列中的元素都被取完后才會看見我') 
        
        # > 太長不打了          
        
      • Pipe 類 管道 兩個進程之間的通信

        • 相當于管道,實例化后返回兩個端口,默認是雙工的

        • send() 發(fā)送消息

        • recv() 接收消息

        import multiprocessing,time
        
        class A(multiprocessing.Process):
        
            def __init__(self,con):
                super().__init__()
                self.con = con
        
            def run(self):
                while True:
                    self.con.send('hello')
                    time.sleep(1)
        
        
        class B(multiprocessing.Process):
        
            def __init__(self, con):
                super().__init__()
                self.con = con
        
            def run(self):
                while True:
                    data = self.con.recv()
                    print(data)
                    time.sleep(1)
        
        if __name__ == '__main__':
        
            con1, con2 = multiprocessing.Pipe()
        
            a = A(con1)
        
            b = B(con2)
        
            a.start()
        
            b.start()   
        
        # > hello
        # > ...
        
    • 不是源自于同一父進程

      • Value類 將值放在系統(tǒng)的共享內(nèi)存中,多個進程可以共同讀寫這塊內(nèi)存,

        • 定義 Value(值類型,值)

        • 值類型

          • u unicodechar

          • i signedint

          • f float

          • d double

        • value 獲取值

        import multiprocessing
        
        class A(multiprocessing.Process):
        
            def run(self):
        
                s = v.value
        
                print('{0} get {1}'.format(self.name,s))
        
        
        if __name__ == '__main__':
            
            v = multiprocessing.Value('u','哈')
        
            for i in range(5):
                p = A()
                p.start()
        
        # > A-1 get 哈
        # > A-2 get 哈
        # > A-4 get 哈
        # > A-5 get 哈
        # > A-3 get 哈
        
      • Array類 Vaule的數(shù)組

        • 數(shù)組中存放的變量類型需要一致

        • 定義 Array(值類型,列表)

        • 返回的是一個可迭代的對象

        import multiprocessing
        
        class A(multiprocessing.Process):
        
            def run(self):
        
                for i in arr:
                    print(i,end='')
        
        
        if __name__ == '__main__':
        
            list = ['哈','哈','-','我','是','A','r','r','a','y']
        
            arr = multiprocessing.Array('u',list)
        
            p = A()
            p.start()
        
        # > 哈哈-我是Array
        
      • Manager類 管理器

        • list 列表

        • dict 字典

        • Condition() 創(chuàng)建一個線程共享條件信號燈

        • Event() 創(chuàng)建一個線程共享事件信號燈

        • Lock() 創(chuàng)建一個線程共享鎖

        • Rlock() 創(chuàng)建一個線程共享可重入視頻

        • Queue() 創(chuàng)建一個共享先進先出隊列

        • Semaphore() 創(chuàng)建一個線程共享信號量

      • managers

        • BaseManager類

          • 原理: 通過Manager啟動一個server進程監(jiān)聽socket,其他進程通過使用socket與主進程進行聯(lián)系,進行信息交換

          • 定義 BaseManager(address=(ip,端口),authkey=秘鑰) 創(chuàng)建一個服務(wù)器Manager對象,其他客戶端Manager通過與此對象連接,進行數(shù)據(jù)交換

          • 常用方法

            • start() 啟動服務(wù)進程

            • get_server() 返回一個服務(wù)對象

            • server_forever() 永遠執(zhí)行下去

            • connect() 將本地管理器連接到主服務(wù)管理器上

            • shuntdown() 關(guān)閉本管理器

            • register(對外暴露的方法名,callable=返回對象的函數(shù))

        • 分布式進程 Master-Worker模式

          • Master 負責分發(fā)任務(wù),并接受返回的最終結(jié)果
          from multiprocessing.managers import BaseManager
          import multiprocessing
          import time
          
          class Master(BaseManager):
              pass
          
          task_que = multiprocessing.Queue()
          result_que = multiprocessing.Queue()
          
          def returntaskque():
              return task_que
          
          def returnresultque():
              return result_que
          
          
          if __name__ == '__main__':
          
              ip = 'XXXXXXXXXXXXXX'
              port = 8888
              key = b'123'
              server = Master((ip,port),key)
          
          
          
              server.register('get_task_que', callable=returntaskque)
              server.register('get_result_que', callable=returnresultque)
          
              server.start()
          
              task = server.get_task_que()
              result = server.get_result_que()
          
              num = 0
              while True:
                  num += 1
                  task.put('工作%s'%num)
                  time.sleep(1)
                  if not result.empty():
                      print('結(jié)果是:%s'%result.get())
          
          • Worker 負責處理任務(wù),并返回結(jié)果
          from multiprocessing.managers import BaseManager
          import time
          
          
          class Worker(BaseManager):
              pass
          
          if __name__ == '__main__':
          
              ip = 'XXXXXXXXXXXXXX'
              port = 8888
              key = b'123'
          
              worker = Worker((ip,port),key)
          
              worker.register('get_task_que')
              worker.register('get_result_que')
          
              worker.connect()
          
              task = worker.get_task_que()
              result = worker.get_result_que()
          
              while True:
                      if not task.empty():
                          data = task.get()
                          print('收到{0}'.format(data))
                          time.sleep(2)
                          result.put('完成{0}'.format(data))
                          time.sleep(1)
          

迭代器 Iterator

  • 一次產(chǎn)生一個對象,可以裝下無限大的對象

  • 可迭代 Iterable 可用于for循環(huán)的對象

  • 迭代器一定是一個可迭代的,但是可迭代的不一定是迭代器

  • 將一個可迭代對象轉(zhuǎn)換為迭代器

    • 通過iter()函數(shù)

      from collections import Iterator
      
      list = [i for i in range(5)]
      print(isinstance(list, Iterator))
      
      list = iter(list)
      print(isinstance(list, Iterator))
      
      # > False
      # > True
      
    • 通過__iter__()函數(shù)

      from collections import Iterator
      
      list = [i for i in range(5)]
      print(isinstance(list, Iterator))
      
      list = list.__iter__()
      print(isinstance(list, Iterator))
      
      # > False
      # > True
      
  • 使用方式

    • 使用for循環(huán)

      
      
      for i in list:
         print(i)
      
    • 使用next()函數(shù),直到?jīng)]有值拋出StopIteration異常

      list = iter([i for i in range(5)])
      next(list)
      next(list)
      ....
      
    • 使用__next__()函數(shù),直到?jīng)]有值拋出StopIteration異常

      list = iter([i for i in range(5)])
      list.__next__()
      list.__next__()
      ....
      

生成器

  • 一邊循環(huán),一邊計算下一個對象,直到遇見yield語句后停止,每次調(diào)用只返回一個值

  • 滿足三個條件

    • 每次調(diào)用都產(chǎn)生一個用于for循環(huán)遍歷的對象

    • 元素到達最后一個后拋出StopIteration異常

    • 可以被next調(diào)用

  • 定義生成器

    • 直接使用生成器

      • 列表生成表達式 list = [i for i in range(5)]

      • 生成器 gen = (i for i in range(5))

    • 函數(shù)中包含yield語句

      def func(n):
          st = '產(chǎn)品'
          num = 0
          while num < n:
              yield st+str(num)
              num += 1
              
      g = func(5)
      print(list(g))  # 將生成器轉(zhuǎn)化為列表,方便查看,也可以使用next(g)挨個輸出值
      
      # > ['產(chǎn)品0', '產(chǎn)品1', '產(chǎn)品2', '產(chǎn)品3', '產(chǎn)品4']
      
    • 可使用send()函數(shù)向生成器發(fā)送值

      • 注意: 生成器每執(zhí)行一次都會在yield處停止,yield前的變量可以接收send發(fā)送的值,yield后是生成器返回的值
      def func():
          num = yield
          print(num)
      
      g = func()
      next(g)
      g.send(5)
      
      # > 5
      
    • 特別注意: 無論是next()還是send(),調(diào)用后都會在下一個yield語句處停止

  • yield from

    • 相當于中間層,每當生成器生成一個元素,都由中間層將元素傳遞給主函數(shù)

    • 包含yield from的生成器叫做委派生成器

    def func():
        yield from 'asds'
    
    g = func()
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    
    # > a
    # > s
    # > d
    # > s
    

協(xié)程

  • 非搶占式多任務(wù),協(xié)程允許不同入口點不同位置執(zhí)行程序

  • 多線程之間的切換會消耗一定的資源,一些高并發(fā)的程序在執(zhí)行時,如果使用多線程,多線程之間的切換會消耗大量的資源和時間,但協(xié)程之間的切換卻消耗的資源少

  • 協(xié)程的實現(xiàn)

    • 使用next()預(yù)激協(xié)程

    • 使用yield獲取返回值

    • 使用send()發(fā)送值

  • 協(xié)程的四個狀態(tài)

    • GEN-CREATED 等待開始執(zhí)行

    • GEN-RUNNING 解釋器正在執(zhí)行

    • GEN-SUSPENED 在yield語句處暫停

    • GEN-CLOSED 執(zhí)行結(jié)束

  • 協(xié)程終止

    • 可以使用哨兵值結(jié)束
  • 獲取協(xié)程的返回值

    import time
    
    def average():
        sum = 0
        count = 0
        avrge = 0
        while True:
            data = yield (avrge,sum,count)
            if data == None:
                break
            sum = sum + data
            count += 1
            avrge = sum / count
        print('協(xié)程結(jié)束')
    
    g = average()
    next(g)
    
    for i in range(1,20,3):
        avr,sum,count = g.send(i)
        print('總數(shù)為:{0} , 個數(shù)為:{1} , 平均數(shù)為{2}'.format(sum,count,avr))
        time.sleep(1)
    
    
  • 協(xié)程的消費者-生產(chǎn)者模型

import time

def Producer():
    num = 0
    while True:
        num += 1
        print('生產(chǎn)者:總產(chǎn)品為%s'%num)
        num = yield num
        time.sleep(0.5)


def Consumer():
    num = 0
    while True:
        num = yield num
        num -= 1
        print('消費者:總產(chǎn)品為%s'%num)
        time.sleep(0.5)

p = Producer()
c = Consumer()
num = next(p)
next(c)
while True:
    num = c.send(num)
    num = p.send(num)

結(jié)構(gòu)化文件儲存

  • 為了解決不同設(shè)備之間的數(shù)據(jù)交換

  • xml庫

    • 構(gòu)成: 處理指令,xml版本和編碼

      • 根元素: 樹形結(jié)構(gòu)的根元素,有且只能有一個

      • 子元素: 可以有多個

      • 屬性: 定義在括號中

      • 內(nèi)容: 標簽中定義的信息

      • 注釋: 使用``

    • 保留字符

      • 轉(zhuǎn)義 保留字符需要用轉(zhuǎn)義進行代替

      • CDATA定義的字符不進行轉(zhuǎn)義,相當于python中的r'', <!{CDATA[不需要進行轉(zhuǎn)義的字符]}>

    • 命名空間

      • xmlns,是xml name space的縮寫

      • 直接在標簽中添加相應(yīng)空間

    • SAX (Simple API for xml)

      • 基于事件驅(qū)動

      • 包含解析器和事件處理兩個部分

      • 流式讀取

      • 速度快

    • DOM (Document Object Model)

      • minidom類

        • parse(file) 打開xml文件,返回節(jié)點樹

        • documentElement 返回xml的根節(jié)點

        • creatElement(tag) 創(chuàng)建新節(jié)點

        • createAttribute(attr) 創(chuàng)建此節(jié)點的新屬性

        • getElementsByTagName(tag) 獲取此節(jié)點下的名為tag標簽的集合

        • getAttribute(attr) 返回此節(jié)點的attr屬性的值

        • parentNode 返回當前節(jié)點的父節(jié)點

        • previousSibling 返回此節(jié)點的前一個兄弟節(jié)點

        • nextSibling 返回此節(jié)點的下一個兄弟節(jié)點

        • childNodes 返回當前節(jié)點的子節(jié)點列表

        • firstChild 返回第一個子節(jié)點

        • lastChild 返回最后一個子節(jié)點

        • nodeName 返回此節(jié)點的標簽名

        • 注意:節(jié)點中的漢字也是有節(jié)點的,是text節(jié)點

      • etree.ElementTree類

        • Element(標簽名) 創(chuàng)建一個節(jié)點

        • SubElement(parent,tag) 生成一個子節(jié)點,并添加到調(diào)用函數(shù)的節(jié)點

        • ElementTree(tag) 生成一個節(jié)點樹,將tag標簽作為根

        • 節(jié)點樹.write(file) 將節(jié)點樹寫入文件

        • set(key,vlue) 修改屬性

        • append(子節(jié)點) 此節(jié)點最后添加子節(jié)點

        • remove(子節(jié)點) 刪除此節(jié)點子節(jié)點

        • parse(file) 打開xml文件,返回節(jié)點樹

        • getroot() 返回節(jié)點樹的根節(jié)點

        • iter(tag) 返回此節(jié)點下的所有節(jié)點,如果指定標簽名,則遍歷所有指定標簽名

        • find() 查找第一個匹配的節(jié)點

        • findall() 查找此節(jié)點下所有匹配的子節(jié)點,返回集合

        • tag 標簽名

        • text 標簽的文本值

        • attrib 返回標簽所有屬性的字典

# 利用etree創(chuàng)建一個xml文件
import xml.etree.ElementTree

root = xml.etree.ElementTree.Element('Root')

name = xml.etree.ElementTree.SubElement(root,'Name')
name.text = 'Jack'

age = xml.etree.ElementTree.SubElement(root,'Age')
age.text = '22'

tree = xml.etree.ElementTree.ElementTree(root)

tree.write('a.xml')

  • json庫

    • 輕量級的數(shù)據(jù)交換工具 (JavaScripObjectNotation)

    • 類似于字典,基于key-value形式

    • 常用函數(shù)

      • 以文件形式存在

        • dump(file) 寫入文件,轉(zhuǎn)化為json對象

        • load(file) 讀取文件,轉(zhuǎn)化為python對象

      • 以數(shù)據(jù)形式存在

        • dumps(data) 寫入內(nèi)容,轉(zhuǎn)化為json對象

        • loads(data) 讀取內(nèi)容,轉(zhuǎn)化為python對象

import json

data = {
    'name':'jack',
    'age':18,
    'sex':'male'
}

# 寫入json文件
with open('a.json','w')as f:
    json.dump(data,f)

#讀取json文件
with open('a.json','r')as f:
    data = json.load(f)
print(type(data))
print(data)

# > <class 'dict'>
# > {'name': 'jack', 'age': 18, 'sex': 'male'}

re 正則表達式模塊

  • 轉(zhuǎn)義字符

    • 重復(fù)限定符

      . 匹配除換行符\n之外的所有字符

      ^ 匹配字符串開頭

      $ 匹配字符串結(jié)尾

      * 匹配前一個字符0次以上,貪婪模式

      + 匹配前一個字符1次以上,貪婪模式

      ? 匹配前一個字符0次或1次,貪婪模式

      {m,n} 匹配前一個字符至少m次,最多n次,當沒有n時則為無限次,貪婪模式

      [] 字符集,匹配字符集中的任意字符,字符客單個給出,也可范圍給出

      () 分組,分組從0開始

      | 或者

      *? +? ?? {m,n}? 非貪婪模式,盡可能少的匹配字符

      import re
      
      text = '<div>name</div><div>age</div>'
      
      regex = re.search(r'<div>.*?</div>',text)
      print(regex.group())
      # > <div>name</div>
      
    • 特殊字符集

      r 原始字符串,字符串中的特殊字符不需要再進行轉(zhuǎn)義,否則則需要使用\進行轉(zhuǎn)義

      [\u4E00-\u9FA5] 漢字

      \b 單詞邊界

      \d 數(shù)字 [0-9]

      \s 任何空白字符 [\n\t\r\f\v<空格>]

      \w 匹配包括下劃線的任何字字符 [A-Za-z0-9_]

      除漢字外,上述特殊集大寫為與之相反的意思

  • flags 編譯標志位

    re.I 不區(qū)分大小寫

    re.M 多行匹配

    re.U 根據(jù)Unicode字符集解析字符

    re.S 使.匹配包括換行符在內(nèi)的所有字符

  • compile(pattern) 編譯正則表達式,返回正則表達式對象

    • 正則表達式對象可以直接調(diào)用以下函數(shù),也可使用re進行調(diào)用.
    import re
    
    text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
    
    #使用re進行調(diào)用
    regex = re.search(r'\d',text)
    print(regex)
    
    # > <_sre.SRE_Match object; span=(24, 25), match='3'>
    
    #使用compile調(diào)用
    par = re.compile(r'\d')
    regex = par.search(text)
    print(regex)
    
    # > <_sre.SRE_Match object; span=(24, 25), match='3'>
    
    • search(pattern,string[,flags]) 查找,查找字符串的所有位置,返回一個匹配對象

    • match(pattern,string[,flags]) 匹配,匹配字符串的開頭位置,與search不同,返回一個匹配對象

    import re
    
    text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
    regex = re.match('library',text)
    print(regex)
    # > None
    
    regex = re.match('https',text)
    print(regex)
    # > <_sre.SRE_Match object; span=(0, 5), match='https'> 
    
    • findall(pattern,string[,flags]) 查找字符串中所有匹配正則表達式的內(nèi)容,返回一個匹配的字符串列表
    import re
    
    text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
    list = re.findall('o',text)
    print(list)
    # > ['o', 'o', 'o', 'o']
    
    • split(pattern,string[,flags]) 按照正則表達式分割字符串對象,將正則表達式中的匹配選項替換為'',并返回一個分割的字符串列表
    import re
    
    text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
    list = re.split(r'/',text)
    print(list)
    # > ['https:', '', 'docs.python.org', '3', 'library', 're.html#regular-expression-syntax']
    
    • sub(pattern,repl,string,count) 替換查找的字符串
    import re
    
    text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
    # 將所有字符替換為@
    regex = re.sub(r'\W','@',text)
    print(regex)
    # > https@@@docs@python@org@3@library@re@html@regular@expression@syntax
    
  • Match 匹配對象

    • 下面的regex即為一個匹配對象
    import re
        
    text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
        
    regex = re.search(r'\d',text)
    # > <_sre.SRE_Match object; span=(24, 25), match='3'>
    
    • 匹配對象的布爾值始終為True,一旦沒有匹配到的對象,則返回None

    • group(index) 當index沒有或者為0時,返回匹配對象的整個字符串,當index不為0時,返回正則表達式中用()括起來的字符

    regex.group()
    # > 3
    
    • groups() 返回被匹配字符串的元組
    regex = re.search(r'(org).+(syntax$)',text)
    # > ('org', 'syntax')
    
    • start() 返回匹配開始位置
    regex.start()
    # > 24
    
    • end() 返回匹配結(jié)束位置
    regex.end()
    # > 25
    
    • span() 返回包含start和end的元組
    regex.span()
    # > (24, 25)
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市勤庐,隨后出現(xiàn)的幾起案子示惊,更是在濱河造成了極大的恐慌,老刑警劉巖愉镰,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件米罚,死亡現(xiàn)場離奇詭異,居然都是意外死亡丈探,警方通過查閱死者的電腦和手機录择,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來隘竭,“玉大人动看,你說我怎么就攤上這事京痢⊙悸郑” “怎么了懒棉?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵妻导,是天一觀的道長辰如。 經(jīng)常有香客問我缭受,道長太防,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任钝鸽,我火速辦了婚禮汇恤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拔恰。我一直安慰自己因谎,他們只是感情好,可當我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布颜懊。 她就那樣靜靜地躺著财岔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪河爹。 梳的紋絲不亂的頭發(fā)上匠璧,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天,我揣著相機與錄音咸这,去河邊找鬼夷恍。 笑死,一個胖子當著我的面吹牛媳维,可吹牛的內(nèi)容都是我干的酿雪。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼侨艾,長吁一口氣:“原來是場噩夢啊……” “哼执虹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起唠梨,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤袋励,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后当叭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體茬故,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年蚁鳖,在試婚紗的時候發(fā)現(xiàn)自己被綠了磺芭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡醉箕,死狀恐怖钾腺,靈堂內(nèi)的尸體忽然破棺而出徙垫,到底是詐尸還是另有隱情,我是刑警寧澤放棒,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布姻报,位于F島的核電站,受9級特大地震影響间螟,放射性物質(zhì)發(fā)生泄漏吴旋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一厢破、第九天 我趴在偏房一處隱蔽的房頂上張望荣瑟。 院中可真熱鬧,春花似錦摩泪、人聲如沸笆焰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仙辟。三九已至,卻和暖如春鳄梅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背未檩。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工戴尸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冤狡。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓孙蒙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親悲雳。 傳聞我的和親對象是個殘疾皇子挎峦,可洞房花燭夜當晚...
    茶點故事閱讀 42,700評論 2 345

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

  • 一、快捷鍵 ctr+b 執(zhí)行ctr+/ 單行注釋ctr+c ...
    o_8319閱讀 5,782評論 2 16
  • Scala與Java的關(guān)系 Scala與Java的關(guān)系是非常緊密的:掀啊坦胶! 因為Scala是基于Java虛擬機,也就是...
    燈火gg閱讀 3,417評論 1 24
  • 一直以來晴楔,我都需要有人去告訴我怎樣去生活顿苇,給我現(xiàn)成的答案,但是現(xiàn)在税弃,在天津的年末照舊霧霾沉沉纪岁,夜空中最亮的啟明星難...
    x56owy閱讀 547評論 2 2
  • 受不了太多世俗和壓迫,我最終還是逃了出來则果,手里捏的是去成都的火車票幔翰,下一站去哪漩氨,我還是沒想好,去云南還是西藏遗增?窗外...
    蒼耳loveyou閱讀 624評論 0 0
  • 雖然撒鹽櫻花練習又失敗了叫惊、但是我還沒放棄,沒嘗試完美之前先更其他的練習贡定,今天又練習用紙巾擦出的效果赋访、勉強能看到天空...
    鹿小乖hi閱讀 419評論 5 3