class MyClass: def __init__(self): print "initialize..." def __play(self): print "play..." a = MyClass()initialize... a._MyClass__play()play... dir(a)['_MyClass__play', '__doc__', '__init__', '__module__']python的私有是偽的,還是可以訪問(wèn)到。 方法就是_類名__方法名,python不過(guò)是在以__開(kāi)頭的方法名面前加了小動(dòng)作導(dǎo)致訪問(wèn)不到看起來(lái)像私有方法。
成都創(chuàng)新互聯(lián)公司10多年企業(yè)網(wǎng)站制作服務(wù);為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁(yè)設(shè)計(jì)及高端網(wǎng)站定制服務(wù),企業(yè)網(wǎng)站制作及推廣,對(duì)木包裝箱等多個(gè)行業(yè)擁有多年的網(wǎng)站營(yíng)銷經(jīng)驗(yàn)的網(wǎng)站建設(shè)公司。
python中函數(shù)和方法的區(qū)別:
首先,從分類的角度來(lái)分析。
(1)函數(shù)的分類:
內(nèi)置函數(shù):python內(nèi)嵌的一些函數(shù)。
匿名函數(shù):一行代碼實(shí)現(xiàn)一個(gè)函數(shù)功能。
遞歸函數(shù)
自定義函數(shù):根據(jù)自己的需求,來(lái)進(jìn)行定義函數(shù)。
(2)方法的分類:
普通方法:直接用self調(diào)用的方法。
私有方法:__函數(shù)名,只能在類中被調(diào)用的方法。
屬性方法:@property,將方法偽裝成為屬性,讓代碼看起來(lái)更合理。
特殊方法(雙下劃線方法):以__init__為例,是用來(lái)封裝實(shí)例化對(duì)象的屬性,只要是實(shí)例化對(duì)象就一定會(huì)執(zhí)行__init方法,如果對(duì)象子類中沒(méi)有則會(huì)尋找父類(超類),如果父類(超類)也沒(méi)有,則直接繼承object(python 3.x)類,執(zhí)行類中的__init__方法。
類方法:通過(guò)類名的調(diào)用去操作公共模板中的屬性和方法。
靜態(tài)方法:不用傳入類空間、對(duì)象的方法, 作用是保證代碼的一致性,規(guī)范性,可以完全獨(dú)立類外的一個(gè)方法,但是為了代碼的一致性統(tǒng)一的放到某個(gè)模塊(py文件)中。
其次,從作用域的角度來(lái)分析:
(1)函數(shù)作用域:從函數(shù)調(diào)用開(kāi)始至函數(shù)執(zhí)行完成,返回給調(diào)用者后,在執(zhí)行過(guò)程中開(kāi)辟的空間會(huì)自動(dòng)釋放,也就是說(shuō)函數(shù)執(zhí)行完成后,函數(shù)體內(nèi)部通過(guò)賦值等方式修改變量的值不會(huì)保留,會(huì)隨著返回給調(diào)用者后,開(kāi)辟的空間會(huì)自動(dòng)釋放。
(2)方法作用域:通過(guò)實(shí)例化的對(duì)象進(jìn)行方法的調(diào)用,調(diào)用后開(kāi)辟的空間不會(huì)釋放,也就是說(shuō)調(diào)用方法中對(duì)變量的修改值會(huì)一直保留。
最后,調(diào)用的方式不同。
(1)函數(shù):通過(guò)“函數(shù)名()”的方式進(jìn)行調(diào)用。
(2)方法:通過(guò)“對(duì)象.方法名”的方式進(jìn)行調(diào)用。
class Foo(object): ? ?def func(self): ? ? ? ?pass#實(shí)例化obj = Foo()# 執(zhí)行方式一:調(diào)用的func是方法obj.func() #func 方法# 執(zhí)行方式二:調(diào)用的func是函數(shù)Foo.func(123) # 函數(shù)
你這個(gè)代碼很有問(wèn)題,
1. class Student:
def __init__(self):
for name in Name:
for id in ID:
self.name = name
self.id = id
最終Student得到的是實(shí)例有兩個(gè)變量name和id,他們的值分別是Kay和3,初始化時(shí)候的遍歷完全沒(méi)有意義。
2. self.lst.append("{} of {}".format(Student.__init__(self.id), Student.__init__(self.name)))
Student是一個(gè)類型,你都沒(méi)創(chuàng)建一個(gè)實(shí)例,__init__是實(shí)例的初始化函數(shù),使用"__"修飾,是私有函數(shù),不能在外部調(diào)用,然后那個(gè)里面參數(shù)的self是Students的self肯定是訪問(wèn)不到id和name的屬性的。
總的來(lái)說(shuō),代碼存在很多的問(wèn)題。
想要獲得的結(jié)果是兩個(gè)列表中元素所有組合的可能性,可以這樣實(shí)現(xiàn):
Name = ['Stella','Kay']
ID = [1,3]
result = [(a, b) for a in ID for b in Name]
這樣得到的result就是兩個(gè)列表的元素的組合
不是使用property才要私有的,而是為了調(diào)用私有方法方便,才使用property的,具體請(qǐng)看下面的詳解
在綁定屬性時(shí),如果直接把屬性暴露出去,雖然寫起來(lái)很簡(jiǎn)單,但是,沒(méi)辦法檢查參數(shù),導(dǎo)致可以把成績(jī)隨便改:
s?=?Student()
s.score?=?9999
這顯然不合邏輯。為了限制score的范圍,可以通過(guò)一個(gè)set_score()方法來(lái)設(shè)置成績(jī),再通過(guò)一個(gè)get_score()來(lái)獲取成績(jī),這樣,在set_score()方法里,就可以檢查參數(shù):
class?Student(object):
def?get_score(self):
return?self._score
def?set_score(self,?value):
if?not?isinstance(value,?int):
raise?ValueError('score?must?be?an?integer!')
if?value??0?or?value??100:
raise?ValueError('score?must?between?0?~?100!')
self._score?=?value
現(xiàn)在,對(duì)任意的Student實(shí)例進(jìn)行操作,就不能隨心所欲地設(shè)置score了:
s?=?Student()
s.set_score(60)?#?ok!
s.get_score()
60
s.set_score(9999)
Traceback?(most?recent?call?last):
...
ValueError:?score?must?between?0?~?100!
但是,上面的調(diào)用方法又略顯復(fù)雜,沒(méi)有直接用屬性這么直接簡(jiǎn)單。
有沒(méi)有既能檢查參數(shù),又可以用類似屬性這樣簡(jiǎn)單的方式來(lái)訪問(wèn)類的變量呢?對(duì)于追求完美的Python程序員來(lái)說(shuō),這是必須要做到的!
還記得裝飾器(decorator)可以給函數(shù)動(dòng)態(tài)加上功能嗎?對(duì)于類的方法,裝飾器一樣起作用。Python內(nèi)置的@property裝飾器就是負(fù)責(zé)把一個(gè)方法變成屬性調(diào)用的:
class Student(object):
@property
def?score(self):
return?self._score
@score.setter
def?score(self,?value):
if?not?isinstance(value,?int):
raise?ValueError('score?must?be?an?integer!')
if?value??0?or?value??100:
raise?ValueError('score?must?between?0?~?100!')
self._score?=?value
@property的實(shí)現(xiàn)比較復(fù)雜,先考察如何使用。把一個(gè)getter方法變成屬性,只需要加上@property就可以了,此時(shí),@property本身又創(chuàng)建了另一個(gè)裝飾器@score.setter,負(fù)責(zé)把一個(gè)setter方法變成屬性賦值,于是,就擁有一個(gè)可控的屬性操作:
s?=?Student()
s.score?=?60?#?OK,實(shí)際轉(zhuǎn)化為s.set_score(60)
s.score?#?OK,實(shí)際轉(zhuǎn)化為s.get_score()
60
s.score?=?9999
Traceback?(most?recent?call?last):
...
ValueError:?score?must?between?0?~?100!
注意到這個(gè)神奇的@property,在對(duì)實(shí)例屬性操作的時(shí)候,就知道該屬性很可能不是直接暴露的,而是通過(guò)getter和setter方法來(lái)實(shí)現(xiàn)的。
還可以定義只讀屬性,只定義getter方法,不定義setter方法就是一個(gè)只讀屬性:
class?Student(object):
@property
def?birth(self):
return?self._birth
@birth.setter
def?birth(self,?value):
self._birth?=?value
@property
def?age(self):
return?2014?-?self._birth
上面的birth是可讀寫屬性,而age就是一個(gè)只讀屬性,因?yàn)閍ge可以根據(jù)birth和當(dāng)前時(shí)間計(jì)算出來(lái)。
一句話總結(jié)
@property廣泛應(yīng)用在類的定義中,可以讓調(diào)用者寫出簡(jiǎn)短的代碼,同時(shí)保證對(duì)參數(shù)進(jìn)行必要的檢查,這樣,程序運(yùn)行時(shí)就減少了出錯(cuò)的可能性。
9.6. 私有變量
只能從對(duì)像內(nèi)部訪問(wèn)的“私有”實(shí)例變量,在 Python 中不存在。然而,也有一個(gè)變通的訪問(wèn)用于大多數(shù) Python 代碼:以一個(gè)下劃線開(kāi)頭的命名(例如 _spam )會(huì)被處理為 API 的非公開(kāi)部分(無(wú)論它是一個(gè)函數(shù)、方法或數(shù)據(jù)成員)。它會(huì)被視為一個(gè)實(shí)現(xiàn)細(xì)節(jié),無(wú)需公開(kāi)。
因?yàn)橛幸粋€(gè)正當(dāng)?shù)念愃接谐蓡T用途(即避免子類里定義的命名與之沖突),Python 提供了對(duì)這種結(jié)構(gòu)的有限支持,稱為 name mangling (命名編碼) 。任何形如 __spam 的標(biāo)識(shí)(前面至少兩個(gè)下劃線,后面至多一個(gè)),被替代為 _classname__spam ,去掉前導(dǎo)下劃線的 classname 即當(dāng)前的類名。此語(yǔ)法不關(guān)注標(biāo)識(shí)的位置,只要求在類定義內(nèi)。
名稱重整是有助于子類重寫方法,而不會(huì)打破組內(nèi)的方法調(diào)用。例如:
class Mapping:
def __init__(self, iterable):
self.items_list = []
self.__update(iterable)
def update(self, iterable):
for item in iterable:
self.items_list.append(item)
__update = update # private copy of original update() method
class MappingSubclass(Mapping):
def update(self, keys, values):
# provides new signature for update()
# but does not break __init__()
for item in zip(keys, values):
self.items_list.append(item)
需要注意的是編碼規(guī)則設(shè)計(jì)為盡可能的避免沖突,被認(rèn)作為私有的變量仍然有可能被訪問(wèn)或修改。在特定的場(chǎng)合它也是有用的,比如調(diào)試的時(shí)候。
要注意的是代碼傳入 exec(), eval() 時(shí)不考慮所調(diào)用的類的類名,視其為當(dāng)前類,這類似于 global 語(yǔ)句的效應(yīng),已經(jīng)按字節(jié)編譯的部分也有同樣的限制。這也同樣作用于 getattr(), setattr() 和 delattr(),像直接引用 __dict__ 一樣。