python_learn Ⅰ

基於 廖雪峯python3教程 學習。html


目錄:java

  • 01_輸入輸出.py
  • 02_list、tuple.py
  • 03_條件判斷.py
  • 04_循環.py
  • 05_利用循環排序.py
  • 06_自定義3元2次方程的根求解函數.py
  • 07_函數的參數.py
  • 08_遞歸函數.py
  • 09_切片.py
  • 10_迭代、索引.py
  • 11_列表生成式.py
  • 12_元組循環迭代列表生成式輸出天干地支.py
  • 13_將列表大小寫字符所有小寫輸出.py
  • 14_生成器.py
  • 15_生成器生成斐波拉契數列.py
  • 16_生成器生成楊輝三角.py
  • 17_迭代器.py
  • 18_高階函數_map、reduce.py
  • 19_filter.py
  • 20_sorted.py
  • 21_返回函數.py
  • 22_匿名函數.py
  • 23_偏函數.py
  • 24_類和實例.py
  • 25_訪問限制.py
  • 26_繼承和多態.py
  • 27_獲取對象信息.py
  • 28_實例屬性和類屬性.py
  • 29_限制實例屬性__slots__.py
  • 30_使用@property.py
  • 31_多重繼承.py
  • 32_枚舉類.py
  • 33_文件讀寫.py
  • 34_StringIO_BytesIO.py
  • 35_操做文件和目錄.py
  • 36_代碼實現dir -l功能.py
  • 37_序列化_pickle模塊.py
  • 38_JSON.py
  • 39_多進程.py
  • 40_多線程.py
  • 41_正則表達式.py
  • 42_datetime模塊.py
  • 43_collections模塊.py
  • 44_base64模塊.py
  • 45_hashlib模塊.py
  • 46_hmac模塊.py
  • 47_itertools模塊.py
  • 48_contextlib模塊.py
  • 49_urllib模塊.py
  • 50_XML解析.py
  • 51_HTMLParser模塊.py
  • 52_pillow模塊.py
  • 53_requests模塊.py
  • 54_chardet模塊.py
  • 55_psutil模塊.py
  • 56_TCP編程.py
  • 57_UDP編程.py
  • 58_SMTP發送郵件.py
  • 59_POP3收取郵件.py
  • 60_使用SQLite.py
  • 61_使用MySQL.py
  • 62_使用SQLAIchemy.py
  • 63_WSGI接口.py

條件判斷

#!/usr/bin/env python
# -*- coding: utf-8 -*-
h = float(input('請輸入你的身高: '))
w = float(input('請輸入你的體重: '))
bmi =float('%.1f' % (w//(h*h)))

if bmi<18.5:
    print('您的體重太輕')
elif bmi<25:
    print('您的處於正常範圍')
elif bmi<28:
    print('您體重太重')
elif bmi<32:
    print('您處於肥胖狀態')
else:
    print('您嚴重肥胖')

循環

#!/usr/bin/env python
# -*- coding: utf-8 -*-
L = ['Bart','Lisa','Adam']
for x in L:
    print('hello,',x)

利用循環排序

#!/usr/bin/env python
# -*- coding: utf-8 -*-

array = [1, 2, 5, 3, 6, 8, 4]
for i in range(len(array) - 1, 0, -1):
    print(i)
    for j in range(0, i):
        print(j)
        if array[j] > array[j + 1]:
            array[j], array[j + 1] = array[j + 1], array[j]
print(array)

三元二次方程求解

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import math
def quadratic(a,b,c):
    for s in (a,b,c):
        if not isinstance(s, (int, float)):
            raise TypeError('數字類型輸入錯誤,請從新輸入')
    d = float(b*b-4*a*c)
    if d < 0:
        print('方程無解')
    elif d == 0:
        x = (b + math.sqrt(d))/ (2*a)
        print('方程僅一個解: %.1f' % x)
    else:
        x1 = (b + math.sqrt(d))/(2*a)
        x2 = -(b + math.sqrt(d))/(2*a)
        print('方程有兩個解: %.1f' % x1,x2)

quadratic(1,4,4)

函數的參數

#!/usr/bin/env python
#-*- coding: utf:8 -*-
# 階乘函數
def power(x,n):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

def power(x,n=2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

print(power(4,3))
print(power(5))

遞歸函數

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 利用遞歸函數計算階乘
# N! = 1 * 2 * 3 * ... * N
def fact(n):
    if n == 1:
        return 1
    return n * fact(n-1)

print('fact(1) =', fact(1))
print('fact(5) =', fact(5))
print('fact(10) =', fact(10))
print('遞歸調用次數太多容易出現棧溢出')
print('--------------------------')

# 利用遞歸函數移動漢諾塔:
def move(n, a, b, c):  # n 爲最初A柱子上的圓盤個數,將其從A移到C,B爲緩衝區
    if n == 1:
        print('move', a, '-->', c)  # n=1 時,直接從A到C
    else:
        move(n-1, a, c, b)  # n 個時,先將 n-1 從A移到B
        move(1, a, b, c)  # 再將剩下最大的一個從A移到C
        move(n-1, b, a, c)  # 將剛纔放在B上的 n-1 從B移到C
move(3, 'A', 'B', 'C')

切片

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 切片只能在list列表和tuple元組中,dict字典中不能進行切片輸出

# list
L = list(range(20))
print(L)        #輸出列表L
print(L[:])      #同上,輸出全部列表數字,從起始到結束,起始結束位置可不寫
print(L[:5])    #輸出前5個數字,起始位置可省略
print(L[-3:])    #輸出後3個數字,結尾位置可省略
print(L[::2])    #每隔一位輸出L列表(輸入偶數位)
print(L[1::2])  #從第一位起每隔兩位輸出L列表(輸出奇數位)
print(L[::-1])  #倒序輸出列表L
print(L[::-3])  #倒序每隔兩位輸出L
print('------------------------------------------------------------')

# tuple
s = (1,2,3,4,5)
print(s[:])
print(s[::-1])

迭代、索引

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#使用for...in...輸出就是一種迭代
d = {'a':5, 'b':6, 'c':7, 'd':8}

for key in d:
    print(key)    #迭代輸出字典d的字符

print('-----------------分隔符----------------')

for value in d.values():
    print(value)  #迭代輸出字典d的字符的值

print('-----------------分隔符-----------------')

#enumerate()函數能夠索引列舉 list、tuple、dict 裏面的內容
for zifu in d:
    print('輸出字典d的內容:',zifu)

for value in d.values():
    print('輸出字典d的字符值:',value)

for suoyin in enumerate(d):
    print('索引列舉出字典d的內容:', suoyin)  #索引單個參數輸出的是元組,如 (1, 2)

for key,hey in enumerate(d):
    print('索引列舉出 key,hey:', key,hey)  #索引多個參數輸出的是 字符序號 和 字符內容自己。

for x,y in ((1,1),(2,4),(3,9)):
    print(x,y)

print('-----------------分隔符-----------------')

#迭代可輸出 列表、元組、字典、字符串,但不能迭代整數
#判斷是否可迭代, isinstance() 判斷對象類型
from collections import Iterable
print('isinstance([1,2,3],Iterable):', isinstance([1,2,3],Iterable))
print('isinstance((1,2,3),Iterable):', isinstance((1,2,3),Iterable))
print("isinstance({'a':1, 'b':2, 'c':3},Iterable):", isinstance({'a':1, 'b':2, 'c':3},Iterable))
print("isinstance('ABC'),Iterable:", isinstance('ABC',Iterable))
print('isinstance(123,Iterable):', isinstance(123,Iterable))

列表生成式

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#列表生成三種方法
print('法一:直接經過range()生成')
print(list(range(10)))

print('法二:經過循環在空列表末尾疊加')
L = []
for x in range(10):
    L.append(x*x)
print(L)

print('法三:列表生成式')
print([x*x for x in range(10)])              #直接列表生成式輸出
print([x*x for x in range(10) if x%2==0])    #輸出偶數的平方列表
print([x+y for x in 'ABCD' for y in 'EFGH'])  #二層循環輸出列表

# *.values()、*.items()函數使用
d = {'A':'a', 'B':'b', 'C':'c', 'D':'d'}
for x in d.values():
    print(x)              #輸出字符的值

for y,z in d.items():
    print(y,'=',z)        #將字符的值賦值給字符,即 A=a

元組循環迭代列表生成式輸出天干地支

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#天干地支
print('***** 法一:循環 *****')

a=('甲','乙','丙','丁','戊','己','庚','辛','壬','癸')
b=('子','醜','寅','卯','辰','巳','午','未','申','酉','戌','亥')
c=[]
for i in range(60):
    print(i)
    c.append(a[i%len(a)]+b[i%len(b)])
print(c)

print('------------------------------------------------------')

print('***** 法二:列表生成式 *****')
#列表生成式一句代替法一循環輸出,代碼更簡潔
a = ['甲','乙','丙','丁','戊','己','庚','辛','壬','癸']
b = ['子','醜','寅','卯','辰','巳','午','未','申','酉','戌','亥']
c = [a[i%len(a)]+b[i%len(b)] for i in range(60)]
print (c)

將列表大小寫字符所有小寫輸出

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#將列表的內容所有小寫輸出

print('--------- 場景一 ---------')
L = ['Hello', 'World', 'Apple']
print([s.lower() for s in L])


print('--------- 場景二 ---------')
L1 = ['Hello', 'World', 18, 'Apple', None]
#print([s.lower() for s in L1])  在L列表中能這樣,L1中不能這樣輸出,由於 *.lower()函數對象只針對於字符串,不能對整型,空值進行。
L2 = []
for s in L1:
    if isinstance(s, str):    # isinstance()函數 判斷 變量類型
        L2.append(s.lower())
    else:
        L2.append(s)
print(L2)

生成器

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#列表生成
L = [x*x for x in range(10)]
print(L)
print('----------- 分隔符 ----------')

#生成器,不一次生成,有效解決列表生成式循環次數過多帶來的內存限制及空間浪費,生成器邊循環邊計算邊輸出
g = (x*x for x in range(10))
print('第一個:',next(g))
print('第二個:',next(g))
print('第三個:',next(g))
print('第四個:',next(g))
print('----------- 分隔符 ----------')

#生成器也可利用循環一次單行輸出全部,不用向上面每次敲 next(g)
g = (x*x for x in range(10))
for s in g:
    print(s)
print('----------- 分隔符 ----------')

#生成器一次輸出成一個列表,如最上面的列表生成同樣
g = (x*x for x in range(10))
print([n for n in g])

生成器生成斐波拉契數列

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#斐波拉契數列:從第三位起,每位數都等於前兩位數字的和
# 1,1,2,3,5,8,13,21,34,...

#方法一:判斷、循環自定義顯示斐波拉契數列的數字個數
max = int(input('請輸入列表顯示的位數 max:'))
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
print(fib(max))
print('----------------- 分隔符 ----------------')

#方法二:生成器生成,使用了 yield ,而後循環列出,輸出沒有 None 字符
min = int(input('請輸入列表顯示的位數 min:'))
def fab(min):
    n, a, b = 0, 0, 1
    while n < min:
        yield b
        a, b = b, a+b
        n = n + 1

L = []
for i in fab(min):
    L.append(i)
print(L)
print('------------ 分隔符 -----------')

#方法三:遞歸、循環自定義顯示斐波拉契數列的數字個數
def xh(n):
    if n==1:
        return 1
    elif n==2:
        return 1
    else:
        return xh(n-1)+xh(n-2)

L = []
a = int(input('請輸入列表顯示的位數 a:'))
for s in range(1,a+1):
    L.append(xh(s))
print(L)

# 以上第一種和第三種會因函數中的變量值的加大而損耗內存,第二種生成器生成的,使用 yield 每次執行一次循環就掛起,
# 下次再從掛起的地方調用,不會一次性生成完,從而不會佔用系統資源。雖然在此輸出結果是相同的,這是由於for...in...
# 循環調用輸出的次數使其所有輸出了。

生成器生成楊輝三角

迭代器

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 可直接做用於 for 循環的對象統稱爲 可迭代對象:Iterable
# list、tuple、dict、str、for循環,是可迭代對象,整數不是可迭代對象。ininstance()判斷 變量類型。
from collections import Iterable
print('isinstance([],Iterable):',isinstance([],Iterable))
print('isinstance((),Iterable):',isinstance((),Iterable))
print('isinstance({},Iterable):',isinstance({},Iterable))
print("isinstance('abc',Iterable):",isinstance('abc',Iterable))
print('isinstance((x for x in range(10)),Iterable):',isinstance((x for x in range(10)),Iterable))
print('isinstance(100,Iterable):',isinstance(100,Iterable))
print('-------------------- 分隔符 ------------------')


# 不但能夠做用於 for 循環,還能夠被next()函數不斷調用並返回下一個值的叫 迭代器:Iterator
# list、tuple、dict、str、int 不是 迭代器,for 循環的 爲 迭代器
from collections import Iterator
print('isinstance([],Iterator):',isinstance([],Iterator))
print('isinstance((),Iterator):',isinstance((),Iterator))
print('isinstance({},Iterator):',isinstance({},Iterator))
print("isinstance('abc',Iterator):",isinstance('abc',Iterator))
print('isinstance((x for x in range(10)),Iterator):',isinstance((x for x in range(10)),Iterator))
print('isinstance(100,Iterator):',isinstance(100,Iterator))
print('-------------------- 分隔符 ------------------')


# 將 可迭代對象 變爲 迭代器 可使用 iter() 函數
from collections import Iterator
print('isinstance(iter([]),Iterator):',isinstance(iter([]),Iterator))
print('isinstance(iter(()),Iterator):',isinstance(iter(()),Iterator))
print('isinstance(iter({}),Iterator):',isinstance(iter({}),Iterator))
print("isinstance(iter('abc'),Iterator):",isinstance(iter('abc'),Iterator))
print('isinstance((x for x in range(10)),Iterator):',isinstance((x for x in range(10)),Iterator))
print('isinstance(iter(100),Iterator):',isinstance(iter(100),Iterator))  # 注:整數不是 可迭代對象,因此加iter()也不能成爲迭代器

# 小結:凡是可做用於for循環的對象都是Iterable類型;
# 凡是可做用於next()函數的對象都是Iterator類型,它們表示一個惰性計算的序列;
# 迭代器都是可迭代對象,可迭代對象不必定是迭代器。

高階函數map、reduce

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# map()函數:map()接收兩個參數,一個是函數,一個是Iterable,map將傳入的函數依次做用到序列的每一個元素,並把結果做爲新的Iterator返回。

# 示例一
def f(x):
    return x*x
r = map(f, [1, 2, 3, 4, 5])
print(list(r))

# 示例二
print(list(map(str, [1, 2, 3, 4, 5])))
print('------------------------------')


# reduce():做用在序列上,函數必須接收兩個參數。將結果繼續和序列下一個元素作累積計算。
# 在python3 中使用reduce函數要先從庫中加載

# 示例一:列表元素求和
from functools import reduce
def sum(x,y):
    return x+y
print(reduce(sum, [1, 2, 3, 4, 5]))

# 示例二:將 [1,3,5,7,9] 輸出爲 13579
from functools import reduce
def fn(m, n):
    return 10 * m + n
print(reduce(fn, [1, 3, 5, 7, 9]))
print('------------------------------')

# 練習一:
# 利用map()函數,把用戶輸入的不規範的英文名字,變爲首字母大寫,其餘小寫的規範名字。
# 輸入:['adam', 'LISA', 'barT'],輸出:['Adam', 'Lisa', 'Bart']
# 大寫字母轉小寫函數 lower(), 小寫字母轉大寫函數 upper()
L1 = ['adam', 'LISA', 'barT']
def normalize(name):
    return name[0].upper()+name[1:].lower()
L2 = list(map(normalize, L1))
print(L2)
print('------------------------------')

# 練習二:
# sum()函數和上面reduce()函數代碼都可求 list 的和,仿照定義 pord() 函數,求 list 的積
from functools import reduce
def s(x,y):
    return x * y
L = [3, 5, 7, 9]
def prod(L):
    return reduce(s, L)
print(prod(L))

print('------------------------------')

# 練習三:
# 利用 map 和 reduce 編寫一個 str2float 函數,把字符串'123.456'轉換成浮點數123.456
from functools import reduce
def str2float(s):
    s = s.split('.')    #以小數點爲分隔符,把字符串分爲兩部分
    def f1(x,y):        #函數1,小數點以前的數用這個函數處理
        return x * 10 + y
    def f2(x,y):        #函數2,小數點以後的數用這個函數處理
        return x / 10 + y
    def str2num(str):    #函數3,用於把字符串'123'逐個變爲數字
        return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[str]
    return reduce(f1,list(map(str2num,s[0]))) + reduce(f2,list(map(str2num,s[1]))[::-1])/10

print(str2float('123.456'))
# 最後一步是這個解法的精髓:
# 小數點前的數'123',用 x * 10 + y 正常求和就能得出123,小數點以後的數'456'要怎樣才能得出0.456呢?
# 首先把字符串'456'用list(map(str2num,s[1]))轉成一個列表[4,5,6]
# 而後用[::-1]切片的方式從後往前取,列表變爲[6,5,4]
# 而後把[6,5,4]利用reduce函數放到f2函數中計算,( 6 / 10 + 5) / 10 + 4 = 4.56,得出結果4.56
# 再除以一個10,得出0.456,到此成功把字符串'456'變成了浮點數0.456
# 把先後結果加起來,就獲得了最終解,成功把字符串'123.456'變成了浮點數123.456

filter

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 與map()相似,filter()也接收一個函數和一個序列。
# 和map()不一樣的是,filter()把傳入的函數依次做用於每一個元素,而後根據返回值是True仍是False決定保留仍是丟棄該元素。
# 而map()僅返回 True or False
def is_odd(n):
    return n % 2 == 1
print(list(filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9])))  # filter() 將自定義函數 is_odd() 爲True的值返回
print(list(map(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9])))      # map() 僅判斷 True or False,不做篩選
print('----------------------------------------------------------')


# 練習一:計算素數
# 首先,列出從2開始的全部天然數,構造一個序列:
# 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
# 取序列的第一個數2,它必定是素數,而後用2把序列的2的倍數篩掉:
# 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
# 取新序列的第一個數3,它必定是素數,而後用3把序列的3的倍數篩掉:
# 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
# 取新序列的第一個數5,而後用5把序列的5的倍數篩掉:
# 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
# 不斷篩下去,就能夠獲得全部的素數。

def _odd_iter():    # 選取從 2 以後,且不爲2倍數的數
    n = 1
    while True:
        n = n + 2
        yield n

def _not_divisible(n):    # 篩選掉以上所選數的倍數
    return lambda x: x % n > 0

def primes():    # 迭代過濾出知足要求的數 n
    yield 2
    it = _odd_iter()
    while True:
        n = next(it)
        yield n
        it = filter(_not_divisible(n), it)

def main():        # 給 n 一個取值,輸出這些數
    for n in primes():
        if n < 10:
            print(n)
        else:
            break

if __name__ == '__main__':
    main()

print('----------------------------------------------------------')

# 練習二:列出 1~1000 的回數(順着倒着讀都同樣,如:12321,909),使用filter()過濾掉非回數
def is_palindrome(n):
    return str(n) == str(n)[::-1]

output = filter(is_palindrome, range(1, 1000))
print(list(output))

sorted

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# sorted() 函數能夠對list元素按小到大排序
print(sorted([36, 5, -12, 9, -21]))

# 此外 sorted() 也是一個高階函數
print(sorted([36, 5, -12, 9, -21], key=abs))

# 字符串也是能夠排序的,按的首字母ASCII的大小
print(sorted(['bob', 'about', 'Zoo', 'Credit']))

# 若是要按字母順序,就須要加參數排除首字母大小寫 ASCII 大小不一的干擾
print(sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower))

print('-----------------------------------')

# 練習:
# 一組學生名字和成績tuple,分別按名字字母、成績排序
# L = [('Bob', 75), ('adam', 92), ('bart', 66), ('Lisa', 88)]

L = [('Bob', 75), ('adam', 92), ('bart', 66), ('Lisa', 88)]
def by_name(name):
    return name[0].lower()

def by_score(score):
    return score[1]

print(sorted(L, key=by_name))
print(sorted(L, key=by_score))
# 對於單個元組,(名字,成績): name[0] 爲名字,score[1] 爲成績

返回函數

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 函數做爲返回值
# map reduce filter sorted 等高階函數,它們將函數做爲參數,除次以外,函數還可做爲返回值。

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

f = lazy_sum(1, 2, 4, 5, 7, 8, 9)
print(f)    # 輸出錯誤,由於輸出f時,f = lazy_sum() ,輸出的是 lazy_sum() 函數裏面的 sum() 求和函數
print(f())  # 輸出 f() 時,纔是輸出 求和函數 sum() 的計算結果

f2 = lazy_sum(1, 2, 4, 5, 7, 8, 9)
print( f==f2 )      # 調用lazy_sum()時,每次調用都會返回一個新的函數,即便傳入相同的參數。 因此 False
print( f()==f2() )  # 函數的參數同樣,返回的結果值也同樣,因此 True

# *args 與 **args 的區別:
# *args和**args適用於函數的參數不肯定的時候。*args能夠看作是多個變量組成的tuple,**args能夠看作是個字典。

# def funarg1(arg):  #只容許傳入一個參數
#    print(arg)
# funarg1(1)
# >>1          #輸出執行結果

# def funarg(arg1,arg2,arg3): #必須傳入3個參數
#    print(arg1,arg2,arg3)
# funarg(1,2,3)
# >>1,2,3      #輸出執行結果

# def funargs(*args): #能夠傳入任意數量個參數(包括零個)
#    for i in args:
#        print(i)
# funargs(1,2,3,4,5)  #傳入5個參數
# list2=(2,3,4,5,6)
# funargs(list2)      #傳入列表
# funargs()
# >>1 2 3 4 5 (2,3,4,5,6)

print('----------------------------')

# 閉包
# why f1(), f2(), f3() returns 9, 9, 9 rather than 1, 4, 9?
def count():
    fs = []
    for i in range(1, 4):
        def f():
            return i * i
        fs.append(f)        # 此時函數f並無執行,只是返回了函數f
    return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())

print('----------------------------')

def count():
    fs = []
    for i in range(1, 4):
        def f():
            return i * i
        fs.append(f())        # 此時函數f執行了,返回了具體的結果數值。這就不屬於 返回函數 了
    return fs

f1, f2, f3 = count()

print(f1)
print(f2)
print(f3)

print('----------------------------')

# fix:
def count():
    fs = []
    def f(n):
        def j():
            return n * n
        return j
    for i in range(1, 4):
        fs.append(f(i))  # f(i)馬上被執行,所以i的當前值被傳入f()
    return fs

f1, f2, f3 = count()

print(f1())
print(f2())
print(f3())

# 小結:
# 函數既能夠的做爲高階函數的參數,又能夠做爲一個函數的返回函數。
# 返回一個函數時,該函數並未執行,返回函數中不要引用任何可能會變化的變量。

匿名函數

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 匿名函數 lambda x: x * x
# 匿名函數簡介方便,不用事先定義,也不用擔憂函數重名,但其只有有一個參數,一個表達式。

print(list(map(lambda x: x * x, [1, 2, 3, 4, 5])))

# 等同於:
def f(x):
    return x * x
print(list(f(x) for x in [1, 2, 3, 4, 5]))

偏函數

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# int()函數能夠把字符串轉換成整數
print(int('12345'))

# int()還可提供額外的base參數
print(int('12345',base=8))  #轉化成8進制

print('----------------')

# 若是常常轉換,每次都加 base 參數,很麻煩,能夠定義一個函數
def int2(x,base=2):
    return int(x, base)

print(int2('1011010'))

print('----------------')

# 其實不用自定義函數,python自帶的 functools.partial()偏函數 就能實現這一功能
import functools
int2 = functools.partial(int,base=2)  # functools.partial 就建立了一個偏函數

print(int2('1011010'))

類和實例

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 面向對象編程
# 類和實例

# 類是一個抽象的模版,實例是根據類建立出來的具體對象,屬性是這個實例所具備的能力
# 好比說貓類、狗類,而後狗類裏面又有具體的實例(泰迪、金毛、二哈),這些狗的實例都具備的屬性(愛吃肉、骨頭、會游泳)

# 定義 類 使用 class:
# class Student(object):
#    psss
# class 後面緊跟 類名(Student), 類名通常首字母大寫。(object)表示該類從哪一個類繼承下來的。

# 定義 實例, 經過 類名+()實現
class Student(object):    # 建立Student類
    pass
bart = Student()      # 建立 bart 實例
bart.name = 'simpson'  # 給實例綁定屬性,name,這個實例叫什麼
print(bart.name)

# 建立實例的時候,把一些必須綁定的屬性強制填寫進去,經過 __init__ 方法 添加上相關屬性。
# 以雙下劃線'__'開頭和結尾的是特殊變量
class Student(object):
    def __init__(self, name, score):    # __init__ 方法的第一個參數永遠是 self
        self.name = name
        self.score = score
bart = Student('simpson', 99)
print(bart.name)
print(bart.score)

print('------------------- ')


# 數據封裝
class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def print_score(self):
        print('%s: %s' % (self.name, self.score))
    def grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'
# 以上整個類能夠封裝起來,對於用戶來講,只要輸入 名字、成績 便可,不須要了解過程

# 輸入
bart = Student('simpson', 99)
bart1 = Student('john', 67)
bart2 = Student('tom', 34)

# 輸出
print('bart.name=', bart.name)
print('bart.score=', bart.score)
bart.print_score()
print('grade of bart:', bart.grade())
print('grade of bart1:', bart1.grade())
print('grade of bart2', bart2.grade())

訪問限制

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 普通的類、實例、屬性代碼,可執行無報錯
class Student():
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def print_score(self):
        print('%s: %s' % (self.name, self.score))

bart = Student('simpson', 99)
print(bart.name)

# 作了訪問限制的屬性,從外部訪問該實例的屬性,不能執行,回顯錯誤
class Student():
    def __init__(self, name, score):
        self.__name = name        # 學生類的 __name__ 屬性,是內部屬性,外部不可訪問
        self.__score = score      # 學生類的 __score__ 屬性,是內部屬性,外部不可訪問
    def print_score(self):
        print('%s: %s' % (self.__name, self.__score))

bart = Student('simpson', 99)
# print(bart.__name)    # 不可訪問,代碼報錯。由於python解釋器把 __name 變成了 _Student__name
print(bart._Student__name)    # 若是要在外部訪問,可使用 _Student__name

繼承和多態

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 繼承:能夠把父類的功能直接拿過來,也可新增本身的方法,也可覆蓋重寫父類的方法,
# 這也造就了子類比父類有更多的可能,造成多態。

class Animal(object):    # 父類 動物類
    def run(self):
        print('Animal is running...')

class Dog(Animal):      # 子類 狗類
    pass
class Cat(Animal):      # 子類 貓類
    pass

dog = Dog()
cat = Cat()

dog.run()    # 無需再定義run(),直接調用父類的函數
cat.run()

print('---------------------')

# 多態
class Animal(object):
    def run(self):
        print('Animal is running...')

class Dog(Animal):
    def run(self):
        print('Dog is running...')    # 覆蓋父類的方法
    def eat(self):
        print('Liking eat meat.')      # 新增本身的方法

dog = Dog()

dog.run()
dog.eat()

獲取對象信息

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# type() 判斷對象類型
print(type(123))    # int型
print(type('abc'))  # str
print(type(None))    # NoneType
print(type(abs))    # 函數方法

print(type(123)==type(456))  # 判斷是否爲同種類型, True or False。
print(type(123)==int)

print('----------------')

# isinstance() 與 type() 做用相同, isinstance() 多用於 class 繼承關係裏
class Animal(object):
    pass
class Dog(Animal):
    pass
class Husky(Dog):
    pass

a = Animal()
d = Dog()
h = Husky()

print(isinstance(h, Husky))
print(isinstance(h, Dog))
print(isinstance(h, Animal))

# dir():得到一個對象的全部屬性和方法
print(dir('ABC'))

# 除了把對象的屬性和方法列出來,還可以使用 getattr()、setattr()、hasattr() 直接操做一個對象的狀態
# getattr() 獲取對象屬性, setattr() 設置對象屬性, hasattr() 詢問對象是否有某屬性
class MyObject(object):
    def __init__(self):
        self.x = 9
    def power(self):
        return self.x * self.x
obj = MyObject()

print(hasattr(obj, 'x'))    # obj 有 x 屬性嗎?
print(getattr(obj, 'x'))    # 獲取 x 屬性的結果
print(obj.x)                # 等同於 getattr()
print(hasattr(obj, 'y'))    # 詢問是否有 y 屬性

setattr(obj, 'y', 10)        # 設置 y 屬性及其具體值
print(getattr(obj, 'y'))    # 獲取 y 屬性結果

實例屬性和類屬性

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 實例屬性 和 類屬性 不要使用相同的名字,同名的 實例屬性 將覆蓋 類屬性,當刪除 實例屬性 後,訪問的是 類屬性

class Student(object):        # Student類
    name = 'Student'          # 類的 name 屬性

s = Student()                # 類的 實例s

print(s.name)                # 打印 實例s 的 name屬性,s並無該屬性,往上找到它的類的 name屬性
print(Student.name)          # 打印 類的 name屬性

s.name = 'Michael'            # 給實例s設置一個name屬性 Michael
print(s.name)                # 因爲 實例屬性 優先級比 類屬性 高,覆蓋 類屬性,打印出 實例屬性
print(Student.name)          # 打印 類屬性

del s.name                    # 刪除 實例屬性
print(s.name)                # 輸出的就是 類屬性

限制實例屬性__slots__

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 動態語言能夠隨時給實例綁定任何屬性和方法
class Student(object):      # 定義一個類
    pass

s = Student()              # 建立類的 實例s
s.name = 'Michael'          # 動態給 實例s 加一個 name屬性
print(s.name)

def set_age(self, age):    # 定義一個函數做爲實例方法
    self.age = age

from types import MethodType
s.set_age = MethodType(set_age, s)    # 給 實例s 綁定 set_age 方法
s.set_age(25)        # 調用 set_age 方法
print(s.age)


s2 = Student()      # 建立類的 實例s2
# s2.set_age(15)      # 調用 set_age 方法
# print(s2.age)      # 輸出結果出錯,由於 s2 並未綁定 set_age 方法,給一個實例綁定方法,對另外一個實例不起做用

# 爲了給全部實例都添加可調用的方法,可對 class 綁定方法
# 方法一:動態綁定,可在程序運行過程當中動態給 class 加上功能,這在靜態語言中很難實現
def set_score(self, score):        # 程序任意位置定義 set_score 方法
    self.score = score

Student.set_score = set_score      # 給 Student類 綁定 set_score 方法

s.set_score(100)        # 實例s 可直接調用 class 方法
print(s.score)
s2.set_score(99)        # 實例s2 也可直接調用 class 方法
print(s2.score)

# 方法二:直接在最初建立類的地方定義類的方法
class Student(object):
    def set_score(self, score):
        self.score = score

# 特殊變量 __slots__  (前面還學習到特殊變量__init__)
# 該變量可限制實例屬性,只容許添加定義的屬性,至關於屬性白名單。
# __slots__ 僅對當前類的實例生效,對其繼承的子類實例不生效
class Student(object):
    __slots__ = ('name', 'age')    # 只容許定義這兩種屬性

s = Student()      # 建立實例
s.name = 'Tom'      # 添加實例 name屬性
s.age = '17'        # 添加實例 age屬性
# s.score = '90'    # 添加實例 score屬性:不被容許,報錯
print(s.name)
print(s.age)
# print(s.score)

class Xiaoming(Student):    # 建立子類 Xiaoming
    pass

y = Xiaoming()        # 建立實例y
y.name = 'xm'
y.age = '18'
y.score = '99'        # 父類中 禁用的屬性,不影響 子類 的使用
print(y.name)
print(y.age)
print(y.score)        # 正常打印 y.score

使用@property

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#屬性函數(property):
#將類方法轉換爲只讀屬性
#從新實現一個屬性的setter和getter方法

class Student(object):

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

s = Student()
s.score = 60
print('s.score =', s.score)
# ValueError: score must between 0 ~ 100!
s.score = 9999

多重繼承

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# MixIn
#「混入」:Mix in。
# 在設計類的繼承關係時,一般,主線都是單一繼承下來的。可是,若是須要「混入」額外的功能,
# 經過多重繼承就能夠實現。

# 動物類
class Animal(object):
    pass

# 又將動物分爲哺乳動物和鳥類:
class Mammal(Animal):
    pass
class Bird(Animal):
    pass

# 上面兩類又能夠細分各類動物類:
class Dog(Mammal):
    pass
class Bat(Mammal):
    pass
class Parrot(Bird):
    pass
class Ostrich(Bird):
    pass

# 上面的各類動物也能夠按 地上跑的 和 天上飛的分類:
class Runnable(object):
    def run(self):
        print('Running...')

class Flyable(object):
    def fly(self):
        print('Flying...')

# 細分的動物能夠繼承多個類:
class Dog(Mammal, Runnable):
    pass
class Bat(Mammal, Flyable):
    pass

枚舉類

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Enum能夠把一組相關常量定義在一個class中,且class不可變,並且成員能夠直接比較。能夠枚舉出該類。

from enum import Enum

Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

for name, member in Month.__members__.items():
    print(name, '=>', member, ',', member.value)

print('--------------------------------------')

from enum import Enum, unique

@unique
class Weekday(Enum):
    Sun = 0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6

day1 = Weekday.Mon

print('day1 =', day1)
print('Weekday.Tue =', Weekday.Tue)
print('Weekday[\'Tue\'] =', Weekday['Tue'])
print('Weekday.Tue.value =', Weekday.Tue.value)
print('day1 == Weekday.Mon ?', day1 == Weekday.Mon)
print('day1 == Weekday.Tue ?', day1 == Weekday.Tue)
print('day1 == Weekday(1) ?', day1 == Weekday(1))

print('--------------------------------------')

for name, member in Weekday.__members__.items():
    print(name, '=>', member, ',', member.value)

文件讀寫

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 文件讀取

# 文件讀寫時都有可能產生IOError,一旦出錯,後面的f.close()就不會調用。
# 因此,爲了保證不管是否出錯都能正確地關閉文件,咱們可使用try ... finally來實現:
try:
    f = open('/Users/xxx/Desktop/sqltest.txt', 'r')  #r 爲read
    print(f.read())
finally:
    if f:
        f.close()

# 這麼寫太繁瑣,Python引入了with語句來自動幫咱們調用close()方法
with open('/Users/xxx/Desktop/sqltest.txt', 'r') as f:
    print(f.read())

# 若是文件很小,read()一次性讀取最方便;若是不能肯定文件大小,反覆調用read(size)比較保險,
# 但一次次調用繁瑣,因而能夠調用下面兩種:
# readline()能夠每次讀取一行內容,readlines()一次讀取全部內容並按行返回list。
with open('/Users/xxx/Desktop/sqltest.txt', 'r') as f:
    print(f.read())
    for line in f.readlines():
        print(line.strip()) # 把末尾的'\n'刪掉

# 二進制文件讀取
f = open('/Users/michael/test.jpg', 'rb') #讀取二進制文件(read bytes),好比圖片、視頻等,用 rb 模式打開
print(f.read())

# 字符編碼
f = open('/Users/michael/gbk.txt', 'r', encoding='gbk') #gbk編碼
print(f.read())

# 寫文件
# case1:
f = open('/Users/michael/test.txt', 'w')
f.write('hello world!')
f.close
# case2:
with open('/Users/michael/test.txt', 'w') as f:
    f.write('hello world!')

StringIO_BytesIO

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# StringIO 在內存中讀寫str。
from io import StringIO
f = StringIO()
f.write('hello')
f.write(' ')
f.write('world!')
print(f.getvalue())

print('----------------------')

from io import StringIO
f = StringIO('Hello!\nHi!\nGoodbye!')
while True:
    s = f.readline()
    if s == '':
        break
    print(s.strip())
print('----------------------')

# StringIO操做的只能是str,若是要操做二進制數據,就須要使用BytesIO。
from io import BytesIO
f = BytesIO()
f.write('中文'.encode('utf-8'))
print(f.getvalue())

from io import BytesIO
f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
print(f.read())

操做文件和目錄

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 在操做系統中對文件的操做能夠直接使用cp、dir等系統命令完成。
# Python中內置的 os 模塊也能夠直接調用操做系統提供的接口函數。

import os
print(os.name) # 輸出系統結果, nt 表明windows系統, posix 表明linux/unix/macos
#print(os.uname())  # 輸出詳細的系統信息(只針對於 非 windows系統,windows會報錯)

# 輸出環境變量
import os
print(os.environ)  # 輸出環境變量

# 輸出指定環境變量的值
print(os.environ.get('PATH'))  # 輸出環境變量的路徑


# 查看當前目錄的絕對路徑
print(os.path.abspath('.'))

# 在某個目錄下建立一個新目錄,首先把新目錄的完整路徑表示出來
print(os.path.join('/Users/xxx', '111'))
# windows下會顯示 /Users/xxx\111 ,但不影響生成目錄
# linux下會顯示  /Users/xxx/111

# 在某個路徑下新建一個新目錄
print(os.mkdir('/Users/xxx/111'))

# 刪除該新增目錄
print(os.rmdir('/Users/xxx/111'))

# 目錄拆分
print(os.path.split('/Users/xxx/111'))
# 這樣能夠把一個路徑拆分爲兩部分,後一部分老是最後級別的目錄或文件名

# os.path.splitext() 能夠獲得文件的擴展名
print(os.path.splitext('/Users/xxx/111/test.txt'))

#### 注: os.path.join()、os.path.split()、os.path.splitext(),合併、拆分不須要這些文件、
#### 文件夾真是存在,他們只對字符串進行操做。


# 文件重命名
print(os.rename('/Users/xxx/111/test.txt', '/Users/xxx/111/te.py'))

# 刪除文件
print(os.remove('/Users/xxx/111/123.txt'))

# 建立文件能夠結合前面的文件讀寫
with open('/users/xxx/111/123.txt', 'w') as f:
    f.write('hello world')

# 複製文件
# 雖然 os 模塊沒有複製文件的函數,但 shutil模塊中有,它能夠看做是 os模塊的補充模塊


# 過濾文件
# 輸出當前目錄下的文件夾
import os
L = [x for x in os.listdir('.') if os.path.isdir(x)]
print(L)

# 輸出當前目錄下的py文件
M = [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1] == '.py']
print(M)

代碼實現dir-l功能

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from datetime import datetime
import os

pwd = os.path.abspath('.')

print('      Size    Last Modified  Name')
print('------------------------------------------------------------')

for f in os.listdir(pwd):
    fsize = os.path.getsize(f)
    mtime = datetime.fromtimestamp(os.path.getmtime(f)).strftime('%Y-%m-%d %H:%M')
    flag = '/' if os.path.isdir(f) else ''
    print('%10d  %s  %s%s' % (fsize, mtime, f, flag))

序列化_pickle模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 序列化:
# Python中叫pickling。把變量從內存中變成可存儲或傳輸的過程稱之爲序列化,如把內存中的字符字符串以二進制格式存儲在硬盤上。

# 反序列化:
# Python中叫unpickling。反過來,把變量存儲起來的內容從序列化的對象從新讀到內存裏稱之爲反序列化。

# 將一個對象序列化並寫入文件:
# 1.將對象序列化:
import pickle
d = dict(name='Bob', age=20, score=80)
print(pickle.dumps(d))  # pickle.dumps() 方法將任意對象序列化成一個bytes

print('---------------------------')

# 2.寫入文件(新建文件dump.txt)
f = open('dump.txt', 'wb')
pickle.dump(d, f)
f.close()

print('---------------------------')

# 將對象反序列化,從磁盤讀取到內存
f = open('dump.txt', 'rb')
d = pickle.load(f)
f.close()
print(d)

JSON

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 不一樣的編程語言之間傳遞對象,就必須把對象序列化爲標準格式,好比XML,
# 但更好的方法是序列化爲JSON。
# JSON不只是標準格式,而且比XML更快,並且能夠直接在Web頁面中讀取,很是方便。

# json標準規定編碼爲 utf-8

# dumps()方法返回一個str,內容是標準json。相似dump()方法能夠直接把json寫入一個file-likes Object
import json
import pickle
d = dict(name='Bob', age=20, score=88)
print(json.dumps(d))

# 把json反序列化爲Python對象,用loads()或者load()
# 前者把json字符串反序列化,後者從file-like Object中讀取字符串並反序列化
json_str = '{"age":20, "score":88, "name":"Bob"}'
print(json.loads(json_str))

多進程

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# unix/linux操做系統提供了一個 fork() 函數,
# 經過系統調用建立一個與原來進程幾乎徹底相同的進程,這個新產生的進程稱爲子進程。
# 只須要調用getppid()就能夠拿到父進程的ID。
# 子進程用getpid()查看PID。

import os
print('Process (%s) start...' % os.getpid())

# 如下在linux/unix/macos下執行,由於windows沒有fork調用
'''
if pid == 0:
    print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
else:
    print('I (%s) just created a child process (%s).' % (os.getpid(), pid))
'''

# multiprocessing:python多進程模塊
from multiprocessing import Process
import os

# 子進程執行的代碼
def run_proc(name):
    print('Run child process %s (%s)...' % (name, os.getpid()))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Process(target=run_proc, args=('test',))
    print('child process will start.')
    p.start()
    p.join()
    print('child process end.')
# join()方法 用於將序列中的元素以指定的字符鏈接生成一個新的字符串。


# Pool:進程池。用於要啓用大量子進程時,批量建立子進程。
from multiprocessing import Pool
import os, time, random

def long_time_task(name):
    print('Run task %s (%s)...' % (name, os.getpid()))
    start = time.time()
    time.sleep(random.random()*3)
    end = time.time()
    print('Task %s runs %0.2f seconds.' % (name, (end-start)))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Pool(4)
    for i in range(5):
        p.apply_async(long_time_task, args=(i, ))
    print('Waiting for all subprocesses done...')
    p.close()
    p.join()
    print('All subprocesses done.')


# 子進程
# subprocess模塊可讓咱們很是方便地啓動一個子進程,而後控制其輸入和輸出。
import subprocess

print('$ nslookup www.python.org') # 打印出內容,爲顯示好看,無實際做用。
r = subprocess.call(['nslookup', 'www.python.org'])
print('Exit code:', r)


import subprocess

print('$ nslookup')
p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate(b'set q=mx\npython.org\nexit\n')
print(output.decode('gbk'))
print('Exit code:', p.returncode)


# 進程間通訊
# Process之間確定是須要通訊的,操做系統提供了不少機制來實現進程間的通訊。
# Python的multiprocessing模塊包裝了底層的機制,提供了Queue、Pipes等多種方式來交換數據。
from multiprocessing import Process, Queue
import os, time, random

# 寫數據進程執行的代碼:
def write(q):
    print('Process to write: %s' % os.getpid())
    for value in ['A', 'B', 'C']:
        print('Put %s to queue...' % value)
        q.put(value)
        time.sleep(random.random())

# 讀數據進程執行的代碼:
def read(q):
    print('Process to read: %s' % os.getpid())
    while True:
        value = q.get(True)
        print('Get %s from queue.' % value)

if __name__=='__main__':
    # 父進程建立Queue,並傳給各個子進程:
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    # 啓動子進程pw,寫入:
    pw.start()
    # 啓動子進程pr,讀取:
    pr.start()
    # 等待pw結束:
    pw.join()
    # pr進程裏是死循環,沒法等待其結束,只能強行終止:
    pr.terminate()

多線程

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 多任務能夠由多進程完成,也可由一個進程的多個線程完成。
# Python標準庫提供 _thread(低級模塊) 和 threading(高級模塊) 兩個模塊進行多線程處理。

import time, threading

# 新線程執行的代碼:
def loop():
    print('thread %s is running...' % threading.current_thread().name)
    n = 0
    while n<5:
        n = n+1
        print('thread %s >>> %s' % (threading.current_thread().name, n))
        time.sleep(1)
    print('thread %s ended.' % threading.current_thread().name)

print('thread %s is running...' % threading.current_thread().name)
t = threading.Thread(target=loop, name='LoopThread')
t.start()
t.join()
print('thread %s ended.' % threading.current_thread().name)


# Lock
# 多線程和多進程最大的不一樣在於,多進程中,同一個變量,各自有一份拷貝存在於每一個進程中,
# 互不影響,而多線程中,全部變量都由全部線程共享,因此,任何一個變量均可以被任何一個線程修改,
# 所以,線程之間共享數據最大的危險在於多個線程同時改一個變量,把內容給改亂了。
import time, threading

balance = 0
lock = threading.Lock()

def change_it(n):
    global balance
    balance = balance + n
    balance = balance - n

def run_thread(n):
    for i in range(100000):
        # 先獲取鎖
        lock.acquire()
        try:
            # 更改數據
            change_it(n)
        finally:
            # 改完釋放鎖
            lock.release()


t1 = threading.Thread(target=run_thread, args=(5,))
t2 = threading.Thread(target=run_thread, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

# 注:
# 進程(Process) 比 線程(thread) 更穩定,windows下建立進程開銷巨大。

正則表達式

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 正則表達式
# 正則表達式(Regular Expression,通常簡寫爲RegEx或者RegExp),
# 也譯爲正規表示法、常規表示法,在計算機科學中,是指一個用來描述
# 或者匹配一系列符合某個句法規則的字符串的單個字符串。

# 用法細節見筆記「正則表達式」

# re模塊
import re
print(re.match(r'^\d{3}\-\d{3,8}$', '010-12345'))
print(re.match(r'^\d{3}\-\d{3,8}$', '010 12345'))
# match()方法判斷是否匹配成功,成功返回Match對象,失敗返回None

print(r'a b  c'.split(' '))
print(re.split(r'\s+', 'a b  c'))

datetime模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from datetime import datetime  # 導入datetime模塊中的datetime類
now = datetime.now()
print(now)

print(type(now))

# 獲取指定日期和時間
from datetime import datetime
dt = datetime(2015, 4, 19, 12, 20, 00)
print(dt)

# 1970年1月1日 00:00:00 UTC+00:00時區的時刻稱爲 epoch time
# 當前時間就是相對於epoch time的秒數,稱爲timestamp
# 示例:
# epochtime = 1970-1-1 00:00:00 UTC+0:00
# timestamp = 1970-1-1 09:00:00 UTC+9:00

# datetime 轉換爲 timestamp
# 使用timestamp()函數
from datetime import datetime
dt = datetime(2015, 4, 19, 12, 20, 00)
print(dt.timestamp())

# timestamp 轉換爲 datetime
# 使用 datetime 提供的 fromtimestamp()方法
from datetime import datetime
t = 1429417200.0
print(datetime.fromtimestamp(t))

# str轉換爲datetime
# 不少時候用戶輸入的是字符串,得把str轉換datetime。
# 經過datetime.strptime()實現,須要一個日期和時間的格式化字符串
from datetime import datetime
cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')
print(cday)

# datetime轉換爲str
# 若是已經有了datetime對象,將它格式化爲字符串現實給用戶,就須要轉換str
# 用 strftime() 實現。
from datetime import datetime
now = datetime.now()
print(now.strftime('%a, %b %d %H:%M'))

# 小結
# datetime表示的時間須要時區信息才能肯定一個特定的時間,不然只能視爲本地時間。
# 若是要存儲datetime,最佳方法是將其轉換爲timestamp再存儲,由於timestamp的值與時區徹底無關。

collections模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# collections是Python內建的一個集合模塊,提供了許多有用的集合類。

# namedtuple()函數用來建立自定義 tuple對象,且規定 tuple元素的個數。
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])  # 規定tuple元素爲 x, y
p = Point(1, 2)
print(p.x)
print(p.y)


# deque
# 實現高效插入與刪除操做的雙向列表,適合於隊列和棧。
# (list是線性存儲,按索引訪問元素很快,但插入和刪除元素就很慢)
from collections import deque
q = deque(['a', 'b', 'c'])
q.append('x')
q.appendleft('y')
print(q)

# defaultdict
# 使用dict時,若是引用的Key不存在,就會拋出KeyError。
# 使用defaultdict若是Key不存在會返回一個默認值。
from collections import defaultdict
dd = defaultdict(lambda : 'N/A')
dd['key1'] = 'abc'
print(dd['key1'])  # key1存在,正常輸出
print(dd['key2'])  # key2不存在,返回默認值 N/A

# OrderedDict
# 在對dict作迭代時,key是無序的。OrderedDict會保持按插入的順序輸出。
# 即 FIFO(先進先出),當容量超出限制時,先刪除最先添加的Key。
from collections import OrderedDict
d = dict([('a', 1), ('b', 2), ('c', 3)])
print(d)  # 無序輸出
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
print(od)  # 順序輸出,先入先出

# Counter
# Counter是一個簡單的計數器,統計字符出現的次數。
from collections import Counter
c = Counter()
for ch in 'programming':
    c[ch] = c[ch] + 1
print(c)

base64模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import base64
print(base64.b64encode(b'testtest'))  # 編碼
print(base64.b64decode(b'dGVzdHRlc3Q='))  # 解碼

hashlib模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 摘要算法:
# 摘要算法又稱哈希算法、散列算法。它經過一個函數,
# 把任意長度的數據轉換爲一個長度固定的數據串(一般用16進制的字符串表示)

# hashlib提供常見的摘要算法,如:md5,sha1.
# case1(md5):
import hashlib
md5 = hashlib.md5()
md5.update('just test'.encode('utf-8'))
print(md5.hexdigest())

# case2(sha1):
import hashlib
sha1 = hashlib.sha1()
sha1.update('just test'.encode('utf-8'))
print(sha1.hexdigest())

# 小結
# 摘要算法在不少地方都有普遍的應用。要注意 摘要算法 不是 加密算法,
# 不能用於加密(由於沒法經過摘要反推明文),只能用於防篡改。
# 可是它的單向計算特性決定了能夠在不存儲明文口令的狀況下驗證用戶口令。

hmac模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# hmac模塊實現標準的Hmac算法,將原始消息message加入隨機的key,哈希算法生成加salt的密文。
import hmac
message = b'Hello world!'
key = b'secret'
h = hmac.new(key, message, digestmod='MD5')
print(h.hexdigest())  # 加鹽的md5加密

import hashlib
message = hashlib.md5()
message.update('Hello world!'.encode('utf-8'))
print(message.hexdigest())  # 未加鹽,密文結果不一樣

# 小結
# Python內置的hmac模塊實現了標準的Hmac算法,它利用一個key對message計算「雜湊」後
# 的hash,# 使用hmac算法比標準hash算法更安全,由於針對相同的message,不一樣的key會
# 產生不一樣的hash。

itertools模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# itertools模塊提供了用於操做迭代對象的函數。
# count()會建立一個無限的迭代器,將數據一直打印出來,必須按ctrl+c退出。
import itertools
natuals = itertools.count(1)
for n in natuals:
    print(n)


# cycle()會將一個序列無限重複下去,一樣停不下來。
import itertools
cs = itertools.cycle('ABC')
for c in cs:
    print(c)


# repeat()能夠將一個元素無限重複下去,不過其第二個參數能夠控制重複次數
import itertools
ns = itertools.repeat('A', 5)
for n in ns:
    print(n)


# 無限序列雖然能夠無限迭代下去,但能夠用 takewhile()函數 經過條件判斷來截取有限序列
import itertools
natuals = itertools.count(1)
ns = itertools.takewhile(lambda x: x<=10, natuals)  # 限定只取10及之內的數
print(list(ns))  # 輸出取的數的列表


# chain()
# 把一組迭代對象串聯起來,造成一個更大的迭代器
import itertools
for c in itertools.chain('ABC','XYZ'):
    print(c)  # 輸出 A B C X Y Z


# groupby()
# 把迭代器中相鄰的重複元素跳出來放在一塊兒
import itertools
for key, group in itertools.groupby('AAABBBCCCAAA'):
    print(key, list(group))
# 輸出:
# A ['A', 'A', 'A']
# B ['B', 'B', 'B']
# C ['C', 'C', 'C']
# A ['A', 'A', 'A']

# 上面字符必須大小寫統一,若是大小寫混雜,可使用upper(),
# 其會將小寫字符轉變爲大寫字符排列,與lower()功能相反。
import itertools
for key, group in itertools.groupby('AAaBbBcCCaAA', lambda x: x.upper()):
    print(key, list(group))

contextlib模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
class Query(object):

    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print('Begin')
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type:
            print('Error')
        else:
            print('End')

    def query(self):
        print('Query info about %s...' % self.name)

with Query('Bob') as q:
    q.query()

urllib模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# urllib提供了一系列用於操做url的功能

# get
from urllib import request

with request.urlopen('https://api.douban.com/v2/book/2129650') as f:
    data = f.read()
    print('Status:', f.status, f.reason)
    for k, v, in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', data.decode('utf-8'))
# 能夠獲取到http相應頭和json數據
'''
Status: 200 OK
Date: Wed, 06 Dec 2017 03:51:05 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 2058
Connection: close
Vary: Accept-Encoding
X-Ratelimit-Remaining2: 98
X-Ratelimit-Limit2: 100
Expires: Sun, 1 Jan 2006 01:00:00 GMT
Pragma: no-cache
Cache-Control: must-revalidate, no-cache, private
Set-Cookie: bid=ernch-JwbnQ; Expires=Thu, 06-Dec-18 03:51:05 GMT; Domain=.douban.com; Path=/
X-DOUBAN-NEWBID: ernch-JwbnQ
X-DAE-Node: sindar1b
X-DAE-App: book
Server: dae
Data: {"rating":{"max":10,"numRaters":16,"average":"7.4","min":0},"subtitle":"","author":["廖雪峯"],"pubdate":"2007","tags":[{"count":21,"name":"spring","title":"spring"},{"count":13,"name":"Java","title":"Java"},{"count":6,"name":"javaee","title":"javaee"},{"count":5,"name":"j2ee","title":"j2ee"},{"count":4,"name":"計算機","title":"計算機"},{"count":4,"name":"編程","title":"編程"},{"count":3,"name":"藏書","title":"藏書"},{"count":3,"name":"POJO","title":"POJO"}],"origin_title":"","image":"https://img3.doubanio.com\/mpic\/s2552283.jpg","binding":"平裝","translator":[],"catalog":"","pages":"509","images":{"small":"https://img3.doubanio.com\/spic\/s2552283.jpg","large":"https://img3.doubanio.com\/lpic\/s2552283.jpg","medium":"https://img3.doubanio.com\/mpic\/s2552283.jpg"},"alt":"https:\/\/book.douban.com\/subject\/2129650\/","id":"2129650","publisher":"電子工業出版社","isbn10":"7121042622","isbn13":"9787121042621","title":"Spring 2.0核心技術與最佳實踐","url":"https:\/\/api.douban.com\/v2\/book\/2129650","alt_title":"","author_intro":"","summary":"本書注重實踐而又深刻理論,由淺入深且詳細介紹了Spring 2.0框架的幾乎所有的內容,並重點突出2.0版本的新特性。本書將爲讀者展現如何應用Spring 2.0框架建立靈活高效的JavaEE應用,並提供了一個真正可直接部署的完整的Web應用程序——Live在線書店(http:\/\/www.livebookstore.net)。\n在介紹Spring框架的同時,本書還介紹了與Spring相關的大量第三方框架,涉及領域全面,實用性強。本書另外一大特點是實用性強,易於上手,以實際項目爲出發點,介紹項目開發中應遵循的最佳開發模式。\n本書還介紹了大量實踐性極強的例子,並給出了完整的配置步驟,幾乎覆蓋了Spring 2.0版本的新特性。\n本書適合有必定Java基礎的讀者,對JavaEE開發人員特別有幫助。本書既能夠做爲Spring 2.0的學習指南,也能夠做爲實際項目開發的參考手冊。","price":"59.8"}
'''

# 模擬瀏覽器發送請求,須要往 Request對象 添加http頭信息
from urllib import request

req = request.Request('http://www.douban.com/')
req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0')
with request.urlopen(req) as f:
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', f.read().decode('utf-8'))


# post
# 發送一個post請求,只需把data以bytes形式傳入。
# 模擬微博登錄
from urllib import request,parse

print('Login to weibo.cn...')
email = input('Email:')
passwd = input('Password:')
login_data = parse.urlencode([
    ('username', email),
    ('password', passwd),
    ('entry', 'mweibo'),
    ('client_id', ''),
    ('savestate', '1'),
    ('ec', ''),
    ('pagerefer', 'https://passport.weibo.cn/signin/welcome?entry=mweibo&r=http%3A%2F%2Fm.weibo.cn%2F')
])

req = request.Request('https://passport.weibo.cn/sso/login')
req.add_header('Origin', 'https://passport.weibo.cn')
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0')
req.add_header('Referer', 'https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=http%3A%2F%2Fm.weibo.cn%2F')

with request.urlopen(req, data = login_data.encode('utf-8')) as f:
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', f.read().decode('utf-8'))


# handler
# 經過一個代理 proxy 去訪問網站,須要用 ProxyHandler 來處理。
from urllib import request
proxy_handler = urllib.request.ProxyHandler(['http': 'http://www.example.com:1080/'])
proxy_auth_handler = urllib.request.ProxyBasicAuthHandler()
proxy_auth_handler.add_password('realm', 'host', 'username', 'password')
opener = urllib.request.build_opener(proxy_handler, proxy_auth_handler)
with opener.open('http://www.example.com/login.html') as f:
    pass


# 小結
# urllib提供的功能就是利用程序去執行各類HTTP請求。若是要模擬瀏覽器完成特定功能,
# 須要把請求假裝成瀏覽器。假裝的方法是先監控瀏覽器發出的請求,再根據瀏覽器的請求
# 頭來假裝,User-Agent頭就是用來標識瀏覽器的。

XML解析

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# python解析xml,準備好三個事件函數 start_element, end_element, char_data 就能夠完成。
# 示例: <a href="/">python</a>
# 會產生3個事件:
# 1.start_element事件,讀取:<a href="/">;
# 2.char_data事件,讀取:python;
# 3.end_element事件,讀取:</a>。

from xml.parsers.expat import ParserCreate

class DefaultSaxHandler(object):
    def start_element(self, name, attrs):
        print('sax:start_element: %s, attrs: %s' % (name, str(attrs)))

    def end_element(self, name):
        print('sax:end_element: %s' % name)

    def char_data(self, text):
        print('sax:char_data: %s' % text)

xml = r'''<?xml version="1.0"?>
<ol>
    <li><a href="/python">Python</a></li>
    <li><a href="/ruby">Ruby</a></li>
</ol>
'''

handler = DefaultSaxHandler()
parser = ParserCreate()
parser.StartElementHandler = handler.start_element
parser.EndElementHandler = handler.end_element
parser.CharacterDataHandler = handler.char_data
parser.Parse(xml)

HTMLParser模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from html.parser import HTMLParser
from html.entities import name2codepoint

class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print('<%s>' % tag)

    def handle_endtag(self, tag):
        print('</%s>' % tag)

    def handle_startendtag(self, tag, attrs):
        print('<%s/>' % tag)

    def handle_data(self, data):
        print(data)

    def handle_comment(self, data):
        print('<!--', data, '-->')

    def handle_entityref(self, name):
        print('&%s;' % name)

    def handle_charref(self, name):
        print('&#%s;' % name)

parser = MyHTMLParser()
parser.feed('''<html>
<head></head>
<body>
<!-- test html parser -->
    <p>Some <a href=\"#\">html</a> HTML&nbsp;tutorial...<br>END</p>
</body></html>''')

# feed()方法能夠屢次調用,也就是不必定一次把整個HTML字符串都塞進去,
# 能夠一部分一部分塞進去。

pillow模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from PIL import Image
im = Image.open('101010.jpg')
w, h = im.size
print('Original image size: %sx%s' % (w, h))  # 輸出原始圖像大小
im.thumbnail((w//2, h//2))
print('Resize image to: %sx%s' % (w//2, h//2))  # 輸出的圖片寬高縮小一半
im.save('thumbnail.jpg', 'jpeg')

requests模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# requests
# python內置的urllib模塊用於訪問網絡資源,但用起來麻煩,缺乏不少實用的高級功能。
# requests處理url更方便。

#get
import requests
r = requests.get('https://www.douban.com/')
print(r.status_code)  # 輸出頁面狀態碼 200
print(r.text)  # 輸出內容

# 對於帶參數的url,傳入一個dict做爲params參數
import requests
r = requests.get('https://www.douban.com/search', params={'q':'python', 'cat':'1001'})
print(r.url)
# 此代碼實際請求的url是 https://www.douban.com/search?q=python&cat=1001


# requests自動檢測編碼,可使用 encoding屬性查看:
print(r.encoding)

# content 獲取響應內容(無論是文本仍是二進制內容均以二進制獲取)
print(r.content)

# requests方便在於特定類型的響應,如 JSON,可直接獲取
r = requests.get('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20%3D%202151330&format=json')
print(r.json())

# 傳入 HTTP Header 時,可加入 dict 添加headers 參數
r = requests.get('https://www.douban.com/', headers={'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit'})
print(r.text)   # 以文本內容獲取

# post
import requests
r = requests.post('https://accounts.douban.com/login',data={'form_email': 'abc@example.com', 'form_password': '123456'})
print(r.status_code)
print(r.text)

# requests 默認使用 application/x-www-form-urlencoded 對POST數據編碼
# 若是要傳遞json數據,可直接傳入json參數
params = {'key':'value'}
r = requests.post(url, json=params)  # 替換url和params數據

# requests 還可進行更復雜的編碼格式(如:二進制),文件上傳
import requests
upload_files = {'file':open('test.xls', 'rb')}
r = requests.post(url, file=upload_files)

# 同理,把 requests.get()、requests.post() 替換爲 put、delete,也可進行該方式請求。

# requests 獲取響應信息
print(r.headers)  # 獲取http頭信息
print(r.status_code)  # 獲取狀態碼
print(r.text)  # 獲取頁面內容

# cookie
# requests 對 cookie 作了特殊處理,是咱們沒必要解析cookie就能夠輕鬆獲取cookie
print(r.cookies)
# 若是要在請求中傳入cookie,和post同樣,使用dict傳入cookie參數
cookie_params = {'token':12345, 'status':'abc', 'session':'DWEHDWLLKSNDQ2SD2H4'}

# 指定超時時間
r = requests.get('url', timeout=2.5) # 2.5秒超時

chardet模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# chardet 用於監測編碼
import chardet
print(chardet.detect(b'hello world!'))
# 結果:{'encoding': 'ascii', 'confidence': 1.0, 'language': ''}
# confidence 表示機率,1.0 表明100%


# 檢測GBK編碼的中文:
data = '離離原上草,一歲一枯榮'.encode('gbk')
print(chardet.detect(data))
# 結果:{'encoding': 'GB2312', 'confidence': 0.7407407407407407, 'language': 'Chinese'}

# 監測utf-8編碼的中文:
data = '離離原上草,一歲一枯榮'.encode('utf-8')
print(chardet.detect(data))
# 結果:{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}

# 檢測日文
data = '最新の主要ニュース'.encode('euc-jp')
print(chardet.detect(data))
# 結果:{'encoding': 'EUC-JP', 'confidence': 0.99, 'language': 'Japanese'}

psutil模塊

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# psutil:process and system utilities, 進程和系統實用工具。
# 自動化運維使用廣泛。

import psutil
print(psutil.cpu_count())  # 獲取CPU邏輯數量
# 結果:4
print(psutil.cpu_count(logical=False))  # CPU物理核心
# 結果:2
# 由於個人電腦是雙核四線程的。

# 統計cpu的用戶/系統/空閒時間
print(psutil.cpu_times())


# 實現相似 top 命令的cpu使用率,每秒刷新一次,累計10次:
'''for x in range(10):
    print(psutil.cpu_percent(interval=1, percpu=True))
'''
print('------------------------------')

# 獲取內存信息
print(psutil.virtual_memory())  # 獲取物理內存信息
# svmem(total=8467226624, available=4421910528, percent=47.8, used=4045316096, free=4421910528)
# 總內存8G,可用4G多,已用佔比47.8%,已使用4G少一點,空餘4G多=前面的可用數額
print(psutil.swap_memory())  # 獲取交換分區信息
# sswap(total=13087117312, used=5167869952, free=7919247360, percent=39.5, sin=0, sout=0)

print('------------------------------')

# 獲取磁盤信息
print(psutil.disk_partitions())  # 獲取磁盤分區信息
print(psutil.disk_usage('/'))  # 磁盤使用狀況
print(psutil.disk_io_counters())  # 磁盤IO,輸入輸出吞吐量

print('------------------------------')

# 獲取網絡信息
print(psutil.net_io_counters())  # 獲取網絡讀寫 字節/包 的個數

print('------------------------------')

# 獲取網絡接口
print(psutil.net_if_addrs())

print('------------------------------')

# 獲取接口狀態
print(psutil.net_if_stats())

print('------------------------------')

# 獲取當前網絡鏈接信息
print(psutil.net_connections())

print('------------------------------')

# 獲取進程信息
'''
>>> psutil.pids() # 全部進程ID
[3865, 3864, 3863, 3856, 3855, 3853, 3776, ..., 45, 44, 1, 0]
>>> p = psutil.Process(3776) # 獲取指定進程ID=3776,其實就是當前Python交互環境
>>> p.name() # 進程名稱
'python3.6'
>>> p.exe() # 進程exe路徑
'/Users/michael/anaconda3/bin/python3.6'
>>> p.cwd() # 進程工做目錄
'/Users/michael'
>>> p.cmdline() # 進程啓動的命令行
['python3']
>>> p.ppid() # 父進程ID
3765
>>> p.parent() # 父進程
<psutil.Process(pid=3765, name='bash') at 4503144040>
>>> p.children() # 子進程列表
[]
>>> p.status() # 進程狀態
'running'
>>> p.username() # 進程用戶名
'michael'
>>> p.create_time() # 進程建立時間
1511052731.120333
>>> p.terminal() # 進程終端
'/dev/ttys002'
>>> p.cpu_times() # 進程使用的CPU時間
pcputimes(user=0.081150144, system=0.053269812, children_user=0.0, children_system=0.0)
>>> p.memory_info() # 進程使用的內存
pmem(rss=8310784, vms=2481725440, pfaults=3207, pageins=18)
>>> p.open_files() # 進程打開的文件
[]
>>> p.connections() # 進程相關網絡鏈接
[]
>>> p.num_threads() # 進程的線程數量
1
>>> p.threads() # 全部線程信息
[pthread(id=1, user_time=0.090318, system_time=0.062736)]
>>> p.environ() # 進程環境變量
{'SHELL': '/bin/bash', 'PATH': '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:...', 'PWD': '/Users/michael', 'LANG': 'zh_CN.UTF-8', ...}
>>> p.terminate() # 結束進程
Terminated: 15 <-- 本身把本身結束了
'''

print('------------------------------')

# 模擬ps命令效果
print(psutil.test())

TCP編程

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# TCP 是可靠的,面向鏈接的協議。

# Socket 是網絡編程的一個抽象概念,意爲「孔、插座」,用於兩個客戶端之間的網絡鏈接,
# 打開一個socket須要指定目標機器的IP和端口。


### 客戶端
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # AF_INET指定使用ipv4,若是是ipv6使用AF_INET6
s.connect(('www.sina.com.cn', 80))  # socket連接 參數是一個 tuple,包含地址、端口號

# 向新浪服務器發送請求
s.send(b'GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')

# 接收服務器返回數據
buffer = []
while True:
    d = s.recv(1024)  # recv(max)方法,一次最多接收指定的字節數
    if d:
        buffer.append(d)
    else:
        break
data = b''.join(buffer)
s.close()  # close()方法關閉Socket,網絡通訊結束。

# 輸出http頭信息
header, html = data.split(b'\r\n\r\n', 1)
print(header.decode('utf-8'))

# 把接收的內容數據寫入文件
with open('sina.html', 'wb') as f:
    f.write(html)


### 服務器
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 綁定監聽端口
s.bind(('127.0.0.1', 9999))

# 調用listen()開始監聽,並設置最大等待鏈接數量,不是鏈接的客戶端數量
s.listen(5)
print('Waiting for connection...')

# 服務器經過永久循環來接受來自客戶端的鏈接
while True:
    # 接受一個新鏈接:
    sock, addr = s.accept()
    # 建立新線程來處理TCP鏈接:
    t = threading.Thread(target=tcplink, args=(sock, addr))
    t.start()

# 每次鏈接都要建立新的線程或進程
def tcplink(sock, addr):
    print('Accept new connection from %s:%s...' % addr)
    sock.send(b'Welcome!')
    while True:
        data = sock.recv(1024)
        time.sleep(1)
        if not data or data.decode('utf-8') == 'exit':
            break
        sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
    sock.close()
    print('Connection from %s:%s closed.' % addr)


# 客戶端與上面服務器通訊
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 創建鏈接:
s.connect(('127.0.0.1', 9999))
# 接收歡迎消息:
print(s.recv(1024).decode('utf-8'))
for data in [b'Michael', b'Tracy', b'Sarah']:
    # 發送數據:
    s.send(data)
    print(s.recv(1024).decode('utf-8'))
s.send(b'exit')
s.close()

UDP編程

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# UDP 是面向無鏈接的協議。

### 服務端
import socket
s = socket.socket(socket.AF_INET, sock.SOCK_DGRAM)  # SOCK_DGRAM 指定Socket類型爲UDP
# 綁定端口
s.bind(('127.0.0.1'. 9999))

# UDP與TCP相比,不須要調用listen(),直接接收客戶端數據
print('Bind UDP on 9999..')
while True:
    # 接收數據
    data, addr = s.recvfrom(1024)  # recvfrom()返回數據和客戶端地址、端口
    print('Received from %s: %s.' % addr)
    s.sendto(b'Hello, %s!' % data, addr)
    # 服務器收到後經過 sendto() 把數據經過UDP發送給客戶端

### 客戶端
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in [b'Michael', b'Tracy', b'Sarah']:
    # 發送數據
    s.sendto(data, ('127.0.0.1', 9999))
    # 接收數據
    print(s.recv(1024).decode('utf-8'))
s.close()

SMTP發送郵件

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Python的 smtplib 和 email 兩個模塊對郵件支持。
# email 負責構造郵件,smtplib 負責發送郵件

from email.mime.text import MIMEText
msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')

# 輸入郵箱地址和口令
from_addr = input('From:')
password = input('Password:')
# 輸入收件人地址
to_addr = input('To:')
# 輸入SMTP服務器地址
smtp_server = input('SMTP server:')

import smtplib
server = smtplib.SMTP(smtp_server, 25)
server.set_debuglevel(1)  # 打印出和SMTP服務器交互的全部信息
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()

# 完整郵件:
from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
import smtplib

def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

from_addr = input('From:')
password = input('Password:')
to_addr = input('To:')
smtp_server = input('SMTP server:')

msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')
msg['From'] = _format_addr('Python愛好者 <%s>' % from_addr)
msg['To'] = _format_addr('管理員 <%s>' % to_addr)
msg['Subject'] = Header('來自SMTP的問候。。。', 'utf-8').encode()

server = smtplib.SMTP(smtp_server, 25)
server.set_debuglevel(1)
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()

POP3收取郵件

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Python內置的poplib模塊,用於實現郵件接收。

# 收取郵件分爲兩步:
# 1.用 poplib 把郵件原始文本下載到本地;
# 2.用 email 解析原始文本,還原郵件對象。

from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr
import poplib

# 解析郵件
# 打印出 message 對象的層次結構
# indent用於縮進顯示
def print_info(msg, indent=0):
    if indent == 0:
        for header in ['From', 'To', 'Subject']:
            value = msg.get(header, '')
            if value:
                if header=='Subject':
                    value = decode_str(value)
                else:
                    hdr, addr = parseaddr(value)
                    name = decode_str(hdr)
                    value = u'%s<%s>' % (name, addr)
            print('%s%s: %s' % (' ' * indent, header, value))
    if(msg.is_multipart()):
        parts = msg.get_payload()
        for n, part in enumerate(parts):
            print('%spart %s' % (' ' * indent, n))
            print('%s----------------' % (' ' * indent))
            print_info(part, indent + 1)
    else:
        content_type = msg.get_content_type()
        if content_type=='text/plain' or content_type=='text/html':
            content = msg.get_payload(decode=True)
            charset = guess_charset(msg)
            if charset:
                content = content.decode(charset)
            print('%sText: %s' % (' ' * indent, content + '...'))
        else:
            print('%sAttachment: %s' % (' ' * indent, content_type))
# 郵件中的名字都是編碼後的str,要正常顯示,必須解碼decode
def decode_str(s):
    value, charset = decode_header(s)[0]
    if charset:
        value = value.decode(charset)
    return value
# 郵件內容也要檢測編碼
def guess_charset(msg):
    charset = msg.get_charset()
    if charset is None:
        content_type = msg.get('Content-Type', '').lower()
        pos = content_type.find('charset=')
        if pos >= 0:
            charset = content_type[pos + 8:].strip()
    return charset

# 輸入郵件地址、口令和POP3服務器地址
email = input('Email:')
password = input('Password:')
pop3_server = input('POP3 server:')

#鏈接到POP3服務器
server = poplib.POP3(pop3_server)
# 打開調試信息
server.set_debuglevel(1)
# 打印POP3服務器的歡迎文字
print(server.getwelcome().decode('utf-8'))

# 身份認證
server.user(email)
server.pass_(password)

# stat()返回郵件數量和佔用空間
print('Messages: %s. Size: %s' % server.stat())
# list()返回全部郵件編號
resp, mails, octets = server.list()
# 查看返回列表
print(mails)

# 獲取最新一封郵件
index = len(mails)
resp, lines, octets = server.retr(index)

# lines存儲了郵件的原始文本的每一行,能夠得到整個郵件原始文本
msg_content = b'\r\n'.join(lines).decode('utf-8')
# 稍後解析出郵件
msg = Parser().parsestr(msg_content)
print_info(msg)
# 關閉鏈接
server.quit()

使用SQLite

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# SQLite是一種嵌入式數據庫,數據庫就是一個文件

# 導入sqlite數據庫
import sqlite3
# 鏈接test.db數據庫,若是不存在會自動建立
conn = sqlite3.connect('test.db')
# 建立Cursor,操做數據庫經過Cursor執行SQL語句
cursor = conn.cursor()
# 執行建立表的命令
cursor.execute('create table user (id varchar(20) primary key, name varchar(20))')
# 插入一條記錄
cursor.execute('insert into user (id, name) values (\'1\', \'Michael\')')
# 經過rowcount得到插入的行數
print(cursor.rowcount)
# 關閉Cursor
cursor.close()
# 提交事務
conn.commit()
# 關閉鏈接
conn.close()

# 查詢
conn = sqlite3.connect('test.db')
cursor = conn.cursor()
# 執行查詢語句
cursor.execute('select * from user where id?', ('1',))
# 得到查詢結果集
values = cursor.fetchall()
print(values)
cursor.close()
conn.close()

使用MySQL

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 安裝mysql驅動
# pip3 install mysql-connector-python --allow-external mysql-connector-python
# pip3 install mysql-connector

import mysql.connector
# 鏈接數據庫
conn = mysql.connector.connect(use='root', password='root', database='test')
cursor = conn.cursor()
# 建立user表
cursor.execute('create table user (id varchar(20) primary key, name varchar(20))')
# 插入一行記錄,注意mysql的佔位符是 %s
cursor.execute('insert into user (id, name) values (%s, %s)', ['1', 'Michael'])
print(cursor.rowcount)
# 提交事務
conn.commit()
cursor.close()
# 查詢
cursor = conn.cursor()
cursor.execute('select * from user where id = %s', ('1',))
values = cursor.fetchall()
print(values)
# 關閉cursor和connection
cursor.close()
conn.close()

使用SQLAIchemy

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# SQLAlchemy 是python 操做數據庫的一個庫。
# pip3 install sqlalchemy

from sqlalchemy import Column, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# 建立對象的基類
Base = declarative_base()
# 定義user對象
class User(Base):
    # 表的名字
    __tablename__ = 'user'

    # 表的結構
    id = Column(String(20), primary_key=True)
    name = Column(String(20))

# 初始化數據庫鏈接
engine = create_engine('mysql+mysqlconnector://root:password@localhost:3306/test')
# 建立DBSession類型
DBSession = sessionmaker(bind=engine)

# ORM(Object Relational Mapping,對象關係映射)框架的做用就是把數據庫表的一行記錄
# 與一個對象互相作自動轉換。

WSGI接口

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# WSGI:Web Server Gateway Interface, web服務網關接口(接口規範)
# 1.瀏覽器發送一個HTTP請求;
# 2.服務器收到請求,生成一個HTML文檔;
# 3.服務器把HTML文檔做爲HTTP響應的Body發送給瀏覽器;
# 4.瀏覽器收到HTTP響應,從HTTP Body取出HTML文檔並顯示。


# hello.py
def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [b'<h1>Hello, web!</h1>']

# server.py
from wsgiref.simple_server import make_server
from hello import application  # 導入 hello.py 定義的application()

httpd = make_server('', 8000, application)
print('Serving HTTP on port 8000...')
httpd.serve_forever()

# hello.py 與 server.py 在同一目錄下,運行 server.py,
# 瀏覽器 輸入 http://localhost:8000,就能顯示處 hello.py 的內容。
相關文章
相關標籤/搜索