進階篇知識點

 
 
 
前言
 
1. virtualenv的使用
virtualenv做用是並行管理多個python程序,解決因多個python版本不兼容的問題
使用方法以下
1)安裝pip:  apt install pip
2)安裝virtualenv:pip install virtualenv
3)創建工做目錄:virtualenv test1
4)在工做目錄下安裝文件:cd test1, source bin/activate, pip install tornado
 
2. 推薦參考書
1)程序員的數學
2)大話數據結構,大話設計模式(後期再看)
3)C語言
4)python標準庫
5) python基礎教程
6)官方文檔 docs.python.org
 
 
 
一,函數
 
 
進階篇 函數 第一節
1.函數基本概念
 
注意點:
a: 輸出函數時要加小括號
b: 函數中的return語句很是重要
c: 函數體爲空的話,這裏要寫一個pass
 
 
def func_name():
    pass# 函數體爲空的話,這裏要寫一個pass,若是不寫,函數是不成立的,
 
輸出函數時要加小括號
def func1():
    return "hello,world"
print func1()
 
錯誤例子1
print "a>b" if a>b else pass 執行的時候會報錯,其實這個三元表達式是執行2個命令,print 和後面的條件語句,若是a>b 會執行print "a>b", 不然,會執行print pass,可是這個pass是一個命令體中的語句,結果就會報錯,最好寫成以下
if a>b:
    print "a>b"
else:
    pass
 
錯誤例子2
def func2():
    print 123
test = func2()
print type(test)
輸出結果是nonetype,因此函數中的return語句很是重要。
 
 
2.參數 <=> 抽象
例如
def add(num1,num2):
    return num1+num2
print add(1,3)
print add(3,8)
 
3.參數分爲可選參數,必選參數
 
1)計算不定數量的整數相加
def add(*num): #這裏*會把num定義爲一個tuple類型,2個*會定義爲字典類型
    d = 0
    for i in num:
        d += i
    return d
print add(1,2,3,4,5)
print add(1,2,3)
print add(2,4,6,8,1,2,3,4,12312,12314,123,123,123)
 
2)可選和必選語法上的區別
1.可選參數 是有默認值的
2.必須參數 是沒有默認值的
默認值和沒有默認值的區別在於  「=」
例如
def add(num1,num2=4)
    return num1+num2
print add(1)
若是參數中的"=4"沒有的話,調用add函數的時候就須要寫2個參數,若是定義函數的時候,2個參數都有等號,那麼調用的時候直接用print add()就行
 
3) 函數的健壯性--考慮到大部分結果,並獲得應急反饋處理。
1)各類狀況下會返回什麼東西(異常處理,條件判斷)
 
2)自定義你想要的返回結果
def add(num1 ,num2):
    if isinstance(num1,int) and isinstance(num2, int):
        return num1+num2
    else:
        return '參數裏有不是數字的類型'
print add('a',(1,2,3))
print add(1,2)
 
測試方法,斷言
assert add(1,2) == 3
assert add(2,4) == 3
在這裏,若是斷言正確,不會輸出任何信息,若是斷言錯誤,就會返回AssertionError
 
 
二,函數第2節
 
1.元組,list,字典都能迭代,int和string不能迭代
 
 
 
2. 怎麼去學習使用函數
    (1)別管那麼多複雜的,先直接把功能實現了。
    (2)抽象成函數:命名規範,僞代碼,參數默認值。
    (3)將函數變得更健壯,讓它能夠跑不少地方
                    1.假設你寫的函數是要交給你的基友用 -》 功能完整
                    2.假設你寫的函數是要交給你的學弟用 -》 異常處理完善
     (4) 測試
                    1.assert
                    2.對函數的返回進行一個值和類型的測試。
                    3.單元測試
def func1(a,b,c,d,e):
    「」「
    @a:
    」「」
    pass
 
3. 命名
下劃線命名線  get_doc
駝峯命名法 getDocFromUrl
爲何要用默認值:
1.更省事
2.更可配置
 
 
4.練習題
 
 
 
三. 函數第3節
 
 
1. assert
 
在開發一個程序時候,與其讓它運行時崩潰,不如在它出現錯誤條件時就崩潰(返回錯誤)。這時候斷言assert就顯得很是有用。
assert不能放在程序流程中,它是用於程序調試的
 
例1. 下面使用assert的方式是不對的
for item in args:
    assert isinstance(item,int),'parameter is integer only'
return max(args),min(args)
 
例2
這段代碼用來檢測數據類型的斷言,由於 a_str 是 str 類型,因此認爲它是 int 類型確定會引起錯誤。
>>> a_str = 'this is a string' 
>>> type(a_str) 
<type 'str'> 
>>> assert type(a_str)== str 
>>> assert type(a_str)== int 
 
Traceback (most recent call last):
File "<pyshell#41>", line 1, in <module> 
assert type(a_str)== int 
AssertionError
 
 
2.自省與函數---func.__code__
例如
def func1(arg1,arg2):
    return arg1 == arg2
print dir(func1.__code__)
print func1.__code__.co_varnames   #('arg1', 'arg2'),返回函數的參數
print func1.__code__.co_filename   #test1.py,返回腳本的文件名。
print help(func1.__code__)
都試一下會輸出什麼
 
3.做用域問題再議
 
例子1
arg = 1
def func1():
    arg = 3
func1()
print arg
 
返回結果是1,說明局部變量只會在函數內部生效。
 
例子2
arg =1
def func1():
    global arg
    arg = 3
 
def func2():
    global arg
    arg =4
 
func2()
func1()
 
print arg
 
結論:
1) func2()和func1()的順序不一樣,輸出結果也會不一樣
2) global關鍵字能夠把局部變量變爲全局變量
 
 
4.可變參數的魔法與禁忌
例子1
def func1(arg):
    arg[0] = 5  用於測試
    return arg
print func1([1,2,3])
 
結果爲[5,3,4],參數arg爲列表,是可變的參數。
 
 
例子2
def func1(arg):
    arg[0] = 5  用於測試
    return arg
 
tlist = [1,2,3]
print func1(tlist) 
print tlist #引入可變參數會很危險,這裏引入的tlist參數本身也被修改了
    
 
 
四. 函數第4節
 
step1:lambda之再議
    
    1.lambda是一個表達式,它沒有名稱,存儲的也不是代碼塊,而是表達式。
    2.它被用做執行很小的功能,不能在裏面使用條件語句。可是能夠執行三元表達式,好比例2
    3.也能夠執行列表推導式,好比例子3
 
例子1
d = lambda x:x+1
print d(2)
輸出爲3,等價於函數
def e(x)
    return x+1
 
例子2
>>> d = lambda x:x+1 if x>0 else "error"
>>> print d(3)
4
>>> print d(-1)
error
 
例子3
>>> g = lambda x:[(x,i) for i in xrange(0,10)]
>>> print g(3)
[(3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9)]
 
例子4
>>> t = [1,2,3,4,5]
>>> g = filter(lambda x:x>3,t) #自動把t的值代入x中
>>> print g
[4, 5]
 
 
step2:函數參數總結
 
1.位置匹配 func(name)
def func(arg1,arg2,arg3):
    return arg1,arg2,arg3
print func(1,2,3) #按位置傳參
 
2.關鍵字匹配 func(key=value)
def test(a='',b='None',c=''):
    return a,b,c
print test(a=2,c=3)
print test(c=9,a=1)
print test(a=3,b=4,c=5)
print test()
 
輸出結果以下
(2, 'None', 3)
(1, 'None', 9) #說明參數順序變化也不要緊
(3, 4, 5)
('', 'None', '')
 
 
3.收集匹配
若是是在參數中沒有定義的位置參數,就會設爲元組或者字典;
*kargs 元組  
**kw   字典
例子
def func2(a,*kargs,**kw):#比較有位置參數a和沒有的區別
    return kargs
print func2(2,3,4,5,[1,2,3],{1:2,3:4})
 
4.參數順序
參數位置規則:位置匹配參數 > 關鍵字匹配參數 > 元組參數 > 字典參數; 好比def func2(a,d,b=4,*kargs,**kw)
 
 
step3:接觸遞歸
    1.遞歸是調用自身
    2.理解下面的函數
"""
def func(i):
    if i<100:
        return i + func(i+1)
    return i
print func(3)
print func(10)
"""
 
 
 
五. 面向對象
 
 初識class
 
1. class的基本定義
class test(object):
    a=1  #a稱爲test的屬性
    def func_1(self): #在類中定義的函數被稱爲方法,方法的第一個參數必須是self。
        pass
 
t = test()
print t.a
print t.func_1()
 
 
2.  __init__方法-------構造函數,
做用:實例化以前能夠先引入一些必要的參數
 
例子1:定義一個空方法
def __init__(self):
    pass
 
 
例子2:
class Person:  #類名後面不加參數也行
    def __init__(self,name,age):
        self.name=''
        self.age=0
p=person('tom',20)
print p
這樣的輸出結果是
hong@hong-VirtualBox:~$ python test2.py
<__main__.person instance at 0x7f5f8104c560>
 
 
 
例子3:將對象的內容打印出來
class test(object):  #全部的class都是object的派生類
    def __init__(self,var1): #注意這裏的逗號
        self.var1 = var1  #把參數var1賦值給self.var1,這樣self.var1就能在類中進行全局調用
    
    def get(self,a=None): #把參數a去掉和a=None是等效的,這樣就不用引入參數了
        return self.var1  #全局調用self.var1,通常的函數是不能使用在其餘函數中的變量的
 
t = test("hello,my name is hong")
 
print t.get()
 
 
 
 
例子4:用於生成對象的字符串表示的方法__str__  
 
class test:  
    def __init__(self,var1): 
        self.var1 = var1  
    def get(self,a=None): 
        return self.var1 
    def __str__(self):
        return self.var1
t = test("hello, my name is hong")
 
print t.get()
print type(t.get())
print str(t)
print type(str(t))
 
輸出以下
hello, my name is hong
<type 'str'>
hello, my name is hong
<type 'str'>
 
 
注意:這裏get方法和__str__方法是等效的。
 
 
 
例子5:把上例改爲2個參數
 
class test:
    def __init__(self,var1,var2):
        self.var1 = var1
        self.var2 = var2
    def get(self):
        return self.var1,self.var2
    def __str__(self):
        return self.var1,self.var2
t = test("hello",33)
print t.get()
print str(t)
 
這樣寫會返回一個錯誤
hong@hong-VirtualBox:~$ python test2.py
('hello', 33)
Traceback (most recent call last):
  File "test2.py", line 13, in <module>
    print str(t)
TypeError: __str__ returned non-string (type tuple)
 
改爲以下代碼就對了,本身琢磨一下
class test:
    def __init__(self,var1,var2):
        self.var1 = var1
        self.var2 = var2
    def get(self):
        return self.var1,self.var2
    def __str__(self):
        return "(%s,%d)" % (self.var1,self.var2)
t = test("hello",33)
 
print t.get()
print type(t.get())
print str(t)
print type(str(t))
 
 
輸出結果以下 
hong@hong-VirtualBox:~$ python test2.py
('hello', 33)
<type 'tuple'>
(hello,33)
<type 'str'>
 
 
3. 析構函數,是用做銷燬的,這種方法不經常使用,由於class被銷燬時,python有內部機制會自動銷燬裏面的數據。
    def __del__(self):
        del self.arg1
    del self.arg2
t = test(1,4)
print t.a
print t.func_1()
 
 
4. class和函數的區別
 
例子1:一個最基本的對象
class test(object):#若是是空類,能夠繼承object類
    def get(self):  #類裏面定義函數,其中的參數self表明的是對象自己,能夠在class內部全局調用
    return "hello"
對比一下,定義一個基本函數  
def get():
    return "hello"
    
t = test() #t是test的一個實例
print t.get() #get稱爲test對象的專屬方法,不能被其餘函數調用,這個就是使用對象的內置方法
print get() #自定義的函數和對象的內置方法進行對比
 
 
例2. 在get()函數中增長一個參數a
class test(object):
    def get(self,a): #引入一個參數a,
        return a
 
def got(a): #自定義的函數也引入一個參數a
    return a
    
t = test()
new_var = 4   
 
print t.get(new_var)
print got(new_var)
 
輸出都是4
 
 
5. 私有變量
再person中,在變量名age開頭加上2個下劃線,代表age是私有變量,這樣age只能person類中訪問;不如下劃線打頭的變量是公有變量,任何代碼均可訪問他們。
 
在編寫大型程序時,一條實用的經驗規則是,首先將全部對象變量都設置爲私有的(即以2個下劃線打頭),再在有充分理由的狀況下將其改成公有的,能夠避免無心間修改對象內部變量致使的錯誤。
 
 
 
6. __repr__和__str__的區別
 
class Test(object):
def __init__(self, value='hello, world!'):
self.data = value #這裏說明並不是必定寫成self.value=value
 
>>> t = Test()
>>> t
<__main__.Test at 0x7fa91c307190>
>>> print t
<__main__.Test object at 0x7fa91c307190>
 
我測試的是t和print t,效果是同樣的。
 
# 看到了麼?上面打印類對象並非很友好,顯示的是對象的內存地址# 下面咱們重構下該類的__repr__以及__str__,看看它們倆有啥區別
 
1) 重構__repr__class TestRepr(Test):
def __repr__(self):
return 'TestRepr(%s)' % self.data
 
>>> tr = TestRepr()
>>> tr
TestRepr(hello, world!)
>>> print tr
TestRepr(hello, world!)
 
# 重構__repr__方法後,無論直接輸出對象仍是經過print打印的信息都按咱們__repr__方法中定義的格式進行顯示了
 
 
2) 重構__str__
calss TestStr(Test):
def __str__(self):
return '[Value: %s]' % self.data
 
>>> ts = TestStr()
>>> ts
<__main__.TestStr at 0x7fa91c314e50>
>>> print ts
[Value: hello, world!]
 
# 你會發現,直接輸出對象ts時並無按咱們__str__方法中定義的格式進行輸出,而用print輸出的信息卻改變了
 
總結:
__repr__和__str__這兩個方法都是用於顯示的,__str__是面向用戶的,而__repr__面向程序員。
  • 打印操做會首先嚐試__str__和str內置函數(print運行的內部等價形式),它一般應該返回一個友好的顯示。
  • __repr__用於全部其餘的環境中:用於交互模式下提示迴應以及repr函數,若是沒有使用__str__,會使用print和str。它一般應該返回一個編碼字符串,能夠用來從新建立對象,或者給開發者詳細的顯示。
當咱們想全部環境下都統一顯示的話,能夠重構__repr__方法;當咱們想在不一樣環境下支持不一樣的顯示,例如終端用戶顯示使用__str__,而程序員在開發期間則使用底層的__repr__來顯示,實際上__str__只是覆蓋了__repr__以獲得更友好的用戶顯示
 
 
 
7. 裝飾器
 
1. @property,這個東西能夠直接把函數當作屬性來用,例如
 
class test(object):
    @property
    def d(self):
        return 4
t=test()
print t.d    #使用了裝飾器,這裏能夠直接寫t.d,就能夠輸出值,而不是t.d()
 
2. @staticmethod裝飾器,能夠不把類test實例化,就能使用其中的方法,以下
class test(object):
    
    @staticmethod  #靜態方法,把命名空間放在了類test中
    def d():  #這裏不須要加self參數了,類的普通內置方法的時候纔會加self參數,這裏和在類外面定義的函數是同樣的
        return 4
print test.d()   #不用實例化,直接用class的名稱來執行。
 
 
 
8. 繼承
 
例子1
class Base(object):
    def __init__(self,name)
        self.name = name
class b(Base): #至關於在b中也有一個init函數
    def get_name(self):
        return self.name #若是寫name就是錯誤的
new_class = b("lilei") #把b實例化
print new_class.get_name()
 
 
六. 模塊
 
1.模塊的基本概念
模塊其實就是一個py文件,好比python內置模塊linecache,能夠用dir(linecache)查看模塊內置方法
 
2.導入模塊的方法
 
1)import  #導入所有方法
import linecache
>>> dir(linecache)
['__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'cache', 'checkcache', 'clearcache', 'getline', 'getlines', 'os', 'sys', 'updatecache']
>>> linecache.__file__ #linecache的腳本文件位置
'/usr/lib/python2.7/linecache.pyc'
 
2)from module import sth,只導入模塊中的某個方法
from linecache import getlines,這樣就能夠直接使用getlines方法
>>getlines
 
3)from module import all 導入所有方法
from linecache import *, 這種方式不會導入如下劃線 (_) 開頭的名稱。
 
注意點,
1)在linecache的腳本文件中,有__all__ =["getline","clearcache","checkcache"],這樣用from linecache import *命令導入時,只會導入getline,clearcache,checkcache這三個方法,這三個方法至關於公有方法,全部人均可以使用;其餘的方法至關於linecache的私有方法,好比updatecache,其餘人不能任意用,使用import linecache時,就不會有這個限制。
2)當用這個方法導入多個模塊的時候,不一樣模塊中的方法名字可能會衝突,因此要慎用!
 
3.自定義模塊
例如自定義個模塊 m1
#coding=utf-8
    
    def hash():
        return 4
那麼在其餘腳本中就可使用m1
#coding=utf-8
import m1
print m1.hash()
 
4.包的建立
包是一羣模塊的組合,因此先建一個文件夾,好比m2,做爲包
 
1)寫初始化文件 __init__.py #此時爲空
爲了讓 Python 將目錄當作包,目錄下必須包含 __init__.py 文件;這樣作是爲了防止一個具備常見名字(例如 string)的目錄無心中隱藏目錄搜索路徑中正確的模塊。最簡單的狀況下,__init__.py 能夠只是一個空的文件,但它也能夠爲包執行初始化代碼或設置__all__
 
2)定義一個url.py
#coding=utf-8
def get_page():
    return "some page content"
 
3)在其餘腳本中引用包
注意使用from package import item時,item 能夠是包的子模塊(或子包),也能夠是包中定義的一些其它的名稱,好比函數、 類或者變量。import語句首先測試 item 在包中是否有定義;若是沒有,它假定它是一個模塊,並嘗試加載它。若是未能找到,則引起ImportError異常。
相反,使用相似 import item.subitem.subsubitem 這樣的語法時,除了最後一項其它每項必須是一個包;最後一項能夠是一個模塊或一個包,但不能是在前一個項目中定義的類、函數或變量
 
#coding=utf-8
import m2
print dir(m2)#查看都什麼內置模塊
print m2.__file__ #會導入init文件
 
#print m2.url是不會調用url.py文件的,執行腳本的時候會出錯,那麼怎麼調用呢?
 
方法1   -----在python命令行,以及在linux腳本中都能執行
import m2.url
print  m2.url
 
#若是以爲m2.url比較麻煩,能夠用import m2.url as url更名,as至關於一個賦值操做,代碼以下
import m2.url as url
print url.get_page()
 
執行結果:
輸出getpage()定義的文本信息:some page content
 
方法2  ---這種方法能夠在python命令行中執行,可是在linux的腳本中不能執行。
from m2 import url
print url.get_page()
 
若是隻想使用url的get_page方法,怎麼辦呢?
 
方法1
from m2.url import get_page
print get_page() 
 
方法2
from m2 import *
print url.get_page()
那麼此時就須要在__init__.py中進行定義__all__ = ["url"],可是經驗證,不用在__inti__.py中定義也行。
 
 
5. 搜索模塊
若是在上面的包中再寫一個模塊,好比test2.py, 這個在包裏的模塊怎麼引入外部的模塊呢? 好比外部模塊爲m1.py
import sys
sys.path.append("/tmp/m") #添加模塊搜索路徑,m文件夾中包含着m1.py文件,其實就是定位m1的位置。
import m1
print m1.bash() #調用m1的bash()方法,視頻中多了代碼 __all__ = ['hash'],測試下不會影響嗎?經驗證,不會影響。
 
 
6. 經常使用模塊
 
1.咱們去哪裏找模塊
pypi.python.org  ---- 這個網站有大量的python的模塊庫
docs.python.org/2.7/  ---- python文檔,其中Library Reference包含全部的內置模塊的說明
 
2.咱們應該首先選擇哪些的模塊
首先考慮的是內置模塊, 相關文檔: http://docs.python.org/2.7/
 
3.經常使用模塊
 
3.1 urllib,urllib2 --- 網絡方面的模塊
import urllib #urllib多是一個包,包和模塊的用法是同樣的
dir(urllib)
help(urllib)裏面FILE有腳本文件的位置信息
使用方法,好比獲取網頁內容
d = urllib.urlopen(" http://www.baidu.com";)
print d.read()
 
3.2 datetime, time --- 時間模塊
import time
time.time() #獲得一個時間戳
import datetime
使用help(datetime),看MODULE DOCS中的網站能夠看到很是詳細的例子
 
3.3 os --- 系統模塊
import os
 
3.4 pickle  --- 對象序列化
經常使用數據交換格式 還有json, xml
import pickle
例子
class test(object):
    def a(self):
        return 4
    def b(self):
        return 5
d = test() #想把對象作持久化保存,好比放在文件裏,那麼須要把對象轉變爲字符串,就須要用到pickle
g=pickle.dumps(d) #對象轉爲字符串
type(g) #這裏就轉變成字符串了
g=pickle.loads(g) #反序列化,字符串轉爲對象
  
3.5 bsddb --- 一個輕量級的數據庫,支持key=>value的字典形式
 
3.6 logging --- 日誌
掌握 info, warning, error,重點看一下
 
 
七,異常
 
exception,中譯異常,保守派的聖盃,被濫用的良藥。
 
1. 出錯的東西們,他們出了什麼錯,他們出錯 = 被拋出了異常
 
2. 咱們不想讓他們出錯,繼續執行下面的程序,該怎麼辦?exception來了。
coding=utf-8
a = [1,2,3,4,5,6]
print a[5]
try:
    print a[6]
except: #捕獲異常
    print u"哈哈哈哈,這裏出錯啦" #出錯之後該作什麼,這裏輸出出錯信息
    
print '繼續往下跑哦'
 
3. 基本語法
try:
" 框住了你感受會拋出異常的代碼 "
    print "41223123"
    print a[6] #這裏拋出異常後就會跳到except語句,不會執行下面的print語句。
    print "hahaha"
except:
" try代碼塊裏的代碼若是拋出異常了,該執行什麼內容"
    print u"哈哈"
else:
"try代碼塊裏的代碼若是沒有拋出異常,就執行這裏"
    print "hoho"
finally:
"無論如何,finally裏的代碼,是總會執行的"
print "xixi"
 
4. 異常的應用
import urllib
#異常輸出以下
sth_url = " http://wasdasdasd";
try:
    d = urllib.urlopen(sth_url)
except:
    print "哈哈哈出錯了"
else:
    content = d.read()
finally:
    d.close()
 
5.咱們爲何不讓他出錯?
其實在開發階段,咱們是可讓任何東西出錯的,這樣能更快的排錯來完善代碼
 
6.何時用,怎麼用?
  咱們何時用異常? 答:不得不用的時候。
  異常怎麼用?
1. (咱們知道會有哪些問題,分析問題,獲得這些問題會拋出的指定異常)捕獲不一樣的異常狀況,最好不要只寫except,這樣捕獲全部異常比較籠統。
好比上面的例子,能夠經過寫多個except語句,完善以下
 
sth_url = " http://wasdasdasd";
try:
    d = urllib.urlopen(sth_url)
except IOError: #打不開網頁的異常,這裏的IOError是網頁不對時python輸出的異常信息。
    print "網頁出錯了"
except 語法錯誤異常:
    print "語法錯誤"
else:
    content = d.read()
finally:
    d.close()
 
2.異常的處理,要合理。要有日誌。
相關文章
相關標籤/搜索