# -*- coding: utf-8 -*-
"""
Created on Fri May 20 01:48:27 2017
@author: zhangll
"""
? ? 函數(shù)也是p對(duì)象,學(xué)過java的同學(xué)都知道“方法”的概念载城,“方法”在java的表現(xiàn)中是指一段程序流程的封裝,而python函數(shù)可以在這個(gè)概念上與java的“方法”概念相呼應(yīng)。但是java
方法調(diào)用的參數(shù)分為實(shí)參和形參赴肚,java中并沒有傳遞“方法”參數(shù)這一說法,一般是通過
包裝好的類、變量作為參數(shù)來實(shí)現(xiàn)程序的轉(zhuǎn)移的。在python中卻可以利用“函數(shù)”作為參數(shù)來傳遞的荚斯,可以說python把“函數(shù)”作為一個(gè)“對(duì)象”來考慮的。如下:我們看一個(gè)簡單的例子:
def pythagorean(a,b):
? ? ? ? return sum((a**2,b**2))**0.5
def pythagoreandouble(funcation,c):
? ? ? ? return funcation(c[0]*2,c[1]*2)
if__name__=='__main__':
? ? ? ? pythagoreandouble(pythagorean,(3,4))
其中pythagorean是勾股定理查牌,我們把pythagorean函數(shù)作為一個(gè)參數(shù)傳入pythagoreandouble(計(jì)算勾股的兩倍)函數(shù)中事期,作為一個(gè)函數(shù)來使用,結(jié)果為纸颜,擴(kuò)充了一倍兽泣,結(jié)果:
Out[361]: 10.0
接下來對(duì)python函數(shù)做幾個(gè)補(bǔ)充,希望對(duì)大家在之后的學(xué)習(xí)中有所幫助:
1.函數(shù)基本組成
由“def”關(guān)鍵字作為定義頭:def(define)相當(dāng)于是一個(gè)定義胁孙,
格式為---------------------------------
def(arg1,arg2,...,argn):
? ? ? ? [function body]
? ? ? ? [return object]
跟絕大多數(shù)語言一樣唠倦,都是以
? ? ? ? ? ? ? ? 方法名(參數(shù))(方法體)[返回值(可有可無)]
構(gòu)成的称鳞。一般情況下在不賦值的情況下,會(huì)生成一個(gè)“匿名對(duì)象”牵敷,而一旦以
? ? ? ? ? ? ? ? ?place=方法名(參數(shù))
如上表達(dá)式出現(xiàn)的時(shí)候胡岔,python就會(huì)產(chǎn)生一個(gè)新的“p對(duì)象”法希,并把這個(gè)對(duì)象“賦值”給place枷餐。place在這里就成了一個(gè)變量,是一個(gè)特殊的對(duì)象苫亦,該對(duì)象具有指向“p對(duì)象”的指針毛肋。
2.把“函數(shù)”作為一個(gè)對(duì)象來使用,因此“函數(shù)”的編寫可以處于代碼模塊中的任何一個(gè)位置屋剑,這種寫法非常自由润匙,可以說秉承了python里一切都是對(duì)象的邏輯。舉個(gè)栗子:
test=True
if test:
? ? ? ? def funct1(a,b):
? ? ? ? return sum((a**2,b**2))**0.5
else:
? ? ? ? def funct2(a,b):
? ? ? ? return sum((a**2,b**2))**1
如果運(yùn)行這段代碼唉匾,根據(jù)test==true的邏輯孕讳,只有funct1被加載了,而funct2并未被加載(為被定義)巍膘,這樣大家可以靈活使用python函數(shù)厂财,編寫自己想要的結(jié)構(gòu)模式。
3.python的函數(shù)傳遞的是任何類型的對(duì)象“引用”峡懈,一旦對(duì)象在函數(shù)體中處于被操作修改璃饱,那么被傳遞進(jìn)去的源“對(duì)象”將被修改,甚至只要對(duì)象符合函數(shù)體中的計(jì)算邏輯運(yùn)算肪康,那么所傳遞的參數(shù)對(duì)象并不受數(shù)據(jù)類型(int荚恶,list,tuple磷支,dict谒撼,array)的限制,這個(gè)比Java函數(shù)定義寬容了許多雾狈,比如下面這段代碼:
def funct3(a,b):
? ? ? ? return a*b
if __name__='__main__':
? ? ? ? funct3(1,2) ? ? ? ? ? ?#Out[*]: 2
? ? ? ? funct3("c",2) ? ? ? ? #Out[*]: 'cc'
也就是說"*"操作不僅可以作為整數(shù)之間的“乘法”作用廓潜,也可以作為整數(shù)與字符串之間的合并操作,這個(gè)是一種python“多態(tài)”的行為箍邮。但這種“多態(tài)”與java中的“多態(tài)”卻不一樣茉帅。我們知道java是強(qiáng)類型語言,注定與python這種弱類型語言在語法上的規(guī)定有著較大的差異锭弊。
java的多態(tài)體現(xiàn)在下面三個(gè)條件上
? ? ? ? 1.繼承
? ? ? ? 2.重寫
? ? ? ? 3.父類引用指向子類對(duì)象
三種條件完備的情況下堪澎,才能稱為java“多態(tài)”,符合第1味滞、2條件的語言頂多叫做“基于對(duì)象”的語言樱蛤,而真正能夠?qū)崿F(xiàn)第三個(gè)條件的才能在真正意義上來講屬于“面向?qū)ο蟆钡恼Z言钮呀。而且第1、2兩點(diǎn)是第三點(diǎn)(最重要特性)的基礎(chǔ)昨凡,這樣才能出現(xiàn)“多態(tài)”的特征爽醋。
多態(tài)相關(guān)內(nèi)容看http://www.cnblogs.com/tanqiantot/archive/2013/03/27/3126818.html
而python中的“變量”首先是弱類型定義的,就在先天無法實(shí)現(xiàn)第三個(gè)條件便脊,即無法實(shí)現(xiàn)父類變量的聲明來指向子類的對(duì)象蚂四。那么即使這樣,難道python就不具有“多態(tài)”特性了嗎哪痰?讓我們繼續(xù)分析一下遂赠,我們知道python本身是可以實(shí)現(xiàn)繼承和重寫的,如下例子:
class Animal:
def __init__(self, name):
? ? ? ? self.name = name
def talk(self):
? ? ? ? raise NotImplementedError("Subclass must implement abstractmethod")
def eat(self):
? ? ? ? return '吃飯了'
class Cat(Animal):
def talk(self):
? ? ? ? return 'Meow!'
class Dog(Animal):
def talk(self):
? ? ? ? return 'Woof! Woof!'
if __name__='__main__':
? ? ? ? animals = [Cat('Missy'),Cat('Mr. Mistoffelees'),Dog('Lassie')]
? ? ? ? for animal in animals:
? ? ? ? ? ? ? ? ? print animal.name + ': ' + animal.talk()
? ? ? ? ? ? ? ? ? print animal.name + ': ' + animal.eat()
輸出結(jié)果:
Missy: Meow!
Missy:吃飯了
Mr. Mistoffelees: Meow!
Mr. Mistoffelees:吃飯了
Lassie: Woof! Woof!
Lassie:吃飯了
在Cat和Dog類中并沒有聲明eat函數(shù)晌杰,但是我們用Cat(父類)的方式實(shí)現(xiàn)了子類對(duì)父類的繼承跷睦,所以子類本身就具有了eat函數(shù)功能,就想父親需要吃飯一樣肋演,繼承的子類也需要有吃的動(dòng)作抑诸。
? ? 然而通過查看python的一些學(xué)習(xí)手冊(cè)和編程指南以及各位python大咖對(duì)python程序的設(shè)計(jì)心得方面的內(nèi)容,始終無法找到能夠滿足第三個(gè)條件特性代碼爹殊,有些人覺得python因?yàn)闊o法體現(xiàn)第三個(gè)條件而認(rèn)為python沒有“多態(tài)”的特性蜕乡,更有甚者認(rèn)為python缺乏多態(tài)特性而認(rèn)為python并不是一個(gè)面向?qū)ο蟮某绦蛟O(shè)計(jì)語言。
? ? 通過wiki對(duì)多態(tài)解釋來了解一下什么是多態(tài)(polymorphism)边灭,個(gè)人也傾向于wiki的解釋异希,其認(rèn)為對(duì)同一操作的行為(*,len())的合理性意義會(huì)根據(jù)傳遞的對(duì)象類型的不同來判斷的绒瘦〕撇荆或者用多態(tài)的原意:同一操作作用于不同對(duì)象,可以有不同的解釋惰帽,生成不一樣的結(jié)果憨降。這樣的描述同樣適用于java多態(tài)的第三個(gè)條件:即同一類(父類)引用不同的對(duì)象(不同子類,但是子類有相同方法)该酗,對(duì)父類的同一操作(方法)實(shí)質(zhì)是作用于不同對(duì)象授药,得到不一樣的結(jié)果。這視乎很繞呜魄,但是我們要理解”多態(tài)“的本質(zhì)悔叽,就比較容易。當(dāng)初定義”多態(tài)“爵嗅,其實(shí)是為“程序設(shè)計(jì)”作服務(wù)的娇澎,因?yàn)橛辛诉@個(gè)概念,才能很好地實(shí)現(xiàn)java中的父類引用指向子類對(duì)象的程序設(shè)計(jì)睹晒,才能理解并自己開發(fā)這樣的程序趟庄。同樣的括细,基于此,我們對(duì)python的”多態(tài)“理解也是為了python程序設(shè)計(jì)需求而提出的一種概念戚啥,我以三種不同的程序流來表示python的”多態(tài)“概念:
a) ? ?利用*號(hào)做運(yùn)算(就如我們剛才提到的勾股定理程序)奋单,我們可以輸入1*10得到10,也可以輸入“a”*3得到“aaa”猫十,前者做了類似于相加的運(yùn)算览濒,而后者做了相當(dāng)于拼接字符的運(yùn)算,雖然我們做了同樣的操作卻得到了不同地解釋或運(yùn)算方式炫彩,而這種不同依據(jù)傳入的對(duì)象的數(shù)據(jù)類型的不同而表現(xiàn)出不同的特性匾七。
b) ? ?利用len()函數(shù)分別對(duì)元組(1絮短,2江兢,3)和列表[1,2丁频,3]
? ? ? ?len((1,2,3)) ? ?#Out[6]: 3
? ? ? ?len([1,2,3]) ? ?#Out[7]: 3
其實(shí)質(zhì)是元組和列表本身就帶有__len__的特殊方法杉允,實(shí)現(xiàn)了不同的計(jì)算原則,而len函數(shù)(同一操作)調(diào)用了不同對(duì)象的__len__方法所存儲(chǔ)的值席里,實(shí)現(xiàn)了對(duì)不同數(shù)據(jù)類型對(duì)象的同一操作(讀仁辶住)的功能,而并沒有做計(jì)數(shù)的操作奖磁。這里我們也發(fā)現(xiàn)改基,一般使用內(nèi)置函數(shù)比自己編寫函數(shù)效率高的原因通過這個(gè)方法的理解可見一斑。
c)通過定義不同類來實(shí)現(xiàn)對(duì)不同對(duì)象做同一操作:(分別定義三個(gè)類咖为,每個(gè)類中都有eat函數(shù)秕狰,并通過循環(huán)對(duì)不同對(duì)象進(jìn)行操作)
class A:
? ? ? ? def eat(self):
? ? ? ? ? ? ? ?return "A"
class B:
? ? ? ? def eat(self):
? ? ? ? ? ? ? ? return "B"
class C:
? ? ? ? def eat(self):
? ? ? ? return "C"
if __name__='__main__':
? ? ? ? list1=[A(),B(),C()]
? ? ? ? [x.eat() for x in list1] ? ? ? ?#Out[11]: ['A', 'B', 'C']
如上三個(gè)例子充分地展現(xiàn)了python的“多態(tài)”針對(duì)的是“同一操作”可以對(duì)不同對(duì)象產(chǎn)生不一樣的結(jié)果,而java等語言的“操作”更偏向于正對(duì)“同一父類”使用相同操作實(shí)現(xiàn)不一樣的方式躁染,而本質(zhì)上這“同一父類”其實(shí)指向的是不同子類對(duì)象鸣哀。在這個(gè)層面上來說,python可以被認(rèn)為是具有“多態(tài)”特性的吞彤。
4.形參與實(shí)參的概念
一般計(jì)算機(jī)語言把定義函數(shù)或方法(被調(diào)用函數(shù)或方法)上(括號(hào)中所包含的定義)關(guān)鍵字
5.函數(shù)的參數(shù)*args與**kwargs的區(qū)別
后續(xù)更新吧