1. 程式人生 > >python封裝與隱藏,擴充套件模組方法

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的檔案,可以直接執行,二進位制檔案還不可逆,保證了

程式碼的不洩露

發現太多了....再開一篇