判斷函數是否可調用
python2.x版本通過
callable(x)
3.x版本使用表達式
hasattr(func,__call__)
函數的參數
關鍵字參數和預設值
def hello_1(greeting,name):
print greeting,name
hello_1("hello","Saint")
定義了一個hello函數,它有兩個參數,這裡參數的順序很重要。但是如果參數很多的情況下,難免無法保證全部輸對,這時候可以提供參數的名字:
hello_1(name="Saint",greeting="nice to meet you,")
如上,隻要參數名稱提供對了,可以不用考慮順序。
關鍵參數還可以設定預設值:
def hello_2(greeting="hello", name="jack"):
print greeting, name
hello_2()
hello_2("nice to meet you")
hello_2(name="saint")
輸出:
hello jack
nice to meet you jack
hello saint
上面的3種用法都是可以的。
收集參數
可以傳入任意數量的參數:
def print_params(*params):
print params
print_params("Test") #('Test',)
print_params(1,2,3) #(1, 2, 3)
這個函數隻定義了一參數,前面加了個
*
号,類似于Java中的
...
。
*
号的作用是收集參數,從輸出可以看出python是用元組來儲存這些參數的。
還有一個能處理關鍵字參數用法:
def print_params_2(**params):
print params
print_params_2(x=1,y=2,z=3) #{'y': 2, 'x': 1, 'z': 3}
它列印的是字典而不是元組
收集參數的逆過程
所謂逆過程是指,不是在方法參數定義中使用
*
号,而是在調用方法的入參中使用。
def add(x,y):
return x+y
params = (1,2)
print add(*params) #3
這個add方法需要兩個參數,可以在調用時在元組params左邊添加一個
*
号。實作将元組内的兩個元素相加。
可以使用同樣的技術來處理字典-使用
**
運算符。
可以這樣使用
params = {'name':'jack','greeting':'nice to meet you'}
hello_2(**params) #nice to meet you jack
号對應元組,
*
号對應字典
**
函數式程式設計
函數可以配置設定給變量、作為參數傳遞以及從其他函數傳回。
In [5]: import functools
In [8]: def func(x):
...: return x.isalnum() # 檢測字元串是否由字母和數字組成
...:
In [9]: seq = ['foo','x41','?!','***']
In [10]: filter(func,seq)
Out[10]: <filter at 0x7fc99d586b70>
In [12]: list(filter(func,seq))
Out[12]: ['foo', 'x41']
(python3)
這裡函數
func
作為參數傳遞到了
filter()
函數。
類
建立自己的類
__metaclass__ = type #使用新式類
class Person:
def setName(self,name):
self.name = name
def getName(self):
return self.name
def greet(self):
print "Hello,world! I'm %s." % self.name
注意,這裡和Java中不同的是,
name
屬性之前沒有定義
self.name = name
将參數中的
name
指派到屬性
name
,保持着python中屬性不用定義的特性。
使用方法:
foo = Person()
bar = Person()
foo.setName("Saint")
bar.setName("Jack")
foo.greet()#Hello,world! I'm Saint.
bar.greet()#Hello,world! I'm Jack.
在setName和greet函數裡面有一個self,這裡的self類似于Java中的this,不過Java中的this是隐式的(即不需要在函數參數中寫明)。
還可以通過
.
号來通路變量:
foo.name = "Mikey"
foo.greet()
相當于name是公有域。
函數和方法
方法和函數的差別是self參數。方法(或稱為綁定方法)将它們的第一個參數綁定到所屬的執行個體上。
python中的方法一般指定義在對象中的method
私有化
Python不直接支援私有方式,但可以通過一些小技巧達到私有屬性的效果。
在方法或屬性的名字前面加上雙下劃線
__
可将方法或屬性變為私有
class Secretive:
def __inaccessible(self):
print "Bet you cant see me..."
def accessible(self):
print "The secret message is:"
self.__inaccessible()
通路一下看:
s = Secretive()
s.__inaccessible()#! AttributeError: 'Secretive' object has no attribute '__inaccessible'
上面嘗試通路這個方法會報錯,看起來像是其他語言中的标準私有方法。
類的内部定義中,所有以雙下劃線開始的名稱都被翻譯成前面加上單下劃線和類名的形式:
if __name__ == '__main__':
s = Secretive()
s._Secretive__inaccessible() # Bet you cant see me...
Java中也有這種類似的特例,能通過反射通路私有屬性和方法。權且通過這種方式來了解就好了
推薦使用單下劃線命名私有屬性或方法。
類的命名空間
所有位于class語句中的代碼都在類命名空間中執行。這個命名空間可由類内所有成員通路。
class MemberCounter:
members = 0
def init(self):
MemberCounter.members += 1
m1 = MemberCounter()
m1.init()
print MemberCounter.members #1
m2 = MemberCounter()
m2.init()
print MemberCounter.members #2
上面的代碼中在類作用域内定義了一個所有成員(執行個體)可以通路的變量,類似于Java中的類變量。注意每次都是通過類名去通路的。
如果執行個體中重綁定members:
m1.members = 'Hello'
print m1.members # Hello
print m2.members # 2
新members值被寫到了m1的特性中,屏蔽了類範圍内的變量。
指定超類
将其他類名寫在class語句後的圓括号内可以指定超類(父類):
class Filter:
def init(self):
self.blocked = []
def filter(self,sequence):
return [ x for x in sequence if x not in self.blocked]
class SPAMFilter(Filter):
def init(self): #重寫Filter超類中的init方法
self.blocked = ['SPAM']
s = SPAMFilter()
s.init()
print s.filter(['SPAM','SPAM','SPAM','SPAM','SPAM','SPAM','eggs','bacon','SPAM'])
列印
['eggs', 'bacon']
其中SPAMFilter的filter方法繼承了父類的方法。
檢查繼承
print issubclass(SPAMFilter,Filter) # True
s = SPAMFilter() # 檢查一個對象是否是另一個類的執行個體
print isinstance(s,SPAMFilter) # True
多個超類
class Calculator:
def caculate(self, expression):
self._value = eval(expression)
class Talker:
def talk(self):
print 'Hi, my value is ' , self._value
class TalingCalculator(Calculator,Talker):
pass
if __name__ == '__main__':
tc = TalingCalculator()
tc.caculate('1+2*3')
tc.talk() # Hi, my value is 7