python面向對象編程(2)

類編寫細節

1.class 語句python

class語句細節python3.x

  • python的class語句是屬於OOP的一種工具(即定義變量名的工具,將數據和邏輯暴露給客戶端),而不是聲明式的
  • class語句是對象的建立者,相似於對象工廠
  • class語句是一種隱含的賦值運算,即執行class語句時,會產生類對象而且將其引用存儲到定義的類名稱上
  • class語句與def同樣,都是可執行語句,即python尚未執行到class語句時,類是不存在的
  • class是複合語句,全部種類語句均可以位於其主體內,如print, 賦值語句, if, def...

class語句如何獲得命名空間函數

  • 首先,執行類語句的時候,會從頭到尾執行其主體內的全部語句
  • 其次,是在執行過程當中的賦值運算會在這個類做用域中建立變量名,從而成爲對應的類對象屬性
  • 與函數相比,能夠把class語句當作一個本地做用域,在class語句下定義的變量就屬於這個本地做用域
  • 與模塊相比,定義的變量名是能夠共享的而且成爲當前類的對象屬性

class語句通常形式 工具

## 根據上述所言,className是類對象的一個引用
class className(superclass1,superclass2,...):          
    ''' 定義類屬性,屬於全部實例的共享數據,經過類語句下進行定義和建立 '''
    class_attr = value 


    ''' 定義實例方法以及實例屬性 '''
    def method(self,data):      ## 定義實例方法
        self.attr = data        ## 設置實例屬性,經過帶有self的方法來分配屬性信息複製代碼

2.方法優化

實例方法對象調用等價於類方法函數調用ui

## python自動將實例方法的調用自動轉成類方法函數,並傳遞實例對象做爲第一個參數傳遞
class Person:
    def study(self,name):
        print("%s study method in for %s" % (name,self.__class__.__name__)

>>> p = Person()
>>> p.study("keithl")
keithl study method in for Person

>>> Person.study(p,"keithl")
keithl study method in for Person

## instance.method(arg1,arg2,...) == class.method(instance,arg1,arg2,...)複製代碼

調用超類的構造函數__init__方法spa

class Person:
    def __init__(self):
        print("call person init ....")

class Student(Person):
    pass

>>> s = Student()               ## 建立子類時會調用父類構造函數,緣由是子類沒有定義本身的構造函數
call person init ....

## 爲子類增長構造函數
class Student(Person):
    def __init__(self):
        print("call student init ....")

>>> s = Student()               ## 只輸出子類的__init__方法,並無調用父類方法,緣由在於python是根據命名空間來執行調用方法
call student init ....

## 若要調用父類構造方法則必須顯示進行調用
class Student(Person):
    """ 必須在子類構造函數中顯式調用父類的構造函數,並傳遞子類的self引用 """
    def __init__(self):
        print("call student init start....")
        Person.__init__(self)              
        print("call student init end....")

>>> s = Student()               
call student init start....
call person init ....
call student init end....複製代碼

靜態方法code

  • 使用場景:
    • 目標:爲全部類實例提供數據共享的類屬性
    • 執行:經過類名稱訪問類屬性
    • 優化:其一是使用OOP思想封裝類屬性而對外提供方法,其二是考慮擴展性,經過繼承來定製
    • 落地:使用靜態方法或者類方法,即不須要傳遞類對象self實例參數的方法
## person.py
class Person:
    num = 1
    """ 定義一個沒有帶參數的普通方法 """
    def printNum():
        Person.num += 1
        print("the number is %s" % Person.num)

    printNum = staticmethod(printNum)                   ## 聲明爲靜態方法

    """ 定義一個帶參數的普通方法,此參數爲類對象參數 """
    def clsPrintNum(cls):
        Person.num += 1
        print("the number is %s" % Person.num)         

    clsPrintNum = classmethod(clsPrintNum)              ## 聲明爲類方法

>>> Person.printNum()
the number is 2

>>> Person.clsPrintNum()
the number is 3

## person.py 使用裝飾器來聲明靜態或類方法
class Person:
    num = 1

 @staticmethod
    def printNum():
        Person.num += 1
        print("the number is %s" % Person.num)

 @classmethod
    def clsPrintNum(cls):
        Person.num += 1
        print("the number is %s" % Person.num)複製代碼

靜態方法、類方法與實例方法cdn

  • 類中帶有實例對象self的參數傳遞的方法稱爲實例方法
  • 類中帶有類對象cls的參數傳遞的方法並經過函數classmethod或者裝飾器@classmethod聲明的方法稱爲類方法
  • 類中沒有實例對象self和類對象cls參數傳遞的方法,且經過staticmethod或裝飾器@staticmethod什麼的方法稱爲靜態方法
class Person:

 @staticmethod
    def static_method():
        print("static method ...")

 @classmethod
    def class_method(cls):
        print("class method ....")

    def instance_method(self):
        print("instance method ...")

    ''' python3.x能夠調用下面的函數,能夠說是靜態方法,但嚴格意義上是屬於類的一個行爲方法,可是python2.x沒法該方法 '''
    def fn():
        print("just a fn,if py3.x,it is static method")

## 總結:
1)在類中定義方法必定要規範化,明確是靜態方法仍是類方法抑或是實例方法
2)避免使用最後一種方式在類中定義方法複製代碼

3.命名空間與做用域對象

  • 命名空間:用於記錄變量的軌跡,key是變量名稱,value是變量值,做用就是根據變量名稱搜索變量
    • 使用無點號運算的變量名稱(X),將根據LEGB(local/enclosing/global/builtin)做用域查找法則來搜索變量
    • 使用點號的屬性名稱(object.x)使用的是對象命名空間來搜索變量(對象:類的實例對象和類對象)
    • 有些做用域會對對象的命名空間進行初始化(模塊和類)

無點號運算的變量名稱

  • 賦值語句:在當前做用域建立或更改變量X,除非聲明爲全局變量
X = "global X"
def enclosing_fn():
    ## global X 
    X = "enclosing fn"      ## 建立當前enclosing_fn的本地變量X若是沒有聲明爲全局變量的話複製代碼
  • 引用:根據LEGB做用域法則來搜索變量
X = "global X"
def enclosing_fn():
    X = "enclosing fn"      ## 若是註釋此行,將打印全局的變量X
    print(X)
    def local_x()
        x = "local x"       ## 若是僅註釋此行,將會打印嵌套的變量X
        print(x)
    local_x()複製代碼

點號的屬性變量名稱

  • 賦值語句:在對應的對象命名空間中建立或修改屬性名稱X,即object.X = value
>>> p = Person()

## 在對象實例的命名空間建立或更改屬性名稱name
p.name = "keithl"       ## 並沒有進行變量名稱的搜索

## 在類的命名空間中建立或更改屬性名稱name
Person.name = "keithl"  ## 並沒有進行變量名稱的搜索複製代碼
  • 引用
    • 基於類的對象引用:會在對象內搜索屬性名稱X,若沒有找到則根據繼承搜索來查找
    • 基於模塊對象的引用:先導入模塊,再從模塊中讀取X
>>> p = Person()
>>> p.name          ## 從對象命名空間開始按照繼承樹來搜索
>>> Person.name     ## 從類的命名空間開始按照繼承樹來搜索複製代碼

命名空間字典

  • 模塊的命名空間是以字典的形式實現的,而且能夠由屬性__dict__來顯示
  • 類和對象能夠當作一個帶有連接的字典,屬性點號就是字典索引運算,屬性繼承就是搜索連接的字典
    • 實例與類經過__class__屬性連接
    • 類與超類經過__bases__屬性連接,能夠經過遞歸往上遍歷超類
  • 均可以經過__dict__查看模塊、類或者對象的屬性信息

類與模塊的關係總結

    • 調用類會建立新的對象
    • 由class來建立類對象
    • 經過調用來使用
    • 屬於模塊的一部分
  • 模塊

    • 是數據和邏輯包
    • 經過py抑或其餘語言來擴展
    • 必須導入才能使用

喜歡能夠關注我我的公衆號,持續更新工程師技術平常

相關文章
相關標籤/搜索