python進階知識點
1.Python支援的函數語言程式設計
A.不是純函數語言程式設計:允許有變數(純函數語言程式設計:不需要變數,沒有副作用,測試簡單
B.支援高階函式:函式可以作為變數傳入
C.支援閉包:有了閉包就能返回函式
D.有限度地支援匿名函式
2.高階函式
能接收函式做引數的函式
變數可以指向函式
函式的引數可以接受變數
一個函式可以接收另一個函式作為引數
能接收函式作引數的函式就是高階函式
A.map()是python內建的高階函式,它接收一個函式f和一個list,並通過把函式f依次作用在list的每個元素上,得到一個新的list並返回
B.reduce()函式也是
C.filter()函式式python內建的另一個有用的高階函式,filter()函式接收一個函式f和一個list,這個函式f的作用是對每個元素進行判斷,返回True或者False,filter()根據判斷結果自動過濾掉不符合條件的元素,返回由符合條件元素組成的新的list
請利用filter()過濾出
import math
def is_sqr(x):
return math.sqrt(x)%1 == 0
print filter(is_sqr, range(1, 101))
D.sorted()函式可對list進行排序,同樣也是一個高階函式,它可以接收一個比較函式來實現自定義排序
對內容進行忽略大小寫排序
def campstr(s1,s2): return cmp(s1.lower(),s2.lower()) print sorted(['bob', 'about', 'Zoo', 'Credit'],campstr)
3.閉包
Python的函式不但可以返回int,str,list,dict等資料型別,還可以返回函式
Python中閉包,在函式內部定義的函式和外部定義的函式式一樣的,只是無法被外部訪問,如果有被定義在外函式內部的情況,並且內層函式引用了外層函式的引數,然後返回內層函式的情況,我們稱為閉包.
閉包的特點是返回的函式還引用了外層函式的區域性變數,所以要正確地使用閉包,就要確保引用的區域性變數在函式返回後不能變.
Python中的匿名函式,高階函式可以接收函式做引數,有些時候,我們不需要顯式地定義函式,直接傳入匿名函式更方便,在python中,對匿名函式提供了有限支援,關鍵字lambda表示寧明函式,冒號前面的x表示函式引數 eg: lambda x:x*x 匿名函式有一個限制,就是隻能有一個表示式,不寫return,返回值就是該表示式的結果
4.裝飾器
Python內建的@語法就是為了簡化裝飾器呼叫
@new_fn
def f1(x):
Return x*2
def f1(x):
return x*2
f1 = new_fn(f1)
作用:
可以極大地簡化程式碼,避免每個函式編寫重複性程式碼
列印日誌:@log
檢測效能:@performance
資料庫事務:@transaction
URL路由:@post(‘/register’)
請編寫一個@performance,它可以打印出函式呼叫的時間。
import time
def performance(f):
def fn(x):
time1 = time.time()
val = f(x)
print "run time = ",time.time() - time1
return val
return fn
@performance
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10)
5.偏函式
當一個函式有很多引數的時候,呼叫者就需要提供多個引數,如果減少引數個數,就可以簡化呼叫者的負擔
我們在sorted這個高階函式中傳入自定義排序函式就可以實現忽略大小寫排序。請用functools.partial把這個複雜呼叫變成一個簡單的函式:sorted_ignore_case(iterable)
def campstr(s1,s2):
return cmp(s1.lower(),s2.lower())
sorted_ignore_case = functools.partial(sorted,cmp= campstr)
print sorted_ignore_case(['bob', 'about', 'Zoo', 'Credit'])
6.模組和包的概念
當代碼越來越多的時候如果將所有的程式碼放入一個py檔案:無法維護
如果將程式碼分拆放入多個py檔案中,好處:
同一個名字的變數互不影響
引用其他的模組
#test.py ---> 自身模組名
Import math --->引用math模組
當模組多了以後,也容易重名,解決模組名衝突,只要將模組放入到不同的包中就可以解決
引用完整的模組名:
Import p1.util
使用:
P1.util.demo()
包就是資料夾,模組名就是.py
如何區分包和普通目錄:
包下面有個_init_.py這樣python才會當做包來處理
動態匯入模組
如果匯入的模組不存在,python直譯器會報ImportError錯誤
EG:
利用import ... as ...,還可以動態匯入不同名稱的模組。
Python 2.6/2.7提供了json 模組,但Python 2.5以及更早版本沒有json模組,不過可以安裝一個simplejson模組,這兩個模組提供的函式簽名和功能都一模一樣。
試寫出匯入json 模組的程式碼,能在Python 2.5/2.6/2.7都正常執行。
try:
import json
except ImportError:
import simplejson as json
print json.dumps({'python':2.7})
使用__future__
Python的新版本會引入新的功能,但是,實際上這些功能在上一個老版本中就已經存在了,要試用某一新的特性,就可以通過匯入__future__模組的某些功能來實現
例如:
from __future__ import division
print 10 / 3 #3.3333333333333335
print 10//3 #3
安裝第三方模組
a.easy_install
b.pip(推薦,已內建到Python2.7.9)
例如安裝web.py第三方模組
pip install web.py
7.Python面向物件程式設計
面向物件程式設計是一種程式設計正規化
把程式看做不同物件的相互呼叫
對現實世界建立物件模型
基本思想
類用於定義抽象型別
例項根據類的定義被創建出來
最重要的思想:資料封裝
由於Python是動態語言,對每一個例項,都可以直接給他們的屬性賦值
可以給一個例項繫結很多屬性,如果不希望被外部訪問到,可以用__雙下劃線開頭,該屬性就無法被外部訪問.但是如果一個屬性以 __xxx__的形式定義,則又可以被外部訪問了,以__xxx__定義的屬性在python的類中被稱為特殊屬性,有很多預定義的特殊屬性可以使用,通常不把普通屬性用__xxx__定義
8.類屬性
繫結在例項上的屬性不會影響其他例項,但是,類本身也是一個物件,如果在類上繫結一個屬性,則所有例項都可以訪問類的屬性,並且,所有例項訪問的類屬性都是同一個,也就是說,例項屬性每個例項各自擁有,互相獨立,而類屬性有且只有一份(類似於java的static)
定義類屬性可以直接在class中定義
class Demo(object):
data1 = 12
Print Demo.data1
因為類屬性是直接繫結在類上的,所以訪問類屬性不需要建立例項.
對一個例項呼叫類的屬性也是可以訪問的,所有例項都可以訪問到它所屬的類的屬性
由於Python是動態語言,類屬性也是可以動態新增和修改的...
當例項屬性和類屬性重名時,例項屬性優先順序高,它將遮蔽掉對類屬性的訪問。不要在例項上修改類屬性,它實際上並沒有修改類屬性,而是給例項綁定了一個例項屬性
9.例項方法
例項的方法就是在類中定義的函式,它的第一個引數永遠是 self,指向呼叫該方法的例項本身,其他引數和一個普通函式是完全一樣的:在例項方法內部,可以訪問所有例項屬性,這樣,如果外部需要訪問私有屬性,可以通過方法呼叫獲得,這種資料封裝的形式除了能保護內部資料一致性外,還可以簡化外部呼叫的難度。
在class中定義的例項方法其實也是屬性,實際上是一個函式物件,因為方法也是一個屬性,所以它也可以動態地新增到例項上,只是需要用type.MethodType()把一個函式變為一個方法
10.類方法
和屬性類似,方法也分例項方法和類方法.在class中定義的全部是例項方法,例項方法第一個引數self是例項本身.通過標記@classmethod 該方法將繫結到類上,而非類的例項上,該方法的第一個引數將傳入類本身,通常將引數名命名為cls,因為是在類上呼叫,而非例項上呼叫,因此類方法無法獲取任何例項變數,只能獲得類的引用
class Person(object):
count = 0
@classmethod
def how_many(cls):
return cls.count
11.類的繼承
子類和父類是is關係,總是從某各類繼承 如果沒有合適的就從object繼承,不能忘記呼叫super().__init__
如果已經定義了Person類,需要定義新的Student和Teacher類時,可以直接從Person類繼承:
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
定義Student類時,只需要把額外的屬性加上,例如score:
class Student(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
一定要用 super(Student, self).__init__(name, gender) 去初始化父類,否則,繼承自 Person 的 Student 將沒有 name 和 gender。
函式super(Student, self)將返回當前類繼承的父類,即 Person ,然後呼叫__init__()方法,注意self引數已在super()中傳入,在__init__()中將隱式傳遞,不需要寫出(也不能寫)。
12.判斷型別
函式isinstance()可以判斷一個變數的型別,既可以用在Python內建的資料型別如str,list,dict,也可以用在我們自定義的類,它們本質上都是資料型別
Isinstance(“ss”,str)
繼承鏈上,一個父類的例項不能是子類型別,因為子類比父類多了一些屬性和方法,一個例項可以看成它本身的型別,也可以看成它父類的型別。
13.多型
類具有繼承關係,並且子類型別可以向上轉型看做父類型別,因此在例項方法的繼承以及複寫而言和java類似,但是bug的是因為python是動態語言,因此python在呼叫例項方法的時候不檢查型別,只要方法存在,引數正確即可以呼叫.意思是:只要類中有這個方法,那麼類似於這樣的方法定義:
def demo(x):
x.demomethod()
只要x中有demomethod這個方法就可成功的呼叫demo方法.
14.多重繼承
除了從一個父類繼承外,python允許從多個父類繼承,稱為多繼承
class A(object):
def __init__(self):
pass
def hi(self):
print "A hi"
pass
class B(object):
def __init__(self):
pass
def hi(self):
print "B hi"
pass
class C(A,B):
def __init__(self):
pass
c = C()
c.hi()
15.獲取物件資訊
拿到一個變數,除了用isinstance()判斷是否是某種型別的例項外,可以用type()函式獲取變數的型別,返回一個Type物件,也可以用dir()函式獲取變數的所有屬性,getattr()獲取屬性值,setattr()設定屬性值
16.特殊方法
用於print的__str__
用於len的__len__
用於cmp的__cmp__
特殊方法的特點
a.定義在class中
b.不需要直接呼叫
c.某些函式或者操作符會呼叫對應的特殊方法
正確實現特殊方法
A.只需要編寫用到的特殊方法
B.有關聯性的特殊方法都必須實現
__getattr__
__setattr__
__delattr__
C.__str__和__repr__
如果要把一個類的例項變成str,需要實現特殊方法__str__()
__repr__()用於顯示給開發人員看
D.__cmp__
對int,str等內建資料型別排序時,python的sorted()按照預設比較函式cmp排序,但是,如果對一組例項排序的時候,就必須提供自己的特殊方法__cmp__,__cmp__用例項自身self和傳入的例項 s 進行比較,如果 self 應該排在前面,就返回 -1,如果 s 應該排在前面,就返回1,如果兩者相當,返回 0。
E.__len__
如果一個類表現的像list,要獲取有多少個元素,就得用len()函式,要讓len()函式工作正常,類就必須提供一個特殊方法__len__()
F.數學運算
Python提供的基本資料型別int,float可以做整數和浮點的四則運算以及乘方等運算,但是四則運算不侷限於int和float,還可以是有理數,矩陣等,要表示有理數,可以用Rational類來表示
G.型別轉換
對於資料的型別轉換 如下:
int(12.23) ---- > 12
float(12) -----> 12.0
如果要把一個物件轉換為int應該實現特殊的方法__int__()
然後呼叫 int(obj) 即可
Float同理類似
class Student(object):
def __init__(self, name, score):
self.name = name
self.__score = score
@property
def score(self):
return self.__score
@score.setter
def score(self, score):
if score < 0 or score > 100:
raise ValueError('invalid score')
self.__score = score
如上 可以通過對getter方法進行@progperty註解 ,這樣就會將score()衍生出score屬性,在呼叫的時候 可以通過 s.score來get或者set
I.__slots__
如果要限制新增的屬性,例如,Student類只允許新增 name、gender和score 這3個屬性,就可以利用Python的一個特殊的__slots__來實現。
顧名思義,__slots__是指一個類允許的屬性列表:
class Student(object):
__slots__ = ('name', 'gender', 'score')
def __init__(self, name, gender, score):
self.name = name
self.gender = gender
self.score = score
現在,對例項進行操作:
>>> s = Student('Bob', 'male', 59)
>>> s.name = 'Tim' # OK
>>> s.score = 99 # OK
>>> s.grade = 'A'
Traceback (most recent call last):
...
AttributeError: 'Student' object has no attribute 'grade'
__slots__的目的是限制當前類所能擁有的屬性,如果不需要新增任意動態的屬性,使用__slots__也能節省記憶體。
J.__call__
一個類例項也可以變成一個可呼叫物件,只需要實現一個特殊方法__call__()。
我們把 Person 類變成一個可呼叫物件:
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def __call__(self, friend):
print 'My name is %s...' % self.name
print 'My friend is %s...' % friend
現在可以對 Person 例項直接呼叫:
>>> p = Person('Bob', 'male')
>>> p('Tim')
My name is Bob...
My friend is Tim...
單看 p('Tim') 你無法確定 p 是一個函式還是一個類例項,所以,在Python中,函式也是物件,物件和函式的區別並不顯著。