1. 程式人生 > 實用技巧 >python基礎學習必知

python基礎學習必知

1.深淺拷貝

在正式開始說深淺拷貝之前,我們先來看一個例子吧

import copy 
a = [1, 2, 3, [4, 5]]
b = copy.copy(a)#淺拷貝
c = copy.deepcopy(a)#深拷貝
d = a

a.append(6)
a[3].append(6)
print("a =", a)
print("b = ", b)
print("c = ", c)
print("d = ", d)
輸出結果是什麼呢???
結果:
a = [1, 2, 3, [4, 5, 6], 6]
b = [1, 2, 3, [4, 5, 6]]
c = [1, 2, 3, [4, 5]]
d = [1, 2, 3, [4, 5, 6], 6]

Process finished with exit code 0

結合這個例子,我們再來看深淺拷貝,上面這個例子中,列表中套列表,最裡層列表中的元素叫做子物件,外邊的叫父物件,當你給最裡層的列表中新增元素時,深拷貝不會跟著新增該元素,因為深拷貝是完全拷貝的,最裡層的列表頁獨自佔有一段自己的記憶體的,而淺拷貝是不完全拷貝的,拷貝出來的最裡層列表跟a的最裡層列表是共享一段id儲存地址的,而用等號給一個變數重新賦值,前後兩個變數的id儲存地址是一樣的

2.metaclass(元類)

其實,python中的類也是一個物件,元類就是用來建立這些類的,python中的類是type類的物件,下面我們來看一個例子

class MyType(type):
    def __init__(self, what, bases=None, dict=None):
        super(MyType, self).__init__(what, bases, dict)
    def __call__(self, *args, **kwargs):
        obj = self.__new__(self, *args, **kwargs)
        self.__init__(obj)

class Foo(object, metaclass=MyType):
def init(self):
pass
def new

(cls, *args, **kwargs):
return object.new(cls, *args, **kwargs)

foo = Foo()

上面的例子中,Foo()建立一個物件時,其實不僅僅是執行了Foo類的__init__(self)方法,Foo本身就是一個物件,所以他建立的時候就預設執行了type的__init__(self)方法,Foo()就是物件再加(),這樣就會呼叫Mytype的__call__方法,然後__call__方法再去呼叫Foo的__new__方法和__init__方法,這樣便建立了一個Foo物件;metaclass=Mytype使得預設建立類的type改為使用Mytype來建立類

3.反射:通過字串的形式來操作物件中的成員

hasattr(),getattr(),setattr(),delattr()

4.單例模式

單例模式就是隻有一個例項的意思 實現單例模式的方法:

class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kwargs)
        return cls._instance

class MyClass(Singleton):
pass

5.python中的單下劃線和雙下劃線

__foo__:一種約定,python內部的名字,用來區別其他使用者自定義的命名,防止命名衝突;

_foo:一種約定,用來指定變數私有,程式設計師用來指定私有變數的一種方式。不能用from module import * 匯入,其他方面和公有一樣訪問;

__foo:表示他是私有成員,我們不能訪問,如果要訪問可通過_class(類名)_foo的方式進行訪問

6.列表生成式和生成器

把列表生成式的中括號改為小括號後就成了生成器

>>> L = [x*x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x*x for x in range(10))
>>> g
<generator object <genexpr> at 0x0000019D90F285C8>
>>> next(g)
0
>>> next(g)
1

7.*args和**kwargs

當你不確定傳入幾個引數時,就可以使用*args,他可以傳遞任意數量的引數:

def foo1(*args):
    for i in args:
        print(i)
foo1(1, 2, 3)

def foo(**kwargs):
for key, value in kwargs.items():
print("{}--{}".format(key, value))
foo(fruit1 = "apple", frult2 = "banaba")

8.__new__和__init__的區別

  • __new__是一個靜態方法,而__init__是一個例項方法

  • __new__方法會返回一個建立的例項物件,而__init__不返回東西

  • 只有在__new__返回一個cls的例項時後面的__init__才能被呼叫

  • 當建立一個新例項時呼叫__new__,初始化一個例項時用__init__

9.python中的·作用域

本地作用域(Local)→當前作用域被嵌入的本地作用域(Enclosing locals)→全域性/模組作用域(Global)→內建作用域(Built-in)

10.GIL執行緒全域性鎖

是python為了保證執行緒安全而採取的獨立執行緒執行的限制,說白了就是一個核只能在同一時間執行一個執行緒.對於io密集型任務,python的多執行緒起到作用,但對於cpu密集型任務,python的多執行緒幾乎佔不到任何優勢,還有可能因為爭奪資源而變慢。

11.執行緒/程序/協程

  • 執行緒就是呼叫cpu的最小執行單位
  • 程序是最小的資源管理單位,一個程序有一個主執行緒和多個子程序
  • 協程是一種比執行緒更加輕量級的存在,一個執行緒可以有多個協程,python裡最常見的yeild就是協程的思想

12.閉包

閉包(closure)是函數語言程式設計的重要的語法結構。閉包也是一種組織程式碼的結構,它同樣提高了程式碼的可重複使用性。

當一個內嵌函式引用其外部作作用域的變數,我們就會得到一個閉包. 總結一下,建立一個閉包必須滿足以下幾點:

  • 必須有一個內嵌函式
  • 內嵌函式必須引用外部函式中的變數
  • 外部函式的返回值必須是內嵌函式

例子:

def outer(x):
    y = 10
    def inner():
        return x*y
    return inner
result = outer(2)()#結果為20

13.lambda匿名函式

例子:

#一個求x的二次方的匿名函式
lambda x: x*x

14.python中的is

is是對比地址,==是對比值

15.socket

要想理解socket,就要先來理解TCP,UDP協議

TCP/IP(Transmission Control Protocol/Internet Protocol)即傳輸控制協議/網間協議,定義了主機如何連入因特網及資料如何再它們之間傳輸的標準,

從字面意思來看TCP/IP是TCP和IP協議的合稱,但實際上TCP/IP協議是指因特網整個TCP/IP協議族。不同於ISO模型的七個分層,TCP/IP協議參考模型把所有的TCP/IP系列協議歸類到四個抽象層中

應用層:TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 等等

傳輸層:TCP,UDP

網路層:IP,ICMP,OSPF,EIGRP,IGMP

資料鏈路層:SLIP,CSLIP,PPP,MTU

每一抽象層建立在低一層提供的服務上,並且為高一層提供服務,看起來大概是這樣子的

我們可以利用ip地址+協議+埠號唯一標示網路中的一個程序。能夠唯一標示網路中的程序後,它們就可以利用socket進行通訊了,我們經常把socket翻譯為套接字,socket是在應用層和傳輸層(TCP/IP協議族通訊)之間的一個抽象層,是一組介面,它把TCP/IP層複雜的操作抽象為幾個簡單的介面供應用層呼叫已實現程序在網路中通訊。

應用程式兩端通過“套接字”向網路發出請求或者應答網路請求。可以把socket理解為通訊的把手(hand)

socket起源於UNIX,在Unix一切皆檔案哲學的思想下,socket是一種"開啟—讀/寫—關閉"模式的實現,伺服器和客戶端各自維護一個"檔案",在建立連線開啟後,可以向自己檔案寫入內容供對方讀取或者讀取對方內容,通訊結束時關閉檔案。socket的英文原義是“插槽”或“插座”,就像我們家裡座機一樣,如果沒有網線的那個插口,電話是無法通訊的。Socket是實現TCP,UDP協議的介面,便於使用TCP,UDP。

例子:

#socket_server.py
import socket
sk = socket.socket()#建立一個socket
print(sk)
address = ('127.0.0.1', 8000)
sk.bind(address)#為socket繫結ip地址和埠
sk.listen(3)#最多允許三個客戶端連線
print("waiting...")
#等待客戶端的連線,沒有客戶端連線之前是阻塞狀態
cone, addr = sk.accept()#conne就像是服務端與客戶端的一條通道,有多個客戶端,就有多條這樣的通道
print(cone)
print(addr)
cone.send(bytes("hello, 靚仔", "utf8"))

#socket_client.py
import socket
sk = socket.socket()#建立一個socket
print(sk)
address = ('127.0.0.1', 8000)
sk.connect(address)#為sk繫結連線的服務端的地址和埠號
data = sk.recv(1024)#接受服務端傳送過來的資料
print(str(data, "utf8")

16.字串格式化:%和.format

.format在許多方面看起來更便利.對於%最煩人的是它無法同時傳遞一個變數和元組.你可能會想下面的程式碼不會有什麼問題:

"hi there %s" % name

但是,如果name恰好是(1,2,3),它將會丟擲一個TypeError異常.為了保證它總是正確的,你必須這樣做:

"hi there %s" % (name,)   # 提供一個單元素的陣列而不是一個引數

但是有點醜..format就沒有這些問題.你給的第二個問題也是這樣,.format好看多了

.format的使用方式:

s = "{0} is {1}".format("luyi", "handsome")
print(s)
#結果:luyi is handsome
#注意:這裡的{}裡面的0和1是可以省略的

17.裝飾器

作用:為已經存在的物件新增額外的功能

例如給一個程式加上執行時間的功能:

import time

def show_time(func):
def inner():
start_time = time.time()
func()
end_time = time.time()
print("spend {}s".format(end_time-start_time))
return inner

@show_time
def foo():
print("hello world")
time.sleep(2)

foo()
#輸出結果為:
hello world
spend 2.0009796619415283s

18.cookie和session

  • cookie是儲存在客戶端的,可以跟蹤會話,也可以儲存使用者的偏好設定或者儲存使用者名稱密碼等,安全性不高
  • session是儲存在服務端的,可以跟蹤會話,出現session技術的原因就是為了安全,session技術是要用到cookie技術的

瞭解更多:https://github.com/taizilongxu/interview_python