我的Python學習筆記(四):動態添加屬性和方法


一、動態語言相關概念

1.1 動態語言

  • 在運行時代碼可以根據某些條件改變自身結構
  • 可以在運行時引進新的函數、對象、甚至代碼,可以刪除已有的函數等其他結構上的變化
  • 常見的動態語言:Object-C、C#、JavaScript、PHP、Python、Erlang

1.2 動態類型語言

  • 在運行期間檢查數據類型的語言
  • 數據類型不是在編譯階段決定的,而是把類型綁定延后到了運行階段
  • 常見的動態類型語言:Python、Ruby、Erlang、JavaScript、swift、PHP、Perl

1.3 強類型語言

  • 一旦一個變量被指定了某個數據類型,如果不經過強制類型轉換,那么它就永遠是這個數據類型
  • 常見的強類型語言:Java、C#、Python、Object-C、Ruby

Python是動態語言,動態類型語言,也是強類型語言。所以Python可以在運行時改變自身結構,動態添加/刪除屬性和方法。接下來將介紹Python如何動態添加屬性和方法。

 

二、動態添加屬性

2.1 添加對象屬性

class Person(object):
    def __init__(self, newName, newAge):
        self.name = newName
        self.age = newAge

zhangsan = Person("張三", 18)
zhangsan.addr = "北京"    # 類對象zhangsan動態添加對象屬性addr
print(zhangsan.name)    # 張三
print(zhangsan.age)     # 18
print(zhangsan.addr)    # 北京

lisi = Person("李四", 28)
print(lisi.name)        # 李四
print(lisi.age)         # 28
print(lisi.addr)        # 'Person' object has no attribute 'addr'

由以上代碼可知,Person類有兩個屬性:name和age。通過[對象名.屬性名]給類對象zhangsan動態添加了對象屬性addr,而Person的另一個類對象lisi卻不能調用這個屬性。

注:通過對象名添加的對象屬性,只有這個對象能使用

2.2 添加類屬性

class Person(object):
    def __init__(self, newName, newAge):
        self.name = newName
        self.age = newAge

Person.addr = "北京"  # 類Person動態添加類屬性addr

zhangsan = Person("張三", 18)
print(zhangsan.name)    # 張三
print(zhangsan.age)     # 18
print(zhangsan.addr)    # 北京

lisi = Person("李四", 28)
print(lisi.name)    # 李四
print(lisi.age)     # 28
print(lisi.addr)    # 北京

由以上代碼可知,通過[類名.屬性名]給類Person動態添加了類屬性addr,Person的類對象zhangsan和lisi都能調用這個屬性

注:通過類名添加的類屬性,這個類的所有對象都能使用

 

三、動態添加方法

類中有三種方法,實例方法,靜態方法和類方法,三種方法的區別如下:

  • 實例方法:需要綁定要一個對象上,第一個參數默認使用self,會把對象作為第一個參數傳遞進來
  • 靜態方法:使用裝飾器@staticmethod進行定義,類和對象都可以調用,不需要默認參數
  • 類方法:使用裝飾器@classmethod進行定義,類和對象都可以調用,第一個參數默認使用cls,會把類作為第一個參數傳遞進來

3.1 添加實例方法

import types

class Person(object):
    def __init__(self, newName, newAge):
        self.name = newName
        self.age = newAge

    def eat(self):
        print("---正在吃---")

def run(self):
    print("---正在跑---")

zhangsan = Person("張三", 18)
zhangsan.eat()  # ---正在吃---
zhangsan.run = types.MethodType(run, zhangsan)  # 類對象zhangsan動態添加對象方法run()
zhangsan.run()  # ---正在跑---

lisi = Person("李四", 28)
lisi.eat()  # ---正在吃---
lisi.run()  # 'Person' object has no attribute 'run'

由以上代碼可知,Person類有一個方法:eat()方法。通過[types.MethodType(方法名, 對象名)]給類對象zhangsan動態添加了對象方法run(),同理,Person的另一個類對象lisi不能調用這個方法

注:通過對象名添加的對象方法,只有這個對象能使用

3.2 添加靜態方法

class Person(object):
    def __init__(self, newName, newAge):
        self.name = newName
        self.age = newAge

    def eat(self):
        print("---正在吃---")

@staticmethod
def staticRun():
    print("---正在跑---")

Person.staticRun = staticRun    # 類Person動態添加靜態方法staticRun()

Person.staticRun()  # ---正在跑---

zhangsan = Person("張三", 18)
zhangsan.eat()        # ---正在吃---
zhangsan.staticRun()  # ---正在跑---

lisi = Person("李四", 28)
lisi.eat()        # ---正在吃---
lisi.staticRun()  # ---正在跑---

由以上代碼可知,通過[類名.靜態方法名]給類Person動態添加了靜態方法staticRun(),Person類的Person的類對象zhangsan和lisi都能調用這個方法

注:通過類名添加的靜態方法,這個類及這個類的所有對象都能使用

3.3 添加類方法

class Person(object):
    def __init__(self, newName, newAge):
        self.name = newName
        self.age = newAge

    def eat(self):
        print("---正在吃---")

@classmethod
def classRun(cls):
    print("---正在跑---")

Person.classRun = classRun    # 類Person動態添加類方法classRun()

Person.classRun()  # ---正在跑---

zhangsan = Person("張三", 18)
zhangsan.eat()        # ---正在吃---
zhangsan.classRun()  # ---正在跑---

lisi = Person("李四", 28)
lisi.eat()        # ---正在吃---
lisi.classRun()  # ---正在跑---

由以上代碼可知,通過[類名.類方法名]給類Person動態添加了類方法classRun(),Person類的Person的類對象zhangsan和lisi都能調用這個方法

注:通過類名添加的類方法,這個類及這個類的所有對象都能使用

 

四、__slots__的使用

通過以上內容,我們知道了如何動態的添加屬性和方法。但是,如果我們想要限制class的屬性該怎么辦?例如:只允許Person實例添加name和age屬性。為了達到這個目的,Python允許在定義class的時候,定義一個特殊變量__slots__來限制該class能添加的屬性。

import types
class Person(object):
    __slots__ = ("name", "age")  # 定義__slots__    
    def __init__(self, newName, newAge):
        self.name = newName
        self.age = newAge

    def eat(self):
        print("---正在吃---")

def run(self):
    print("---正在跑---")

Person.num = 100        # 類Person動態添加類屬性num

zhangsan = Person("張三", 18)
print(zhangsan.name)    # 張三
print(zhangsan.age)     # 18
print(zhangsan.num)     # 100
zhangsan.eat()          # ---正在吃---

zhangsan.addr = "北京"   # 'Person' object has no attribute 'addr'
zhangsan.run = types.MethodType(run, zhangsan)  # 'Person' object has no attribute 'run'

通過以上代碼可知,__slots__對Person類的動態添加沒有限制,而Person類對象zhangsan不能再動態添加對象屬性和方法。

對於__slot__有以下幾個需要注意的地方:

  • __slots__只對類對象進行限制,不對類進行限制
  • __slots__不僅限制類對象的屬性,還限制類對象的方法
  • __slots__僅對當前類起作用,對繼承的子類不起作用
  • 在子類中定義__slots__,子類允許定義的屬性就是自身的__slots__加上父類的__slots__

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM