您能夠關注公衆號《Python數據結構》瞭解更多知識。
i = i+1 和 i += 1
因爲自己是不可變數據類型,執行後都會生產新的對象
x = 1
print(id(x)) # 1510566928
x += 1
print(id(x)) # 1510566960
---------------------------
x = 1
print(id(x)) # 1510566954
x = x + 1
print(id(x)) # # 1510566998
能夠看到 使用 += 並不會改變對象的內存地址
x = [1, 2]
print(id(x)) # 2701823038387
x = x + [3, 4]
print(id(x)) # 2701823038334
------------------
x = [1, 2]
print(id(x)) # 2701823038344
x += [3, 4]
print(id(x)) # 2701823038344
n = n + n 做用域問題內部爲[1, 2, 1, 2], 外部仍爲[1, 2]
def num(n):
n = n + n
x = [1, 2]
num(x)
print(x) # [1, 2]
--------------------
def num(n):
n += n
x = [1, 2]
num(x)
print(x) # [1, 2, 1, 2]
內建函數
zip
key = [key for key in dict(zip(('a','b','c','d','e'),(1,2,3,4,5))) ]
print(key)
--------------------------------------------------------
['a', 'b', 'c', 'd', 'e']
A0 = dict(zip(('a','b','c','d','e'),(1,2,3,4,5)))
A1 = range(10)
A2 = [i for i in A1 if i in A0]
A3 = [A0[s] for s in A0]
A4 = [i for i in A1 if i in A3]
A5 = {i:i*i for i in A1}
A6 = [[i,i*i] for i in A1]
-------------------------------------------------------------
A0 = {'a': 1, 'c': 3, 'b': 2, 'e': 5, 'd': 4}
A1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
A2 = []
A3 = [1, 3, 2, 5, 4]
A4 = [1, 2, 3, 4, 5]
A5 = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
A6 = [[0, 0], [1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81]]
閉包
做用——保存局部信息不被銷燬。
def num2(n):
i = 1
def num_in():
nonlocal i
i = i + n
print(i)
return num_in
i = 0
start = num2(3)
while i<5:
start()
i += 1
匿名函數(lambda)
與正常寫法相比,使用匿名函數至關簡潔
a = [1, 2, 3]
x = []
for each in a:
x.append(each+1)
print(x)
### 使用map(func, iterable)
print(list(map(lambda x: x+1, a)))
- reduce(func, seq) 積累每次計算的值
def num(x, y):
return x + y
print(reduce(num, [1, 2, 3, 4]))
--------------------------
print(reduce(lambda x, y: x*y, [1, 2, 3, 4]))
- filter(func, iterable) 過濾知足條件的值
print(list(filter(lambda x: x%2==0,range(10))))
進程和線程的區別
- 進程是資源(CPU、內存等)分配的基本單位,它是程序執行時的一個實例。
- 線程是程序執行時的最小單位,它是進程的一個執行流。
- 進程有本身的獨立地址空間,每啓動一個進程,系統就會爲它分配地址空間,創建數據表來維護代碼段、堆棧段和數據段,這種操做很是昂貴
- 線程是共享進程中的數據的,使用相同的地址空間,所以CPU切換一個線程的花費遠比進程要小不少,同時建立一個線程的開銷也比進程要小不少
- 進程實現
from multiprocessing import Pool
import time
import random
import os
def work(msg):
start = time.time()
print("work{}開始執行,id爲{}".format(msg, os.getpid()))
time.sleep(random.random()*2)
stop = time.time()
print("work{}耗時{}.".format(msg, stop-start))
p = Pool()
for i in range(10):
# 非堵塞運行
p.apply_async(work, args=(i,))
# 堵塞進行
# p.apply(work, args=(i,))
print("開始")
p.close()
p.join()
print("結束")
import threading
import os
from time import sleep
def sorry(i):
print('say sorry {}'.format(i))
sleep(1)
if __name__ == '__main__':
for i in range(1,10):
t = threading.Thread(target=sorry, args=(i,))
t.start()
協程
協程以前咱們明白Python的進程和線程,這裏咱們來講一下協程
- 子程序切換不是線程切換,而是由程序自身控制
- 沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優點就越明顯
- 不須要多線程的鎖機制,由於只有一個線程,也不存在同時寫變量衝突,在協程中控制共享資源不加鎖
- 協程實現
def custumer():
r = ''
while True:
n = yield r # 接受send的值 返出yield的值
if not n:
return
print('custer {}'.format(n))
r = 'done'
def produce(c):
c.send(None) # 啓動
n = 0
while n < 5:
n += 1
print('custer {}'.format(n))
r = c.send(n)
print('custer return {}'.format(r))
c.close()
c = custumer()
produce(c)
GIL
Python並不支持真正意義上的多線程。Python中提供了多線程包,可是若是你想經過多線程提升代碼的速度,使用多線程包並非個好主意。Python中有一個被稱爲Global Interpreter Lock(GIL)的東西,它會確保任什麼時候候你的多個線程中,只有一個被執行。線程的執行速度很是之快,會讓你誤覺得線程是並行執行的,可是實際上都是輪流執行。通過GIL這一道關卡處理,會增長執行的開銷。這意味着,若是你想提升代碼的運行速度,使用threading包並非一個很好的方法。
不過仍是有不少理由促使咱們使用threading包的。若是你想同時執行一些任務,並且不考慮效率問題,那麼使用這個包是徹底沒問題的,並且也很方便。可是大部分狀況下,並非這麼一回事,你會但願把多線程的部分外包給操做系統完成(經過開啓多個進程),或者是某些調用你的Python代碼的外部程序(例如Spark或Hadoop),又或者是你的Python代碼調用的其餘代碼(例如,你能夠在Python中調用C函數,用於處理開銷較大的多線程工做)。
copy
Python拷貝分爲深拷貝和淺拷貝
l1 = [1, 2, [3, 4]]
l2 = copy.copy(l1)
l1.append(5)
l1[2].append(5) # 子對象 改變
print(l1)
print(l2)
--------------
[1, 2, [3, 4, 5], 5]
[1, 2, [3, 4, 5]]
l1 = [1, 2, [3, 4]]
l2 = copy.deepcopy(l1)
l1.append(5)
l1[2].append(5)
print(l1)
print(l2)
--------------
[1, 2, [3, 4, 5], 5]
[1, 2, [3, 4]]
垃圾回收機制
import sys
# 請在Python解釋器下運行 爲 2 建立一次 調用一次
str1 = 'hello world'
print(sys.getrefcount(str1))
Python默認定義了三代對象集合,索引數越大,對象存活時間越長
Python中使用了某些啓發式算法(heuristics)來加速垃圾回收。例如,越晚建立的對象更有可能被回收。對象被建立以後,垃圾回收器會分配它們所屬的代(generation)。每一個對象都會被分配一個代,而被分配更年輕代的對象是優先被處理的。
垃圾回收器會定時尋找這個循環,並將其回收。舉個例子,假設有兩個對象o1和o2,並且符合o1.x == o2和o2.x == o1這兩個條件。若是o1和o2沒有其餘代碼引用,那麼它們就不該該繼續存在。但它們的引用計數都是1。
is和==
# is 比較的是內存地址 == 比較內容和數據類型
a = [1, 2, 3]
b = a
print(a is b)
print(a == b)
c = copy.deepcopy(a)
print(a is c)
print(a == c)
-------------
True
True
False
True
文件操做
read,readline和readlines
read 讀取整個文件
readline 讀取下一行,使用生成器方法
readlines 讀取整個文件到一個迭代器以供咱們遍歷
遞歸輸出文件
import os
def print_directory_contents(sPath):
for sChild in os.listdir(sPath):
sChildPath = os.path.join(sPath, sChild)
if os.path.isdir(sChildPath):
print_directory_contents(sChildPath)
else:
print(sChildPath)
print_directory_contents('F:\\GZ\\mxgController')
Fibonacci數列
def fab(n):
a, b = 0, 1
while n:
yield b
a, b = b, a+b
n -= 1
內存管理
a = 1
b = 1
print(a is b) # True
# True
a = "good"
b = "good"
print(a is b)
# False
a = "very good morning"
b = "very good morning"
print(a is b)
# False
a = []
b = []
print(a is b)
函數調用
函數賦值會開闢新空間,即[] 和 [3, 2, 1]內存地址不同,前者引用,後者覆蓋
def f(x, l=[]):
for i in range(x):
l.append(i*i)
print(l)
f(2) # [0, 1]
f(3,[3,2,1]) # [3, 2, 1, 0, 1, 4] # 本身單獨開闢
f(3) # [0, 1, 0, 1, 4] # 和f(2)共用
三目
if/else
# 若果 a>b 成立 就輸出 a-b 不然 a+b
h = a-b if a>b else a+b
and/or
### and 全部值都爲真,返回最後一個真;如有一個假,返回第一個假
print(2 and 1 and 3) # 3
print(1 and 3 and 0 and 4) # 0
print(1 and 0 and 3/0) # 0
### or 全部值都爲假,返回最後一個假;如有一個真,返回第一個真
print(0 or 1 or 1/0)
print(0 or '')
### 若是 a<b 返回True 不然返回a+b
print((a-b) and (a<b) or (a+b))
設計模式
單例---類方法方式
class Single():
def __init__(self, name):
self.name = name
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Single, "_instance"):
Single._instance = Single(*args, **kwargs)
return Single._instance
s1 = Single.instance('Gage')
s2 = Single.instance()
print(s1)
print(s2)
單例---new方式
class Single(object):
__isstance = None
__first_init = False
def __new__(cls, *args, **kwargs):
if not cls.__isstance:
cls.__isstance = object.__new__(cls)
return cls.__isstance
def __init__(self, name):
if not self.__first_init:
self.name = name
Singleton.__first_init = True
a = Single('a')
b = Single('b')
print(id(a))
print(id(b))
工廠模式
# 首先定義一個抽象基類
class CarStore(object):
# 定義生產汽車的方法
def createcar(self, name):
pass
# 根據類型去生產車
def order(self, name):
self.car = self.createcar(name)
self.car.move()
# 定義4s店 實現抽象類
class AoDiCarStore(CarStore):
def createcar(self, name):
self.factory = CarFactory()
return self.factory.createcar(name)
# 建立一個車
class AoDi():
def move(self):
print('移動')
# 定義一個工廠
class CarFactory():
def createcar(self, name):
self.name = name
if self.name == 'AoDi':
self.car = AoDi()
return self.car
aodi = AoDiCarStore()
aodi.order('AoDi')
數據結構
鏈表成對調換
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
# @param a ListNode
# @return a ListNode
def swapPairs(self, head):
if head != None and head.next != None:
next = head.next
head.next = self.swapPairs(next.next)
next.next = head
return next
return head
單鏈表反轉
class Node(object):
def __init__(self, data=None, next=None):
self.data = data
self.next = next
link = Node(1, Node(2, Node(3, Node(4, Node(5, Node(6, Node(7, Node(8, Node(9)))))))))
def rev(link):
pre = link
cur = link.next
pre.next = None
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
return pre
root = rev(link)
while root:
print root.data
root = root.next
快速排序
def quicksort(list):
if len(list)<2:
return list
else:
midpivot = list[0]
lessbeforemidpivot = [i for i in list[1:] if i<=midpivot]
biggerafterpivot = [i for i in list[1:] if i > midpivot]
finallylist = quicksort(lessbeforemidpivot)+[midpivot]+quicksort(biggerafterpivot)
return finallylist
print quicksort([2,4,6,7,1,2,5])
二分搜索
#coding:utf-8
def binary_search(list,item):
low = 0
high = len(list)-1
while low<=high:
mid = (low+high)/2
guess = list[mid]
if guess>item:
high = mid-1
elif guess<item:
low = mid+1
else:
return mid
return None
mylist = [1,3,5,7,9]
print binary_search(mylist,3)
