python封裝與隱藏,擴充套件模組方法
封裝分兩個層面:
1建立類的時候,分別建立兩者的名稱空間,只能通過類名加"."或者object.的方式來訪問裡面的名字
2,類中把某些屬性和方法隱藏起來,或者定義為私有,只有類的內部使用,在類的外部無法使用,
或者留下少數的介面(函式)供外使用
但是無論哪種層面的封裝都要對外提供好訪問內部隱藏內容的介面
在python中,使用雙下劃線的方式實現隱藏功能(設定成私有的屬性)
在python中隱藏類的私有屬性用什麼方法呢??
class Teacher: def __init__(self,name,age,course): self.name=name self.age=age self.course=course def teach(self): print("%s is teaching"%self.name) class Student: def __init__(self,name,age,group): self.name=name self.age=age self.group=group def study(self): print("%s is studying"%self.name) t1=Teacher("alex",28,"python") s1=Student("jack",22,"group2") print(t1.name,t1.age,t1.course) print(s1.name,s1.age,s1.group) 把兩類長得一些屬性隱藏起來後,程式碼如下: class Teacher: def __init__(self,name,age,course): self.__name=name self.__age=age self.__course=course def teach(self): print("%s is teaching"%self.__name) class Student: def __init__(self,name,age,group): self.__name=name self.__age=age self.__group=group def study(self): print("%s is studying"%self.__name) t1=Teacher("alex",28,"python") s1=Student("jack",22,"group2") print(t1.name,t1.age,t1.course) print(s1.name,s1.age,s1.group) 會出現traceback........因為屬性值已經私有..... 可以看到隱藏屬性後,再像以前那樣訪問物件內部的屬性,就會返回屬性錯誤,那現在要怎麼才能訪問其內部屬性呢? 現在來檢視t1和s1的名稱空間 print(t1.__dict__) {'_Teacher__name': 'alex', '_Teacher__age': 28, '_Teacher__course': 'python'} print(s1.__dict__) {'_Student__name': 'jack', '_Student__age': 22, '_Student__group': 'group2'} print(t1._Teacher__name) print(t1._Teacher__age) print(t1._Teacher__course) 這次沒有報錯了,看來隱藏屬性之後可以通過"_類名__屬性"的方式來訪問其內部的屬性值, 來得到和隱藏屬性之前,直接檢視其內部屬性一樣的值。 python並不會真的阻止開發人員訪問類的私有屬性,模組也是遵循這種約定。 很多模組都有以單下劃線開頭的方法,此時使用 from module import * 時,這些方法是不會被匯入的,此時必須要通過 from module import _private_module來倒入這個模組
property裝飾:
property裝飾器用於將被裝飾的方法偽裝成一個數據屬性, 在使用時可以不用加括號而直接引用
class People: def __init__(self,name,weight,height): self.name=name self.weight=weight self.height=height def bmi(self): return self.weight / (self.height**2) peo=People('張三',130,1.65) print(peo.name) #張三 print(peo.bmi()) #47.75022956841139
#property裝飾器 #是一種封裝思想的體現,方便了查 刪 改 class people: def __init__(self,name): self.__name=name @property def name(self): #檢視obj.name return '名字是:%s'%self.__name @name.setter #更改obj.name=name def name(self,name): if type(name) is not str: raise TypeError('名字必須是str型別') self.__name=name @name.deleter #刪除 del obj.name def name(self): print('不讓刪除') #裡面可以設定提示 # del self.__name #也可以設定直接刪除功能 peo=people('張三') #預設不加@property呼叫方法為: peo.name='李四' #@name.setter 呼叫了更改 print(peo.name) #@property 呼叫了檢視 輸出結果:名字是:李四 del peo.name #@name.deleter 呼叫了產出的需求 輸出結果:不讓刪除
繫結方法: 特性:繫結給誰就應該由誰來呼叫,誰來呼叫就會將誰當做第一個引數
精髓:是在於自動傳值 繫結物件的方法:在類內部定義的函式(沒有被任何裝飾器修飾的),預設是繫結
給物件用的, 繫結給物件的:自動傳的是物件的值 繫結給類的方法:在類內部定義的函式如果被裝飾器@classmethod裝飾, 那麼則是繫結給類的,應該由類來呼叫,類來呼叫就自動將類當做第一個引數自動傳入 繫結給類的:自動傳的是類的值
非繫結方法
類中定義的函式如果被裝飾器@staticmethod裝飾,那麼該函式就變成非繫結方法 既不與類繫結,又不與物件繫結,意味著類與物件都可以來呼叫 但是無論誰來呼叫,都沒有任何自動化傳值的效果,就是一個普通函式
什麼時候繫結給類? 什麼時候繫結給物件?取決於函式體程式碼 如果函式體程式碼需要用外部傳入的類,則應該將該函式定義成繫結類的方法 如果函式體程式碼需要用外部傳入的物件,則應該將該函式定義成繫結給物件的方法 如果函式體程式碼既不需要外部傳入的類也不需要外部傳入的物件,則應該將該函式定義成非繫結方法物件,
#繫結方法初始例項:繫結給類@classmethod
class Foo:
@classmethod
def f1(cls):
print('Foo.f1')
print(cls)
def f2(self):
print(self)
obj=Foo()
# print(obj.f2) #預設繫結給物件用#<bound method Foo.f2 of <__main__.Foo object at 0x04BACD10>>
# print(Foo.f1) #繫結給類用 <bound method Foo.f1 of <class '__main__.Foo'>>
Foo.f1() #類呼叫
print(Foo) #所以傳入的值就是類的值 <class '__main__.Foo'>
obj.f2() #物件呼叫,
print(obj) #所以傳入的值就是物件的值 <__main__.Foo object at 0x04C50EB0>
# f1繫結給類的應該由類來呼叫,但物件其實也可以使用,只不過自動傳入的任然是類
#f2繫結給物件的應該由物件來呼叫,但是類其實也可以使用
# 繫結方法進階例項2:新的例項化方式,繫結給類
"""
將需要傳入的資訊寫到settings.py檔案裡面,呼叫更加靈活方便
IP='192.168.11.3'
PORT=3306
"""
import settings
class Mysql:
def __init__(self,ip,port):
self.ip=ip
self.port=port
def tell_info(self):
print('%s:%s'%(self.ip,self.port))
# print(self)
@classmethod
def from_conf(cls):
return cls(settings.IP,settings.PORT) #可以理解為 Mysql('1.1.1.1',23)即呼叫了init方法,給其傳引數 cls名字可以隨便起
# print(settings.IP)
#預設的例項化方式:類名(..)(實質給tell_info(self)裡的self傳的是物件res的值)
res=Mysql('1.1.1.1',23)
print(res) #<__main__.Mysql object at 0x05717410>即為物件res也就是tell_info(self)的值
res.tell_info()
# 一種新的例項化方式,從配置檔案中讀取配置完成例項化(這裡實質給cls傳的是類Mysql的值)
res=Mysql.from_conf()
res.tell_info()
print(res.ip)
擴充套件模組:有兩種
一種是按照程式碼的規範,用C/C++直接寫python模組; 此方法開發出來的擴充套件模組(DLL動態庫),可看做原生的python模組, 不需要依賴其他第三方庫;缺點是,開發需要寫大量的規範的C/C++到Python的轉換程式碼
第二種是現在有好多的可以直接將python程式碼轉化為cpy的檔案,可以直接執行,二進位制檔案還不可逆,保證了
程式碼的不洩露
發現太多了....再開一篇