Python 簡明教程 --- 19,Python 類與對象

微信公衆號:碼農充電站pro
我的主頁:https://codeshellme.github.iohtml

那些能用計算機迅速解決的問題,就別用手作了。
—— Tom Duffpython

目錄
在這裏插入圖片描述git

上一節 咱們介紹了Python 面向對象的相關概念,咱們已經知道類與對象面向對象編程中很是重要的概念。github

類就是一個模板,是抽象的。對象是由類建立出來的實例,是具體的。由同一個類建立出來的對象擁有相同的方法屬性,但屬性的值能夠是不一樣的。不一樣的對象是不一樣的實例,互不干擾。shell

1,類的定義

以下,是一個最簡單的類,其實是一個空類,不能作任何事情:編程

class People:
    pass

在Python 中定義一個類,須要用到class 關鍵字,後邊是類名,而後是一個冒號:,而後下一行是類中的代碼,注意要有縮進微信

2,建立對象

People 雖然是一個空類,但依然能夠建立對象,建立一個對象的語法爲:數據結構

對象名 = 類名(參數列表)

參數列表是跟__init__ 構造方法相匹配的,若是沒有編寫__init__ 方法,建立對象時,就不須要寫參數,以下:函數

>>> p = People()
>>> p
<__main__.People object at 0x7fd30e60be80>
>>> 
>>> p1 = People()
>>> p1
<__main__.People object at 0x7fd30e60be48>

pp1 都是People類的對象。0x7fd30e60be80p 的地址,0x7fd30e60be48p1 的地址。能夠看到不一樣的對象的地址是不一樣的,它們是兩不一樣的實例,互不干擾。this

3,屬性

類中能夠包含屬性類中的變量),建立出來的對象就會擁有相應的屬性,每一個對象的屬性的值能夠不一樣。

建立好對象後,能夠用以下方法給對象添加屬性:

>>> p = People()
>>> p.name = '小明' # 添加 name 屬性
>>> p.sex = '男'    # 添加 sex 屬性
>>> p.name         # 訪問對象的屬性
'小明'
>>> p.sex          # 訪問對象的屬性
'男'

雖然在技術上能夠這樣作,可是通常狀況下,咱們並不這樣爲對象添加屬性,這樣會破壞類的封裝性,使得代碼混亂,不利於維護。

當訪問一個不存在的屬性時,會出現異常:

>>> p.job         # 一個不存在的屬性
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'People' object has no attribute 'job'

咱們通常會在__init__ 方法中爲類添加屬性並賦值。

4,__init__ 方法

在Python 的類中,以雙下劃線__開頭和結尾的方法,被稱爲魔法方法,每一個魔法方法都有特定的含義。Python 爲咱們規定了一些魔法方法,讓咱們本身實現這些方法。

__init__ 方法叫作構造方法,用來初始化對象。Python 解釋器會在生成對象時,自動執行構造方法,而無需用戶顯示調用。

__init__ 方法不須要有返回值。

類中的全部實例方法 方法,都至少有一個參數,就是self。Python 中的self 至關於C++ 和Java 中的this 指針,都是表明當前對象。只是Python 中的self 須要顯示寫在方法的第一個參數,而this 指針則不須要寫在方法參數中。

構造方法通常用於初始化對象的一些屬性,構造函數能夠不寫,也能夠只有一個self 參數。

當構造函數只有一個self 參數時,建立該類的對象時,不須要添加參數。當構造函數除了self 參數還有其它參數時,建立該類的對象時,則須要添加相匹配的參數。

好比,咱們定義一個People 類,它有三個屬性,分別是namesexage

class People:

    def __init__(self, name, sex, age):
        self.name = name
        self.sex = sex
        self.age = age
        print('執行了 __init__ 方法')

    def print_info(self):
        print('people:%s sex:%s age:%s' % (
            self.name, self.sex, self.age))

在這個People 類中除了有一個__init__ 方法外,還有一個print_info 方法,每一個方法中的都有self 參數,而且是第一個參數,self 表明當前對象。

在建立該類的對象時,須要傳遞匹配的參數(self 參數不用傳遞):

>>> p = People('小明', '男', 18)
執行了 __init__ 方法
>>> p 
<People.People object at 0x7feb6276bda0>
>>> p.print_info()
people:小明 sex:男 age:18
>>>
>>> p1 = People('小美', '女', 18)
執行了 __init__ 方法
>>> p1
<People.People object at 0x7fd54352be48>
>>> p1.print_info()
people:小美 sex:女 age:18

能夠看到,在建立pp1 對象時,字符串執行了 __init__ 方法 被打印了出來,而咱們並無顯示調用該方法,說明__init__ 方法被默認執行了。

對象pp1 是兩個不一樣的對象,擁有相同的屬性和方法,可是屬性值是不同的。兩個對象互不干擾,對象p 的地址爲0x7feb6276bda0p1 的地址是0x7fd54352be48

執行代碼p.print_info(),是調用p 對象的print_info() 方法,由於,在定義該方法的時候,只有一個self 參數,因此在調用該方法的時候,不須要有參數。

5,私有屬性和方法

私有屬性

普通的屬性,就像上面的namesexage 屬性,都是公有屬性,在類的外部均可以被任意的訪問,就是能夠用對象.屬性名的方式來訪問屬性,以下:

>>> p = People('小明', '男', 18)
執行了 __init__ 方法
>>> p.name  # 訪問屬性
'小明'
>>> p.name = '小麗'  # 修改屬性
>>> p.name  # 訪問屬性
'小麗'

這樣就破壞了數據的封裝性,這種訪問方式是不可控(會不受限制的被任意訪問)的,不利於代碼的維護,不符合面向對象的編程規範。

因此,一般咱們會將類中的屬性,改成私有屬性,就是不能以對象.屬性名 這樣的方式訪問類屬性。

在Python 中,經過在屬性名的前邊添加雙下劃線__,來將公有屬性變爲私有屬性,以下:

#! /usr/bin/env python3

class People:

    def __init__(self, name, sex, age):
        self.__name = name   # 兩個下劃線
        self.__sex = sex     # 兩個下劃線
        self._age = age      # 一個下劃線
        print('執行了 __init__ 方法')

    def print_info(self):
        print('people:%s sex:%s age:%s' % (
            self.__name, self.__sex, self._age))

這樣就沒法經過對象.屬性名的方式來訪問屬性了,以下:

>>> p = People('小美', '女', 18)
執行了 __init__ 方法
>>> p.__name        # 出現異常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'People' object has no attribute '__name'

可是,Python 中這種私有屬性的方式,並非真正的私有屬性,Python 只是將__name 轉換爲了_People__name,便是在__name 的前邊加上了_類名(_People),咱們依然能夠這樣訪問__name 屬性:

>>> p._People__name
'小美'

但咱們並不提倡這種方式,這會讓代碼變得混亂難懂。

能夠注意到,People 類中的_age 屬性是以單下劃線開頭的,這種以單下劃線開頭的屬性是能夠在類的外部被訪問的:

>>> p._age
18

可是根據Python 規範,以單下劃線開頭的屬性,也被認爲是私有屬性,也不該該在類的外部訪問(雖然在技術上是能夠訪問的)。

注意:以雙下劃線__ 開頭且結尾的屬性__xxx__,是特殊屬性,是公有的,可在類的外部訪問

私有方法

私有方法與私有屬性相似,也能夠在方法名的前邊加上雙下劃線__,來將某個方法變成私有的,通常不須要被外部訪問的方法,應該將其設置爲私有方法

6,setget 方法

爲了數據的封裝性,咱們不該該直接在類的外部以對象.屬性名的方式訪問屬性,那麼若是咱們須要訪問類的屬性該怎麼辦呢?

這時咱們須要爲每一個私有屬性都提供兩個方法:

  • set 方法:用於設置屬性的值
  • get 方法:用於訪問屬性的值

爲了減小代碼量,這裏只爲__name 屬性設置了這兩個方法,代碼以下:

#! /usr/bin/env python3

class People:

    def __init__(self, name, sex, age):
        self.__name = name
        self.__sex = sex
        self._age = age
        print('執行了 __init__ 方法')

    def print_info(self):
        print('people:%s sex:%s age:%s' % (
            self.__name, self.__sex, self._age))

    # set 和 get 方法
    def set_name(self, name):
        self.__name = name

    def get_name(self):
        return self.__name

用戶能夠這樣設置和訪問類的屬性:

>>> from People import People
>>> p = People('小美', '女', 18)
執行了 __init__ 方法
>>> p.get_name()         # 獲取 name 值
'小美'
>>> p.set_name('小麗')   # 設置新的值
>>> p.get_name()        # 再次獲取name 值
'小麗'

由於這種setget 方法,是由類的開發者提供的,是被開發者控制的。

類的開發者會根據須要,來控制類的使用者如何使用該類,即哪些類的屬性和方法應該被使用者訪問,以及如何被使用者訪問。

如此,類的使用者就不能隨便的訪問類中的屬性,這就達到了封裝的目的。

(完。)


推薦閱讀:

Python 簡明教程 --- 14,Python 數據結構進階

Python 簡明教程 --- 15,Python 函數

Python 簡明教程 --- 16,Python 高階函數

Python 簡明教程 --- 17,Python 模塊與包

Python 簡明教程 --- 18,Python 面向對象


歡迎關注做者公衆號,獲取更多技術乾貨。

碼農充電站pro

相關文章
相關標籤/搜索