1. 程式人生 > >Python 簡明教程 --- 20,Python 類中的屬性與方法

Python 簡明教程 --- 20,Python 類中的屬性與方法

> **微信公眾號:碼農充電站pro** > **個人主頁:** > **與客戶保持良好的關係可以使生產率加倍。** > —— Larry Bernstain **目錄** ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/202006271223363.png?#pic_center) 類中的變數稱為`屬性`,類中的函式稱為`方法`。 類中的屬性分為: - 例項屬性:物件所有,互不干擾 - 類屬性:類所有,所有物件共享 類中的方法分為: - 例項方法:定義中有`self` 引數 - 類方法:定義中有`cls` 引數,使用`@classmethod` 裝飾器 - 靜態方法:定義中即沒有`self` 引數,也沒有`cls` 引數,使用`@staticmethod` 裝飾器 ### 1,例項屬性與類屬性 類的物件,就是類的一個例項。類的`例項屬性`被物件所有,包含在每個物件之中,不同的物件之間,互不干擾。類的`類屬性`被類所有,被包含在類中,是所有的`類物件`共享。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200625103556426.png?#pic_center) 一般情況下,例項屬性會在`__init__` 方法中宣告並初始化,並且使用`self` 來繫結。而類屬性是在類作用域中被宣告,並且不使用`self` 來繫結。 例如下面程式碼中,`country` 為類屬性,`__name` 為例項屬性: ```python #! /usr/bin/env python3 class People: country = 'china' def __init__(self, name): self.__name = name ``` 訪問例項屬性時使用`物件.屬性名`的格式,例項屬性屬於物件各自的,互不影響: ```shell >
>> p1 = People('小明') >>> p2 = People('小美') >>> >>> p1.get_name() '小明' >>> p2.get_name() '小美' ``` 類屬性被所有物件共有,一旦被改變,所有物件獲取到的值都會被改變。訪問類屬性時使用`類名.屬性名`的格式,也可以使用`物件.屬性名`的格式來訪問: ```shell >>> People.country # 用`類名.屬性名`的格式訪問 'CHINA' >>> p1.country # 用`物件.屬性名`的格式訪問 'china' >>> p2.country 'china' >>> >>> People.country = 'CHINA' # 類屬性的值被改變 >
>> p1.country # 每個物件獲取到的值也會被改變 'CHINA' >>> p2.country 'CHINA' ``` 注意,在使用`物件.屬性名`的格式訪問物件時,不要以這種格式對`類屬性`進行賦值,否則結果可能不會像你想象的一樣: ```shell >>> p1 = People('小明') >>> p2 = People('小美') >>> People.country 'china' >>> p1.country 'china' >>> p2.country 'china' >>> p1.country = '中國' # 使用`物件.屬性名`的格式對類物件進行賦值 >>> p1.country # 只有 p1.country 被改變 '中國' >
>> p2.country # p2.country 沒有被改變 'china' >>> People.country # People.country 也沒有被改變 'china' ``` 從上面程式碼中可以看到,在Python 中以`物件.屬性名`格式對`類屬性`進行賦值時,只有`p1.country` 的值被改變了,`p2.country` 和 `People.country` 的值都沒有被改變。 實際上,這種情況下,`類屬性`的值並沒有被改變,而是物件`p1` 中多了一個`country` 例項屬性,此後,`p1.country` 訪問的是`p1` 的例項屬性,`p1.country`對屬性`country`的訪問遮蔽了類中的`country`屬性,而`p2.country` 和 `People.country` 訪問的依然是原來的`類屬性`。 所以,`類名.屬性名`和`物件.屬性名`的格式都可以訪問`類屬性`的值,但儘量避免使用`物件.屬性名`的格式對類屬性的值進行賦值,否則可能會發生混亂。 > **建議:** > > 不管是訪問還是改變`類屬性`的值,都只用`類名.屬性名`的格式 ### 2,例項方法,類方法,靜態方法 Python 類中有三種方法: - 例項方法 - 類方法 - 靜態方法 `例項方法`屬於物件,方法中都有一個`self` 引數(代表物件本身)。例項方法只能由物件呼叫,不能通過類名訪問。例項方法中可以訪問例項屬性和類屬性。 `類方法`屬於類,方法中都有一個`cls` 引數(代表類本身)。類方法即可以通過類名訪問,也可以通過物件訪問,類方法中只能訪問類屬性,不能訪問例項屬性。 > **注意:** > > Python 直譯器在構造類與物件時,`類`是先於`物件`產生的。 > > 因此,`類屬性與類方法`是先於`例項屬性與例項方法` 產生的。 > > 所以當類方法產生時,還沒有例項屬性,因此,類方法中不能訪問例項屬性。 `靜態方法`中,沒有`self` 引數,也沒有`cls` 引數。因此,在靜態方法中,即不能訪問`類屬性`,也不能訪問`例項屬性`。靜態方法可以使用類名訪問,也可以使用物件訪問。 在Python 中,定義類方法需要用到裝飾器`@classmethod`,定義靜態方法需要用到裝飾器`@staticmethod`。 **例項方法演示** ```python #! /usr/bin/env python3 class People: country = 'china' def __init__(self, name): self.__name = name # 例項方法中有self 引數 def instance_method_test(self): # 在例項方法中訪問了例項屬性和類屬性 print('name:%s country:%s' % (self.__name, People.country)) ``` 使用: ```shell >>> p = People('小明') >>> p.instance_method_test() name:小明 country:china ``` 在例項方法中訪問了例項屬性`__name`和類屬性`country`,均可以被訪問。 **類方法演示** ```python #! /usr/bin/env python3 class People: country = 'china' def __init__(self, name): self.__name = name # 類方法中都有cls 引數 @classmethod def class_method_test1(cls): print('在類方法中訪問類屬性country:%s' % cls.country) @classmethod def class_method_test2(cls): print('在類方法中訪問例項屬性__name:%s' % self.__name) ``` 使用: ```shell >>> p = People('小明') >>> p.class_method_test1() # 在類方法中訪問類屬性,可以 在類方法中訪問類屬性country:china >>> >>> p.class_method_test2() # 在類方法中訪問例項屬性,出現異常 Traceback (most recent call last): File "", line 1, in File "/home/wp/to_beijing/People.py", line 18, in class_method_test2 print('在類方法中訪問例項屬性__name:%s' % self.__name) NameError: name 'self' is not defined ``` 從上面程式碼中可以看到,在類方法中可以訪問類屬性,但在類方法中訪問例項屬性,會出現異常。 **靜態方法演示** ```python #! /usr/bin/env python3 class People: country = 'china' def __init__(self, name): self.__name = name # 靜態方法中即沒有self 引數也不沒有cls 引數 @staticmethod def static_method_test1(): print('在靜態方法中訪問類屬性country:%s' % cls.country) @staticmethod def static_method_test2(): print('在靜態方法中訪問例項屬性__name:%s' % self.__name) ``` 使用: ```shell >>> p = People('小明') >>> p.static_method_test1() # 在靜態方法中訪問類屬性,出現異常 Traceback (most recent call last): File "", line 1, in File "/home/wp/to_beijing/People.py", line 14, in static_method_test1 print('在靜態方法中訪問類屬性country:%s' % cls.country) NameError: name 'cls' is not defined >>> >>> p.static_method_test2() # 在靜態方法中訪問例項屬性,出現異常 Traceback (most recent call last): File "", line 1, in File "/home/wp/to_beijing/People.py", line 18, in static_method_test2 print('在靜態方法中訪問例項屬性__name:%s' % self.__name) NameError: name 'self' is not defined ``` 從上面程式碼中可以看到,在靜態方法中無論訪問例項方法還是類方法,都會出現異常。 ### 3,專有方法 我們之前講到過的`魔法方法`,即以雙下劃線`__`開頭且結尾的方法`__xxx__`,就是`專有方法`。這些方法都被Python 賦予了特殊的含義,使用者可以根據需要,來實現這些方法。 下面我們介紹一些 Python 中常見的專有方法。 **`__len__` 方法** 實現該方法的類的物件,可以用`len()` 函式計算其長度。 **`__str__` 方法** 實現該方法的類的物件,可以轉化為字串。 **`__call__` 方法** 實現該方法的類的物件,可以像函式一樣呼叫。 **`__iter__` 方法** 實現該方法的類的物件,是可迭代的。 **`__setitem__ ` 方法** 實現該方法的類的物件,可以用`索引`的方式進行賦值。 **`__getitem__` 方法** 實現該方法的類的物件,可以用`索引`的方式進行訪問。 **`__contains__` 方法** 實現該方法的類的物件,可以進行`in` 運算。 --- **`__add__` 方法** 實現該方法的類的物件,可以進行`加+`運算。 **`__sub__` 方法** 實現該方法的類的物件,可以進行`減-`運算。 **`__mul__` 方法** 實現該方法的類的物件,可以進行`乘*`運算。 **`__div__` 方法** 實現該方法的類的物件,可以進行`除/`運算。 **`__pow__` 方法** 實現該方法的類的物件,可以進行`乘方`運算。 **`__mod__` 方法** 實現該方法的類的物件,可以進行`取模`運算。 --- **`__eq__` 方法** 實現該方法的類的物件,可以進行`相等==`比較。 **`__ne__` 方法** 實現該方法的類的物件,可以進行`不等於!=`比較。 **`__gt__` 方法** 實現該方法的類的物件,可以進行`大於>`比較。 **`__ge__` 方法** 實現該方法的類的物件,可以進行`大於等於>=`比較。 **`__lt__` 方法** 實現該方法的類的物件,可以進行`小於<`比較。 **`__le__` 方法** 實現該方法的類的物件,可以進行`小於等於<=`比較。 (完。) --- **推薦閱讀:** [Python 簡明教程 --- 15,Python 函式](https://www.cnblogs.com/codeshell/p/13040458.html) [Python 簡明教程 --- 16,Python 高階函式](https://www.cnblogs.com/codeshell/p/13158903.html) [Python 簡明教程 --- 17,Python 模組與包](https://www.cnblogs.com/codeshell/p/13158924.html) [Python 簡明教程 --- 18,Python 面向物件](https://www.cnblogs.com/codeshell/p/13193851.html) [Python 簡明教程 --- 19,Python 類與物件](https://www.cnblogs.com/codeshell/p/13193866.html) --- 歡迎關注作者公眾號,獲取更多技術乾貨。 ![碼農充電站pro](https://img-blog.csdnimg.cn/20200505082843773.png?#pic