類的兩個裝飾器classmethod、staticethod和內建魔術方法

先生發表於2021-05-14

一、兩個裝飾器@classmethod、@staticmethod

@classmethod:把類中的繫結方法變成一個類方法,cls 就等於類名

有什麼用?

1、在方法中任然可以引用類中的靜態變數

2、可以不用例項化物件,就直接用類名在外部呼叫這個方法

什麼時候用?

1、定義了一個方法,預設傳 self ,但這個 self 沒有被使用。

2、並且你在這個方法裡用到了當前類名,或者你準備使用這個類的記憶體空間中的名字的時候

# 商品打折:
class Goods:
    __discount = 0.8def __init__(self, original_price):
        self.original_price = original_price
        self.price = self.original_price * self.__discount
​
    @classmethod        # 把一個物件的繫結方法改成一個類方法
    def change_discount(cls, count):
        cls.__discount = count  # 相當於Goods.__discount = count
​
​
Goods.change_discount(0.6)      # 類方法可以通過類名呼叫
# 例項化一個華為手機物件
huawei = Goods(20)
print(int(huawei.price))
​
huawei.change_discount(0.4)     # 類方法可以通過物件呼叫
# 例項化一個蘋果手機物件
apple = Goods(20)
print(int(apple.price))
​
# 輸出
12
8

擴充套件:

在掉用類的函式的時候就例項化了一個物件

import time
​
class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
​
    @classmethod
    def today(cls):
        structure = time.localtime()
        # 在方法中建立一個物件
        obj = cls(structure.tm_year, structure.tm_mon, structure.tm_mday)
        return obj
​
​
# 當呼叫類中的today方法就會返回一個物件(物件屬性不用自己填,today方法已經填好了)
data物件 = Date.today()
print(data物件.year)
print(data物件.month)
print(data物件.day)
​
# 輸出
2021
5
4

@staticmethod:被裝飾的方法會成為一個靜態方法

本身是一個普通函式,被挪到類的內部執行,那麼直接給這個函式新增 @staticmethod 裝飾器就可以了

在函式的內部即用不到 self 變數,也用不到 cls 類

class User:
    pass
​
    @staticmethod
    def login(user):
        print(f'{user},登入成功')
​
User.login('Alen')   # 類可以調傭
Bob = User()
Bob.login('Bob')     # 物件可以調傭
# 輸出
Alen,登入成功
Bob,登入成功

總結:能定義到類中的內容。

1、靜態變數:是個所有的物件共享的變數 ——由物件、類呼叫

2、例項變數:是物件的屬性變數 ——由物件呼叫

3、繫結方法:是個自帶self引數的函式 ——由物件呼叫

4、類方法:是個自帶cls引數的函式 ——由物件、類呼叫

5、property屬性:是個偽裝屬性的方法 ——由物件呼叫,但不加括號

二、內建魔術方法

__call__方法:物件 + ( ) 呼叫這個類中的__call__方法

class User:
    pass
​
    @staticmethod
    def login(user):
        print(f'{user},登入成功')
​
User.login('Alen')   # 類可以調傭
Bob = User()
Bob.login('Bob')     # 物件可以調傭
# 輸出
Alen,登入成功
Bob,登入成功

__len__方法:len (物件) 需要實現這個類中的__len__方法

class A:
    def __init__(self):
        self.lis = [1, 2, 3, 4, 5]
​
    def len(self):
        return len(self.lis)
​
    def __len__(self):
        return len(self.lis)
​
​
a = A()
print(len(a))       # 可以直接len(a)就可以檢視lis裡面值的個數
print(a.len())      # 不然就要使用類中的len方法才可以檢視
# 輸出
5
5# -------------------------------------------------------------------------------------
# 擴充套件:也可以使用自定義的函式
class A:
    def __init__(self, count):
        self.count = count
​
    def __square__(self):
        value = self.count ** 2
        return value
​
def square(count):
    return A.__square__(count)
​
a = A(5)
​
print(square(a))
​
# 輸出
25

__new__方法:例項化的時候會先執行__new__方法用來建立一個物件需要的空間

class A:
    def __new__(cls, *args, **kwargs):
        o = super().__new__(cls)
        print(o)                    # 記憶體地址和 self 的記憶體地址一樣
        print('執行了__new__方法')
        return o
​
    def __init__(self):
        print(self)
        print('執行了__init__方法')
​
A()     # 例項化物件
# 輸出
<__main__.A object at 0x014E0970>
執行了__new__方法
<__main__.A object at 0x014E0970>
執行了__init__方法

__new__方法的設計模式:————>單例模式

一個類,從頭到尾,只會建立一次 self 的空間

例如:我有一輛車(有且只有一輛),小紅要拿去用,我就給她了,她拿去隨便怎麼改裝,換個紅色車漆,換藍色車輪都可以。但是小明又過來找我要用車,那我就去把我的車給拿回來在給小明,也隨小明隨便改裝。

class Car:
    __attribute = None
​
    def __new__(cls, *args, **kwargs):
        if cls.__attribute is None:         # 當第一次開空間的時候__attribute肯定是空的
            # 所以就會開一個新的空間。並把__attribute給賦值,那麼以後的都不是第一次了。
            cls.__attribute = super().__new__(cls)  
        return cls.__attribute                      # 把新空間返回給self
def __init__(self, car_paint, cartwheel_colour):
        self.car_paint = car_paint
        self.cartwheel_colour = cartwheel_colour
​
​
xiao_hong = Car('紅色的車漆', '藍色的車輪')
print('小紅的記憶體地址:', xiao_hong)    # 他們的記憶體地址都是一樣的
print(xiao_hong.car_paint)          # 紅色的車漆————>小紅剛拿到的時候還是紅色的
xiao_ming = Car('白色的車漆', '黑色的車輪')
print('小名的記憶體地址:', xiao_ming)
print(xiao_hong.car_paint)          # 白色的車漆————>小明在拿過來,把顏色給改成白的了
print(xiao_ming.car_paint)          # 白色的車漆————>小紅的也變了,應為他們都是同一個車
# 輸出
小紅的記憶體地址: <__main__.Car object at 0x01A70A60>
紅色的車漆
小名的記憶體地址: <__main__.Car object at 0x01A70A60>
白色的車漆
白色的車漆

__str____repr__方法:

str方法:幫助我們在列印或展示物件的時候更加直觀的顯示物件內容

1、在列印一個物件的時候,呼叫__str__方法

2、在 %s 拼接一個物件的時候,呼叫__str__方法

3、在str一個物件的時候,呼叫__str__方法

當列印一個物件的時候,希望這個物件顯示的值是什麼,那麼你就必須在這個物件內部實現一個__str__ ,這樣的話你就能做到,你在列印這個物件的時候你就能檢視到他的內容是多少(檢視的內容由你自己在 str 中定義),不然就只能答應一堆記憶體地址。

repr方法:是 str 的備胎(有str的時候列印str,沒有就列印rper),同時 %r 和 repr 有合作關係

class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age
​
    def __str__(self):
        return self.name
​
    def __repr__(self):
        return self.age
​
​
Bob = User('鮑勃', '18')
​
print(Bob)  # 現在就可以直接列印物件了,——不設定str方法,列印的就是是一堆記憶體地址,優先列印 str 方法
print('我的名字是%s' % Bob)  # 在 %s 拼接一個物件的時候,呼叫__str__方法
print('我的年齡是%r' % Bob)  # 在 %r 拼接一個物件的時候,呼叫__repr__方法
# 輸出
鮑勃
我的名字是鮑勃
我的年齡是18

相關文章