xx: 公有變量
_x: 單前置下划線,私有化屬性或方法,from somemodule import 禁止導入,類對象和子類可以訪問【另解:前置單下划線,又稱口頭私有變量,私有化屬性或方法的一種,一般來講,變量名_xx被看作是“私有 的”,在模塊或類外不可以使用。當變量是私有的時候,用_xx 來表示變量是很好的習慣。類對象和子類可以訪問,這並不能完全做到真正的私有,只是約定俗成的而已,這樣寫表示不希望這個變量在外部被直接調用】
__xx:雙前置下划線,避免與子類中的屬性命名沖突,無法在外部直接訪問(名字重整所以訪問不到)【__xx:前置雙下划線,私有化屬性或方法,只有內部可以訪問,外部不能訪問。】
__xx__:雙前后下划線,用戶名字空間的魔法對象或屬性。例如:init , __ 不要自己發明這樣的名字【__xx__:以雙下划線開頭,並且以雙下划線結尾的,是特殊變量(這就是在python中強大的魔法方法),特殊變量是可以直接訪問的,對於普通的變量應當避免這種命名風格。】
xx:單后置下划線,用於避免與Python關鍵詞的沖突
通過name mangling(名字重整(目的就是以防子類意外重寫基類的方法或者屬性)如:_Class__object)機制就可以訪問private了。
#coding=utf-8 class Person(object): def __init__(self, name, age, taste): self.name = name self._age = age self.__taste = taste def showperson(self): print(self.name) print(self._age) print(self.__taste) def dowork(self): self._work() self.__away() def _work(self): print('my _work') def __away(self): print('my __away') class Student(Person): def construction(self, name, age, taste): self.name = name self._age = age self.__taste = taste def showstudent(self): print(self.name) print(self._age) print(self.__taste) @staticmethod def testbug(): _Bug.showbug() # 模塊內可以訪問,當from cur_module import *時,不導入 class _Bug(object): @staticmethod def showbug(): print("showbug") s1 = Student('jack', 25, 'football') s1.showperson() print('*'*20) # 無法訪問__taste,導致報錯 # s1.showstudent() s1.construction('rose', 30, 'basketball') s1.showperson() print('*'*20) s1.showstudent() print('*'*20) Student.testbug()
----------------------------------------------講解----------------------------------------------------------------------------------------
1.Python中屬性:類屬性 ,實例屬性,私有屬性的使用
在Python中的屬性分為:類屬性和對象(實例)屬性:
1.類屬性就是屬於類所有,可以直接用類名.屬性名直接調用,類的屬性在內存中只有一份。實例屬性就是在__init__()方法中初始化的屬性;
2.實例屬性屬於類的對象所有,可以用對象名.屬性名的形式進行調用,但是不能用類名.屬性名進行調用 。因為實例屬性只有在實例創建時,才會初始化創建。
#1.類屬性和實例的屬性的調用關系 class Person: country ="china" #類屬性 def __init__(self,name,age): sex ="男" #這不是實例屬性,只是變量而已,用對象名.sex調不出來。 self.name = name #實例屬性 self.age = age #創建對象 print(Person.country) #print(Person.age) 出錯,AttributeError: type object 'Person' has no attribute 'age' p1 = Person("tom",12) print(p1.country,p1.age,p1.name,p1) ----------結果如下------------------------------------------------------------------------ china china 12 tom ---------------------------------------------------------------------------------------- #2.修改類屬性和實例屬性:類屬性只能通過類名.屬性才可以修改 class Person: country ="china" #類屬性 def __init__(self,name,age): sex ="男" #這不是實例屬性,只是變量而已,用對象名.sex調不出來。 self.name = name #實例屬性 self.age = age -------創建對象------------------------------------------------------------------------- p1.country = "america" print(p1.country) #通過實例去修改屬性,實例的屬性修改了:america print(Person.country)#但是類的屬性還是沒有修改:china Person.country = "japan" #只有用類名.屬性名才能修改類的屬性值。 p2= Person("jack",11) print("p1.country:",p1.country) print("p2.country",p2.country) print("Person.country",Person.country) ------結果如下----------------------------------------------------------------------------- america china p1.country: america p2.country japan Person.country japan
實際開發中為了程序的安全,關於類的屬性都會封裝起來,Python中為了更好的保存屬性安全,即不能隨意修改。一般屬性的處理方式為:1.將屬性定義為私有屬性。2.添加一個可以調用的方法,供調用。
3.Python中用__兩個下划線開頭,聲明該屬性為私有,不能在類地外部被使用或直接訪問
class Person1(object): country ='china' #類屬性 __language ="Chinese" #私有類屬性也不能直接外部調用 def __init__(self,name,age): self.name = name self.__age = age #使用__下划線表示私有屬性,對象不能直接調用,要通過方法調調用 def getAge(self): return self.__age def setAge(self,age): if age >100 or age <0: print("age is not true") else : self.__age = age def __str__(self): info = "name :"+self.name +",age(保密):"+str(self.__age) #注意這里不是self.age return info #------創建對象,調用方法,屬性測試------------------------------------------------------- stu1 = Person1("tom",18) print("修改前的結果:",stu1.__str__()) stu1.name="tom_2" #修改stu1的name屬性 print("修改name后的結果:",stu1.__str__()) #print(stu1.__age) #直接調用私有屬性__age報錯,'Person1' object has no attribute '__age' print("打印私有age內存地址:",id(stu1.getAge())) stu1.__age = 19 #如果這樣賦值的話,不會報錯,因為系統找不到這個變量,直接新建了一個。但是實際沒有修改對象的屬性值 print(stu1.__age) #有值,但是沒有 實際修改stu1對象的age屬性值 print("打印stu1.__age的內存地:",id(stu1.__age)) #兩個內存地址值不一樣。 print("錯誤修改age后的值",stu1.__str__()) #實際值沒有變 stu1.setAge(22) #只有調用才可以修改age的值 print("正確修改age后的值",stu1.__str__()) '''執行結果如下: 修改前的結果: name :tom,age(保密):18 修改name后的結果: name :tom_2,age(保密):18 打印私有age內存地址: 1388146224 19 打印stu1.__age的內存地: 1388146256 錯誤修改age后的值 name :tom_2,age(保密):18 正確修改age后的值 name :tom_2,age(保密):22 '''
2.私有方法,類方法,靜態方法的使用
1.私有方法:以 __兩個下划線開頭,聲明該方法為私有方法,只能在類的內部調用 (類內部別的方法可以調用他),不能在類地外部調用。
lass Person5: def __p(self): print("這是私有屬性") #內部函數也同樣可以任意之間互相調用 def p1(self): print("這是p1不是私有方法") def p2(self): print("這是p2,可以調用p1,也可以調用私有方法__p") self.p1() self.__p() #創建對象 c1 = Person5() c1.p1() c1.p2() #c1.__p() #不能直接私有函數。報錯。注意區分系統自帶的函數如__str__,外部可以直接調用的。 '''結果如下: 這是p1不是私有方法 這是p2,可以調用p1,也可以調用私有方法__p 這是p1不是私有方法 這是私有屬性 '''
2.類方法的使用:是類所擁有的方法,需要用修飾器@classmethod來標識其為類方法,對於類方法,第一個參數必須是類對象,一般以cls作為第一個參數,也可以有別的參數。但是第一個必須是類對象,類似類中的def定義的普通方法第一個參數要是self一樣的道理
class People(object): country = 'china' #類方法,用classmethod來進行修飾,跟普通的方法區別就是可以直接通過類名.方法名的方式調用 @classmethod def getCountry(cls): return cls.country @classmethod def sum(cls,a,b): return a+b p = People() print (p.getCountry()) #可以用過實例對象引用 print (People.getCountry() ) #可以通過類名.方法名的形式調用 print(p.sum(10,11)) print(People.sum(10,11)) ==================================================================================== china china 21 21 3.靜態方法:需要通過修飾器@staticmethod來進行修飾,靜態方法不需要多定義參數 class People(object): country = 'china' @staticmethod #靜態方法,不用定義參數 def getCountry(): return People.country print (People.getCountry())
3.方法的使用注意要點
注意python中不支持方法的重載:即方法名相同,參數類型(參數個數不同)不同的函數,python中 不支持。
def p(): print("dd") def p(a,b): print("dd") def p(a): print("dd") p()#報錯,因為python中不需要定義參數的類型。如果有多個重載的函數,則python默認只能使用最后一個有效。 所以只能調用P(a)這個函數