《Python核心編程》筆記

1 python是大小寫敏感的python

 

2 遍歷一個字典的鍵值:linux

for a in dict_obj.keys():
    print a


3 列表解析功能可讓代碼很簡潔,好比:
squared = [x ** 2 for i in range(0, 3)]
還能夠加上篩選條件:
squared = [x ** 2 for i in range(0, 3) if not x % 2]算法

 

4 python的一些命名風格:
__xxx__:系統定義的名字
__xxx:類中的私有變量名sql

 

5 在python程序中,咱們常常看到
if __name__ == '__main__'這樣的語句,這條語句通常寫爲頂級執行代碼,__name__是一個系統變量,當程序是被其它模塊導入時,該值爲模塊名字,當直接執行該文件時該值爲'__main__'express

 

6 del語句可以直接釋放資源編程

 

7 python的垃圾收集器其實是一個引用計數器和一個循環垃圾收集器,循環垃圾收集器是指會嘗試清理未引用的循環windows

 

8 使用局部變量替換模塊變量,能夠加快查找速度,由於省去了名字查詢,舉例:
ls = os.linesep
os.linesep返回的是當前系統的行終止符,好比linux系統的是'\n',windows系統的是'\r\n',Mac系統的是'\r'
若是每次都使用os.linesep則解釋器須要先確認os是一個模塊,而後從該模塊中找linesep變量,取一個本地變量名,查找速度會快不少,因此若是頻繁使用時可使用本地變量來替換模塊變量數組

 

9 Python提供了is和is not運算符來測試兩個變量是否指向同一個對象
a is b 等價於 id(a) == id(b)服務器

 

10 [::1]這是一種擴展切片操做,其第三個參數你能夠當作是range函數的那個步長參數,好比
str = 'abcdefg'
則str[::2]就等於aceg
str[::-1]就等於gfedcba網絡

 

11 在python中單引號和雙引號括起來的字符串是沒有區別的,不像其它腳本語言,在雙引號還有些轉義的東西,由於python對字符串的處理是當作一個標量,建立了後是不改變的,修改則是建立了一個新的字符串標量對象

 

12 for-else語句是指若是for循環中所有循環完了沒有break則會執行else語句
因此這裏有個巨坑:

for j in range(i+step, num_len, step):
    pass

覺得當j不知足num_len時退出,覺得j>=num_len,結果是若是j+step>=num_len就退出,j並無加上step
解決方法能夠:

for j in range(i+step, num_len, step):
    pass
else:
    j += step

 

13 格式化字符串有兩種,一種是元組做爲參數類型的,相似於C模式的格式化輸出,另一種是字典做爲參數的,分別示例以下:
'yy:%s %s' %('oo', 'ii')
'yy%(abc)s' %{'oo':77, 'abc':99}
字符串模板:它至關於定義了一個模板,傳參套用便可,substitute還有個類似的成員函數:safe_substitute,區別是後者若是遇到key不存在時不是拋錯,而是將模板字符串原封不動輸出
from string import Template
s = Template('abc ${haha} abc')
print s.substitute(haha='99')

 

14 原始字符串操做符:r/R
用法是在字符串引號前加上小寫r或大寫R:好比r'\n'
也就是說它消除了轉義符等,表達了真實要表達的字符
print '\n'會輸出換行的空行
print r'\n'則是輸出\n
r'\n'至關於字符串'\\n'

 

15 python的三引號能夠用來包含多行字符的字符串,字符串中能夠包含換行符、製表符等

 

16 列表可使用大部分的對象和序列類型的操做符,此外,列表也有屬於本身的方法,好比列表解析,在邏輯上描述要建立的列表的內容,舉例:
>>> [i * 2 for i in [8, -2, 5]]
[16, -4, 10]

 

17 字符串排序使用的是字典序,而不是字母序,即比較ASCII碼值,好比:
>>> s = ['aaa', 'TTT']
>>> print sorted(s)
['TTT', 'aaa']
由於'T'的ASCII碼值比'a'的小

 

18 python中也是有數組模塊的,array模塊,不過通常可用list替代

 

19 檢查一個字典中包含某個鍵能夠用has_key方法或者用in和not in來檢查,has_key方法在後面可能會被棄用

if uuu.has_key('ddd'):
    xxx
if 'ddd' in uuu:
    xxx


20 字典的鍵必須是可哈希的,可使用hash函數來判斷鍵是不是可哈希的,若是是則返回哈希後的值,不然拋出異常

 

21 字典的keys()、values()和items()方法都是返回列表,iterkeys()、itervalues()和itemvalues()返回的是一個迭代器,因此當字典量大,要遍歷時iter的這些方法優點就是節省內存。

for i in kk.keys():
    print i
for i in kk.iterkeys():
    print i

結果是同樣的

print kk.keys()
print kk.iterkeys()

這二者則不一樣了,可本身打出來看下

 

22 python中有一個叫集合的數據結構,集合的元素必須是可哈希的,可以使用set工廠方法來建立,建立不變的集合使用frozenset工廠方法

>>>s = set('ghj')
>>>s
set(['g', 'h', 'j'])

集合的特別是處就在於它跟數學中的集合概念很類似,同時提供了一些操做符很方便的操做集合,好比大於小於號用來判斷子集關係,-用於補集,&用於交集,|用於並集,+號不是集合類型的運算符

 

23 相似C語言中的三元操做符:samller = x if x < y else y

 

24 python的zip函數,以可迭代對象做爲參數,將對象中對應的元素打包成一個個元組,而後返回由這些元組組成的列表。例:

>>>a = [1, 2, 3]
>>>b = [4, 5, 6, 7]
>>>zipped = zip(a, b)
[(1, 4), (2, 5), (3, 6)]

利用*號操做符可將元組加壓爲列表

>>>zip(*zipped)
[(1, 2, 3), (4, 5, 6)]

 

25 迭代器從根本上來講是一個next()方法的對象,條目所有獲取完成後會引起一個StopInteration異常來告訴外部調用者迭代完成了。
它的做用:
(1)帶來訪問性能上的提高
(2)可建立更簡潔可讀的代碼
建立迭代器的方法:
iter(obj)可返回一個對象的迭代器,調用了該對象的__iter__方法和next方法
iter(func, sentinel);若是是傳遞了兩個參數給iter函數,則它會重複的調用func,直到迭代器的下個值等於sentinel。
文件也是可迭代的python數據類型,文件對象生成的迭代器會自動調用readline方法,因此有:
for eachLine in myFile:

 

26 列表解析
解析語法:
[expr for iter_var in iterable]
eg:[x ** 2 for x in range(6)]
擴展版本的語法:
[expr for iter_var in iterable if cond_expr]
eg:[x for x in seq if x % 2]
列表解析支持多重嵌套for 循環以及多個 if 子句
eg:[(x+1,y+1) for x in range(3) for y in range(5)]

 

27 生成器表達式
生成器是特定的函數,容許你返回一個值,而後「暫停」代碼的執行,稍後恢復。
爲啥須要生成器表達式:列表解析的一個不足就是必要生成全部的數據, 用以建立整個列表. 這可能對有大量數據的迭
代器有負面效應. 生成器表達式經過結合列表解析和生成器解決了這個問題,是一個內存使用更友好的結構。
生成器表達式:(expr for iter_var in iterable if cond_expr)
舉例:sum(len(word) for line in data for word in line.split())

 

28 能夠從sys.argv對象中獲取程序參數,相似於C語言中的argv參數,sys.argv[0]永遠是程序的名稱。

 

29 可以使用pickle模塊將對象進行序列化,包括用戶本身定義的類,cPickle是pickle的一個更快的C語言編譯版本。shelve則不只提供了序列化功能還提供了對象的永久性存儲功能。

 

30 異常處理

try 
    xxx
except Exception1, e:
    pass
except Exception2, e:
    pass

若是兩個異常類型使用同一種方法處理,則能夠把異常類型一同放在元組裏

try:
    xxx
except (Exception1, Exception2), e:
    pass

BaseException是全部異常類的基類,KeyboardInterrupt和systemExit被從Exception中移出來,和Exception處於同級,其它的內建異常類都是以Exception爲基類

try-except-else-finally

 

31 能夠對一個實例進行__class__函數調用,能夠顯示出該實例屬於哪一個類

32 with
with context_expr [as var]:
with_suite
with語句僅能工做於支持上下文管理協議的對象,只有內建了"上下文管理"的對象能夠和 with 一塊兒工做。
下面列出一些支持該協議對象的第一批成員簡短列表:
file
decimal.Context
thread.LockType
threading.Lock
threading.RLock
threading.Condition
threading.Semaphore
threading.BoundedSemaphore
以打開文件舉例:

with open('/etc/passwd', 'r') as f:
    for eachLine in f:
        # ...do stuff with eachLine or f...

這裏是with語句幫你打開文件和結束時自動關閉文件,實現原理:
上下文表達式(context_expr),上下文管理器
當with語句執行時便開始執行上下文符號(with和as之間的內容)來得到一個上下文管理器,上下文管理器用來提供一個上下文對象。這是經過調用__context__()方法來實現的,該方法返回一個上下文對象。獲取上下文對象後會執行__enter__()方法來作with包含的語句塊執行前的準備工做,若是有as聲明變量,則該變量會被賦值爲__enter__()方法返回的值。
不管with語句塊正常執行結束仍是異常結束,結束時都會先調用__exit__()方法,好比能夠在該方法中關閉上下文對象,該方法會有三個參數,若是正常結束,則返回3個None,若是異常結束,等同於調用sys.exc_info()函數返回的三個值:類型(異常類)、值(異常實例)和回溯(traceback)。__exit__方法返回值是true or false決定了會往下執行with後的代碼仍是拋出異常給用戶。

33 exc_info函數
是另外一種獲取異常信息的途徑,返回一個元組,包含3個對象,分別是:
(1)exc_type:異常類
(2)exc_value:異常類的實例
(3)exc_traceback:追蹤(traceback)對象
eg:

try:
        float('jjf')
except:
        import sys
        exc_tuple = sys.exc_info()
        for each_item in exc_tuple:
                print each_item

 

34 裝飾器
首先介紹一個裝飾器實用的地方,好比定義一個類的靜態方法,若是沒有使用裝飾器,須要在該方法的第一行加上staticFoo = staticmethod(staticFoo),顯得臃腫,若是使用裝飾器則只須要在方法的上面加上@staticmethod便可。

@deco2
@deco1
def func(arg1, arg2, ...): 
    pass

等價於:

def func(arg1, arg2, ...): 
    pass
func = deco2(deco1(func))

先調用deco2,而後在deco2裏調用deco1,最後deco1裏調用func

上面說的是無參數的裝飾器,下面說下有參數的裝飾器:

@decomaker(deco_args)
def foo(): 
    pass

須要本身返回以函數foo做爲參數的裝飾器。換句話說,decomaker()用 deco_args 作了些事並返回
函數對象(裝飾器返回的函數,不是foo),而該函數對象正是以 foo 做爲其參數的裝飾器。簡單的說來:
foo = decomaker(deco_args)(foo)

因此有參數和無參數的裝飾器結合起來就是:

@deco1(deco_arg)
@deco2
def func(): 
    pass

等價於:
func = deco1(deco_arg)(deco2(func))

舉例(不帶參數的):

#!/usr/bin/env python

from time import ctime, sleep

def tsfunc(func):
        def wrappedFunc():
                print '[%s] %s() called' % (ctime(), func.__name__)
                return func()
        return wrappedFunc

@tsfunc
def foo():
        print 'ok'

foo()
sleep(4)

for i in range(2):
        sleep(1)
        foo()

輸出:
[Sun Mar 10 01:29:36 2019] foo() called
ok
[Sun Mar 10 01:29:41 2019] foo() called
ok
[Sun Mar 10 01:29:42 2019] foo() called
ok

疑問地方:
(1)

def tsfunc(func):
        #def wrappedFunc():
        #       print '[%s] %s() called' % (ctime(), func.__name__)
        #       return func()
        #return wrappedFunc
        print '[%s] %s() called' % (ctime(), func.__name__)
        return func

爲何須要閉包函數,爲何這樣子進行調用只打了一次時間戳?

舉例(帶參數的):

def outer(outer_args):
    def middle(func):
        def wrapper(*args,**kwargs):
            print("before func")
            print("use args: "+outer_args)
            wrapper_result=func(*args,**kwargs)
            print("after func")
            return wrapper_result
        return wrapper
    return middle

@outer("hello")
def foo(a,b):
    return a+b

 

35 函數的參數
能夠傳遞元組或者字典,*tuple_param,**dict_param
這裏能夠區分下非關鍵字參數和關鍵字參數,像b='1'這樣的就叫作關鍵字參數,因此字典便是關鍵字參數;非關鍵字參數須要放到關鍵字參數以前
test(*tuple, **dict_param)
python是容許傳遞默認參數的,好比你常常會看到一個函數的定義的參數末尾是這樣的,uuu='abc',但要注意全部的必要參數要放在默認參數的後面,爲何要這樣規定呢,簡單來講就是若是容許這樣隨意混雜,有些狀況會有歧義的。
好比不容許這樣:def test(a, b='1', c)
應該這樣:def test(a, c, b='1')
對於函數的參數定義一樣很靈活,能夠經過元組和字典定義可變參數的函數:def function_name([formal_args,][*vargst,] **vargsd)
其實就是對於非關鍵字參數formal_args中沒有的則會放到vargst元組裏,對於關鍵字參數就放到vargsd中

36 匿名函數與 lambda
lambda [arg1[, arg2, ... argN]]: expression
eg:

>>> hh = lambda x, y=3: x+y
>>> hh(5)
8
>>> hh(5, 9)
14
>>> type(hh)
<type 'function'>

 

37 函數式編程的內建函數,apply,filter,map和reduce:
apply(func[, nkw][, kw]) :用可選的參數來調用func函數,該函數其實已被拋棄,由於如今的函數已經支持可選參數調用了。
eg:
apply(test, *tuple_param)

filter(func, seq):調用一個返回布爾值的函數func來迭代sql中的每一個元素,若是是返回True的則插入到要返回的列表中
eg:
filter(test, [1, 4, 8])
好比test是對偶數進行刪選的函數,則返回[4, 8]

map(func, seq1[,seq2...]):該函數跟filter函數有點像,不過func函數不必定是要布爾函數,它能夠對序列裏的每一個元素進行處理並返回值,該值再插入到列表中,最後返回列表。

reduce(func, seq[, init]):func是一個二元函數,做用於seq序列的元素,每次攜帶一對(先前的結果以及下一個序列元素),這樣一直計算到最後一個。
eg:
reduce(lambda x, y:x+y, [1, 2, 3])
算法實現是先拿出第一個,而後陸續從第2個開始。
>>> reduce(lambda x, y:x-5, [1, 3, 5])
-9
>>> reduce(lambda x, y:x-5, [1])
1
下面這個例子就能夠看出來,先拿出1獲得1,而後拿出3,獲得-4,而後拿出5獲得-9

38 使用global關鍵字可引用全局變量

ii = 3
def test():
    global ii
    ii = 7
print ii

 

39 生成器
生成器是一個帶 yield 語句的函數。一個函數或者子程序只返回一次,但一個生成器能暫停執行並返回一箇中間的結果----那就是 yield 語句的功能, 返回一個值給調用者並暫停執行。當生成器的 next()方法被調用的時候,它會準確地從離開地方繼續。
簡單的生成器例子:

#!/usr/bin/env python
def simpleGen():
        yield 1
        yield '2'
gs = simpleGen()
print gs.next()
print gs.next()
#print gs.next() # StopIteration
for item in simpleGen():
        print item

除了next方法,增強的生成器還有send和close方法,send方法用於向生成器傳遞值,好比下面例子的val,close方法用來關閉生成器,好比下面例子的最後一行就會報stopInteration異常

#!/usr/bin/env python
def counter(start_at=0):
        count = start_at
        while True:
                val = (yield count)
                if val is not None:
                        count = val
                else:
                        count += 1
kk = counter(10)
print kk.next()
print kk.next()
print kk.send(1)
print kk.next()
kk.close()
print kk.next()

輸出:
10
11
1
2
Traceback (most recent call last):
  File "test_python.py", line 16, in <module>
    print kk.next()
StopIteration

40 模塊和命名空間相關
一個文件被看做是一個獨立模塊, 一個模塊也能夠被看做是一個文件。 模塊的文件名就是模塊的名字加上擴展名 .py。
sys.path能夠看到當前的搜索路徑,import的時候就是去這些路徑下找文件模塊的
若是想添加新得搜索路徑,能夠調用sys.path.append('xxx'),好比sys.path.append('/root/oo/')
sys.modules則能夠看到當前導入的模塊名稱和對應的物理位置,是字典對象,key爲模塊名,value爲物理位置,好比'kk': <module 'kk' from '/root/oo/kk.py'>

名稱空間是名稱(標識符)到對象的映射
在程序執行時會有3個名稱空間:這三個名稱空間分別是局部名稱空間, 全局名稱空間和內建名稱空間
Python 解釋器首先加載內建名稱空間。 它由 __builtins__ 模塊中的名字構成。 隨後加載執行模塊的全局名稱空間, 它會在模塊開始執行後變爲活動名稱空間,在函數調用時就會出現有局部名稱空間。
經過 globals() 和 locals() 內建函數判斷出某一名字屬於哪一個名稱空間。
globals() 和 locals() 內建函數分別返回調用者全局和局部名稱空間的字典。
舉例:

#!/usr/bin/env python

o = 8
def yy():
        i = 9
        print locals()
        print globals()
        print locals().keys()
yy()

輸出:
{'i': 9}
{'__builtins__': <module '__builtin__' (built-in)>, '__file__': 'test_python.py', 'o': 8, '__package__': None, 'yy': <function yy at 0x7fedd7c6e578>, '__name__': '__main__', '__doc__': None}
['i']
因此能夠判斷一個變量在當前名稱空間是否存在,能夠這樣判斷if 'xxx' in locals().keys()

當你獲得一個函數實例或一個類實例時,至關於你建立了一個名稱空間,你能夠將想要的東西放入這個名稱空間裏,好比:

#!/usr/bin/env python
def foo():
        pass
foo.__doc__ = 'Oops, forgot to add doc str above!'
foo.version = 0.2
print foo.version

class abc():
        pass
a = abc()
a.uu = 9
print a.uu

 

模塊導入的方式有好幾種:
import xxx
from xx import xxx
from xx import xxx as x

加載模塊會讓該模塊的頂層代碼被執行。

41.包
包是一個有層次的文件目錄結構, 它定義了一個由模塊和子包組成的Python應用程序執行環境
每一個包的目錄都會有__init__.py文件,能夠是空文件,有時在from-import導入子包時會用到它
導入有絕對導入和相對導入兩種方式,絕對導入是默認的比較經常使用的方式,import只支持絕對導入,from-import支持相對導入
相對導入:語法的第一部分是一個句點, 指示一個相對的導入操做。 以後的其餘附加句點表明當前from起始查找位置後的一個級別,能夠相對導入看起來沒有那麼清晰

只要在你的 Python 模塊頭部加入一個額外的編碼指示說明就可讓導入者使用指定的編碼解析你的模塊, 編碼對應的 Unicode 字符串
好比utf-8編碼:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-

有時咱們會遇到包的循環導入問題,好比A文件中import B,B中又也是import A,解決方法能夠是若是某方只是想要某個函數用一些另一個模塊的,能夠在那個函數裏內部導入下,由於此時運行時就不會有互相導入致使循環問題,或者引入第三方,把要調用的集成到另一個公共模塊

42.類
初始化一個類實例時會調用類的__init__方法,你能夠把它理解爲類的構造方法
python的OOP面相對象編程中的經常使用術語:
(1)抽象/實現:抽象就是對現實問題的一種抽象建模,以程序的方式來描述現實;實現則是根據建好的模賦予真實數據並交互起來
(2)封裝/接口:封裝便是把具體實現隱藏起來,只須要提供相對應的調用接口便可,告訴用戶只要這樣調用接口就能實現相對應的功能
(3)合成:一個類裏面可能引用了其它類,幾個類聯合起來解決實際的問題
(4)派生/繼承:派生就是繼承了一個父類後子類本身定義的方法實現,父類沒有的,繼承便是繼承了父類的一些屬性和方法
(5)泛化/特化:泛化是指子類、父類及其祖先都有的一個特定屬性功能,好比各類人本質都是一我的,有追根溯源的味道,特化是指子類有其本身特定的某些功能,即雖然都是人,可是我有其它人不會的技能
(6)多態:多態的概念指出了對象如何經過他們共同的屬性和動做來操做及訪問,而不需考慮他們具體的類。最簡單的實用例子就是咱們能夠根據不一樣的配置選擇不一樣的driver類實現,而後調用對應類的方法,由於這些類都有這些方法,但實際調用哪一個類,則要看driver是實例化了哪一個子類。
(7)反射:這個性質展現了某對象是如何在運行期取得自身信息的。若是傳一個對象給你,你能夠查出它有什麼能力,dir()和 type()內建函數便是用到了這種能力。

類的數據屬性:數據屬性僅僅是所定義的類的變量,咱們成爲靜態變量,相似於C++中的在一個變量定義前加了個static

#!/usr/bin/env python

class A(object):
        jk = 1
        def update(self, value):
                self.jk = value  # 並無影響到類的屬性jk,只是建立了個實例屬性
print A.jk
a = A()
a.update(3)
print A.jk
print a.jk

輸出:
1
1
3

在類屬性可變的狀況下,好比類屬性是dict結構的,類實例能夠改變掉類對象的屬性值:

class A(object):
        jk = 1
        kk = {'a': 1}
a = A()
a.jk = 2
a.kk['a'] = 2
print A.jk
print A.kk

輸出:
1
{'a': 2}

要知道類的屬性能夠有幾種方法:
(1)經過調用內建函數dir()
(2)訪問類的__dict__屬性
(3)內建的vars()函數接受類對象做爲參數,返回類的__dict__屬性的內容

特殊類屬性
A.__name__ 類A的名字(字符串)
A.__doc__ 類A的文檔字符串
A.__bases__ 類A的全部父類構成的元組
A.__dict__ 類A的屬性
A.__module__ 類A定義所在的模塊(1.5 版本新增)
A.__class__ 實例A對應的類(僅新式類中)

顯示調用父類方法:

class A(object):
        jk = 1
        def __init__(self):
                print 'A class'

class B(A):
        def __init__(self):
                print('B class')
                super(B, self).__init__()
                # 或者是:A.__init__(self)

kb = B()

與__init__()相比,__new__()方法更像一個真正的構造器。__new__()必須返回一個合法的實例,這樣解釋器在調用__init__()時,就能夠把這個實例做爲 self 傳給它
__del__() "解構器"方法
除非你知道你正在幹什麼,不然不要去實現__del__()
若是你定義了__del__,而且實例是某個循環的一部分,垃圾回收器將不會終止這個循環——你須要自已顯式調用 del

類裏面有staticmethod()和 classmethod()內建函數,能夠將方法變爲靜態方法和類方法,如今通常用裝飾器來實現靜態方法和類方法的轉換,靜態方法咱們比較熟悉,比較不熟悉的是類方法,類方法區別去靜態方法的是它須要傳遞一個類對象參數,它的比較大的用處在於讓咱們嘗試一種另類的構造函數。可看下面例子:

class Date(object):
    @classmethod
    def from_string(cls, date_as_string):
        day, month, year = map(date_as_string.split('-'))
        date1 = cls(day, month, year)
        return date1
date2 = Date.from_string('11-09-2012')

cls表示類對象,而不是類實例
至關於咱們調用了類方法from_string來構造一個類實例並返回
其實重寫覆蓋__new__方法也同樣實現這個功能

class RoundFloat(float):
    def __new__(cls, val):
        return float.__new__(cls, round(val, 2))
        #或者return super(RoundFloat, cls).__new__(cls, round(val, 2))

注意python的類的方法是不支持重載特性的,但可覆蓋方法,也就是說不能像C++那樣,參數多少均可以被重載爲兩個不一樣的方法

isinstance函數能夠用來判斷一個對象是否屬於某個給定的類的實例:

i = 8
if isinstance(i, int):
        print 'yes'
else:
        print 'no'


類屬性的一些經常使用方法:
hasattr():返回值示Boolean型的,查詢是否有該屬性;
getattr():獲取某個屬性的值,若是沒有會引起AttributeError異常,除非有給默認參數;
setattr():設置屬性
delattr():刪除屬性

重寫一些方法能夠定製類的特殊方法,這些特殊方法都是__開頭的:
__cmp__(self, obj) 對象比較;內建 cmp()
還有不少大於小於加減乘除等

43 網絡編程相關
套接字有兩種,分別是基於文件型的和基於網絡型的,分別是AF_UNIX(AF_LOCAL)和AF_INET
python還支持一種套接字AF_NETLINK,AF_NETLINK套接字家族讓用戶代碼與內核代碼之間的IPC可使用標準BSD套接字接口。

不管是哪一種類型的套接字,都分爲兩種類型套接字,面向鏈接和無鏈接套接字。
面向鏈接套接字通信前要先創建一條鏈接,這種通信方式提供了順序的、可靠的、不會重複的數據傳輸,並且也不會被加上數據邊界。實現這種鏈接的主要協議就是傳輸控制協議(TCP),套接字類型對應爲SOCK_STREAM。這些套接字使用Internet協議(IP協議)來查找主機,因此聯合起來是TCP/IP。
無鏈接套接字與面向鏈接相反,發送數據前不用先創建鏈接,但這也意味着數據不必定保證送到,且發送數據順序和數據包重複沒法獲得保證,但這樣的好處是性能好,在某些場景下有用。
實現這種鏈接的主要協議是數據報協議(UDP),套接字類型爲SOCK_DGRAM,UDP/IP。

使用socket.socket()函數來建立套接字
socket(socket_family, socket_type, protocol=0)
socket_family 能夠是 AF_UNIX 或 AF_INET。socket_type 能夠是 SOCK_STREAM 或 SOCK_DGRAM。protocol 通常不填,默認值爲 0。

套接字對象的經常使用函數:
服務器端套接字函數
s.bind() 綁定地址(主機,端口號對)到套接字
s.listen() 開始 TCP 監聽
s.accept() 被動接受 TCP 客戶的鏈接,(阻塞式)等待鏈接的到來
客戶端套接字函數
s.connect() 主動初始化 TCP 服務器鏈接
s.connect_ex() connect()函數的擴展版本,出錯時返回出錯碼,而不是拋異常
公共用途的套接字函數
s.recv() 接收 TCP 數據
s.send() 發送 TCP 數據
s.sendall() 完整發送 TCP 數據
s.recvfrom() 接收 UDP 數據
s.sendto() 發送 UDP 數據
s.getpeername() 鏈接到當前套接字的遠端的地址
s.getsockname() 當前套接字的地址
s.getsockopt() 返回指定套接字的參數
s.setsockopt() 設置指定套接字的參數
s.close() 關閉套接字
Blocking-Oriented Socket Methods
s.setblocking() 設置套接字的阻塞與非阻塞模式
s.settimeout() 設置阻塞套接字操做的超時時間
s.gettimeout() 獲得阻塞套接字操做的超時時間
面向文件的套接字的函數
s.fileno() 套接字的文件描述符
s.makefile() 建立一個與該套接字關連的文件

一個簡單的socket服務器例子:

#!/usr/bin/env python

from socket import *
from time import ctime

HOST = ''
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)

while True:
        print 'waiting for connection...'
        tcpCliSock, addr = tcpSerSock.accept()
        print '...connected from:', addr
        try:
                while True:
                        data = tcpCliSock.recv(BUFSIZ)
                        if not data:
                                break
                        tcpCliSock.send('[%s] %s' % (ctime(), data))
        except Exception, e:
                print e
tcpCliSock.close()
tcpSerSock.close()

 

一個簡單的客戶端例子:

#!/usr/bin/env python

from socket import *

HOST = 'localhost'
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)

tcpCliSock = socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)
while True:
        data = raw_input('> ')
        if not data:
                break
        tcpCliSock.send(data)
        data = tcpCliSock.recv(BUFSIZ)
        if not data:
                break
        print data

tcpCliSock.close()

 

SocketServer模塊:

#!/usr/bin/env python

from SocketServer import (TCPServer as TCP, StreamRequestHandler as SRH)
from time import ctime

HOST = ''
PORT = 21567
ADDR = (HOST, PORT)

class MyRequestHandler(SRH):
        def handle(self):
                print '...connected from:', self.client_address
                self.wfile.write('[%s] %s' % (ctime(), self.rfile.readline()))
                # self.request.send('[%s] %s' % (ctime(), self.request.recv(1024)))
tcpServ = TCP(ADDR, MyRequestHandler)
print 'waiting for connection...'
tcpServ.serve_forever()
相關文章
相關標籤/搜索