python禪語 42 物件 類 以及從屬關係

2021-10-12 01:22:55 字數 3781 閱讀 3051

# 練習42.物件、類、以及從屬關係

有乙個重要的概念你需要弄明白,那就是「類(class)」和「物件(object)」的區別。問題在於,class 和 object 並沒有真正的不同。它們其實是同樣的東西,只是在不同的時間名字不同罷了。我用禪語來解釋一下吧:

魚和三文魚有什麼區別?

這個問題有沒有讓你有點暈呢?說真的,坐下來想一分鐘。我的意思是說,魚和三文魚是不一樣,不過它們其實也是一樣的是不是?三文魚是魚的一種,所以說沒什麼不同,不過三文魚又有些特別,它和別的種類的魚的確不一樣,比如三文魚和大比目魚就不一樣。所以三文魚和魚既相同又不同。怪了。

這個問題讓人暈的原因是大部分人不會這樣去思考問題,其實每個人都懂這一點,你無須去思考魚和三文魚的區別,因為你知道它們之間的關係。你知道三文魚是魚的一種,而且魚還有別的種類,根本就沒必要去思考這類問題。

讓我們更進一步,假設你有乙隻水桶,裡邊有三條三文魚。假設你的好人卡多到沒地方用,於是你給它們分別取名叫frank, joe,和mary。現在想想這個問題:

mary和三文魚有什麼區別?

這個問題一樣的奇怪,但比起魚和三文魚的問題來還好點。你知道mary是一條三文魚,所以他並沒什麼不同,他只是三文魚的乙個「例項(instance)」。frank和joe一樣也是三文魚的例項。我的意思是說,它們是由三文魚建立出來的,而且代表著和三文魚一樣的屬性。

所以我們的思維方式是(你可能會有點不習慣):魚是乙個「類(class)」,三文魚是乙個「類(class)」,而mary是乙個「物件(object)」。仔細想想,然後我再一點一點慢慢解釋給你。

魚是乙個「類」,表示它不是乙個真正的東西,而是乙個用來描述具有同類屬性的例項的概括性詞彙。 你有鰭?你有鰾?你住在水裡?好吧那你就是一條魚。

後來河蟹養殖專家路過,看到你的水桶,於是告訴你:「小夥子,你這些魚是三文魚。」 並且專家還定義了乙個新的叫做「三文魚」的「類」,而這個「類」又有它特定的屬性。長鼻子?淺紅色的肉?生活在海洋裡?吃起來味道還可以?那你就是一條三文魚。

最後乙個廚師過來了,他跟專家說:「非也非也,你看到的是三文魚,我看到的是mary,而且我要把mary和剁椒配一起做一道小菜。」於是你就有了乙隻叫做mary的三文魚的「例項(instance)」(三文魚也是魚的乙個「例項」),並且你使用了它,這樣它就是乙個「物件(object)」。

這會你應該了解了:mary是三文魚的成員,而三文魚又是魚的成員。這裡的關係式:物件屬於某個類,而某個類又屬於另乙個類。

## 寫成**是什麼樣子

這個概念有點繞,不過實話說,你只要在建立和使用 class 的時候操心一下就可以了。我來給你兩個區分 class 和 object 的小技巧。

首先針對類和物件,你需要學會兩個說法,「is-a(是啥)」和「has-a(有啥)」。「是啥」要用在談論「兩者以類的關係互相關聯」的時候,而「有啥」要用在「兩者無共同點,僅是互為參照」的時候。

接下來,通讀這段**,將每乙個注釋為`##`?? 的位置標明他是「is-a」還是「has-a」的關係,並講明白這個關係是什麼。在**的開始我還舉了幾個例子,所以你只要寫剩下的就可以了。

記住,「是啥」指的是魚和三文魚的關係,而「有啥」指的是三文魚和鰓的關係。

## animal is-a object (yes, sort of confusing) look at the extra credit

class animal(object):

pass

class dog(animal):

def __init__(self, name):

self.name = name

class cat(animal):

def __init__(self, name):

self.name = name

class person(object):

def __init__(self, name):

self.name = name

## person has-a pet of some kind

self.pet = none

class employee(person):

def __init__(self, name, salary):

## ?? hmm what is this strange magic?

super(employee, self).__init__(name)

self.salary = salary

class fish(object):

pass

class salmon(fish):

pass

class halibut(fish):

pass

## rover is-a dog

rover = dog("rover")

satan = cat("satan")

mary = person("mary")

mary.pet = satan

frank = employee("frank", 120000)

frank.pet = rover

flipper = fish()

crouse = salmon()

harry = halibut()

## 關於 class name(object)

記得我曾經強迫讓你使用`class name(object)` 卻沒告訴你為什麼吧,現在你已經知道了「類」和「物件」的區別,我就可以告訴你原因了。如果我早告訴你的話,你可能會暈掉,也學不會這門技術了。

真正的原因是在 python 早期,它對於`class` 的定義在很多方面都是嚴重有問題的。當他們承認這一點的時候已經太遲了,所以逼不得已,他們需要支援這種有問題的 `class`。為了解決已有的問題,他們需要引入一種「新類」,這樣的話「舊類」還能繼續使用,而你也有乙個新的正確的類可以使用了。

這就用到了「類即是物件」的概念。他們決定用小寫的「object」這個詞作為乙個類,讓你在建立新類時從它繼承下來。有點暈了吧?乙個類從另乙個類繼承,而後者雖然是個類,但名字卻叫「object」……不過在定義類的時候,別忘記要從 object 繼承就好了。

的確如此。乙個詞的不同就讓這個概念變得更難理解,讓我不得不現在才講給你。現在你可以試著去理解「乙個是物件的類」這個概念了,如果你感興趣的話。

不過我還是建議你別去理解了,乾脆完全忘記舊格式和新格式類的區別吧,就假設 python 的 class 永遠都要求你加上 (object) 好了,你的腦力要留著思考更重要的問題。

## 附加題

> 1. 研究一下為什麼python新增了這個奇怪的叫做`object`的類,它究竟有什麼含義呢?

> 1. 有沒有辦法把`class`當作`object`使用呢?

> 1. 在習題中為 animals、fish、還有 people 新增一些函式,讓它們做一些事情。看看當函式在 animal 這樣的「基類(base class)」裡和在 dog 裡有什麼區別。

> 1. 找些別人的**,理清裡邊的「是啥」和「有啥」的關係。

> 1. 使用列表和字典建立一些新的一對應多的「has-many」的關係。

> 1. 你認為會有一種「has-many」的關係嗎?閱讀一下關於「多重繼承(multiple inheritance)」的資料,然後盡量避免這種用法。

## 常見問題

### q: 這些注釋符`## ??`是幹什麼的?

> 這些是你需要完成的「填空」,你需要填上 "is-a"或者 "has-a"。再讀一遍本節練習,看看其他的注釋,弄明白我再說什麼。

### q: `self.pet = none`是什麼意思?

> 確保給`self.pet`設定了乙個預設值`none`

### q: `super(employee, self).__init__(name)`實現了什麼?

4 2 物件與類(二) 運算子過載

在c 中,函式過載也稱為函式多型,運算子過載是一種形式的c 多型。運算子過載將過載的概念擴充套件到運算子上,允許賦予c 運算子多種含義。例如 運算子用於位址,將得到儲存在這個位址中的值,但將它用於兩個數字時,得到的將是它們的乘積。此時,c 根據運算元的數目和型別來決定採用哪種操作。c 允許將運算子過...

python筆記11 物件和類

物件 客觀世界中的實體在計算機中的邏輯對映 現實世界中,我們把萬事萬物都叫做 事物 計算機世界中,我們把萬事萬物都叫做 物件 認知新的 事物 思維 對應 物件 它 看起來 聞起來 什麼樣?屬性 它怎麼使用?方法 例子 乙個list a 0,1,2,3,abc a的屬性 看起來什麼樣?有乙個 包在外圍...

2 物件與類

在乙個檔案中,只能有乙個公共類,但是可以有任意數量的非公共類。final修飾的例項,必須在構造物件時初始化 初始化塊 在乙個類的宣告中,可以包含任意多的 塊。只要構造這個類的物件,這些塊就會被執行。class employee public employee public static void m...