溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Ruby與Python的對象系統(tǒng)有什么區(qū)別

發(fā)布時(shí)間:2021-11-26 11:33:25 來源:億速云 閱讀:124 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“Ruby與Python的對象系統(tǒng)有什么區(qū)別”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Ruby與Python的對象系統(tǒng)有什么區(qū)別”吧!

屬性

屬性的嚴(yán)格定義不知道去哪里找, 這里暫且用來指對象實(shí)例用來儲存自身狀態(tài)的方式好了。 用途自然是儲存對象的協(xié)作者與數(shù)據(jù)等。 或者干脆說成是: per-instance 的東西都叫屬性1

內(nèi)部訪問

一般來說, 對象的內(nèi)部狀態(tài)輕易不向外暴露, 讀寫操作主要由對象的方法完成。 這種自己默默修改自身屬性的存取方式我們暫時(shí)稱作內(nèi)部訪問。

Ruby 中為每個(gè)對象提供了單獨(dú)的命名空間來存放屬性, 語法上 @foo 是讀取,@foo = 'bar' 是寫入。 而且讀寫語義無法通過元編程來干擾。 也不與常量查找、方法調(diào)用、局部變量存取等尋址方式相沖突。

在 Python 中這種命名空間似乎也是存在的, 而且乍一看可以通過 __dict__字典來訪問2。 但由于打字太多, 實(shí)際恐怕很少有人積極使用, 更多地還是直接用外部訪問的方法。 往下看。

外部訪問

Ruby 默認(rèn)禁止外部直接訪問對象屬性3, 需要我們顯式地在類定義中使用attr系列方法 來顯式定義供外部使用的存取方法。

Python 這邊就容易得多, 自定義的 New Style Class 默認(rèn)有 __dict__ 屬性4, 讀寫全開, 可以直接用 foo.bar,foo.bar = 'baz' 語法存取, 內(nèi)部存取時(shí)多半也用這種語法。

這里我不想談及定義了 __slots__ 的情況, 因?yàn)榭次臋n里面一長串需要當(dāng)心的 notes 可以猜測沒什么人愿意用。 稍微 Google 一下的結(jié)果也基本證實(shí)如此。

元編程:自定義 getter/setter

兩種語言都支持在語法上依然寫出常規(guī)的屬性取值/賦值, 而背后執(zhí)行任意的代碼。 常用的場景包括延遲求值, 計(jì)算屬性(Calculated Attribute), 只讀屬性等。

在 Ruby 里由于語法糖實(shí)在太甜, 調(diào)用方法時(shí)可以省略掉括號, 能夠不傳參數(shù)調(diào)用的方法就是 getter, 寫起來像 foo.bar。 以 = 結(jié)尾的一元方法就是 setter, 通過 foo.bar = 'baz' 就會調(diào)用到。 前面提到的 attr 系列方法 也只是按照這個(gè)接口來定義方法, 并非特殊的語言關(guān)鍵字。

至于 Python, 只需 getter 時(shí)還好說, 直接用 @property 裝飾器就好。 但需要允許外部只讀訪問屬性時(shí)就有些麻煩。 讀寫控制要由 property descriptor 來實(shí)現(xiàn), 為了自定義一個(gè)只讀 descriptor 寫起來像這樣:

EDIT: 明顯下面的代碼是不對的, 當(dāng)時(shí)我在想什么。 還好真實(shí)世界中一般都用下劃線方案而不是用這種方案來滿足語義純化論者。

class Foo(object):
    bar = property()
    @bar.setter
    def bar(self, value):
        raise AttributeErrorFoo().bar = 'shit' # => 拋 AttributeError 異常

這樣在內(nèi)部訪問中要寫入屬性時(shí)就要被迫改用這種傷鍵盤的寫法:self.__dict__['bar'] = 'blah'。 所以現(xiàn)實(shí)生活中人們往往用下劃線開頭表達(dá)私有屬性, 然后定義一個(gè)去掉開頭下劃線的 getter 來提供只讀訪問了事。

+1 for Ruby

到這里已經(jīng)可以總結(jié)出我偏好 Ruby 的一點(diǎn)原因:

對屬性的內(nèi)部與外部存取做出明確區(qū)分, 默認(rèn)不提供外部直接存取。 且兩種存取方式的語法都不難寫。 鼓勵(lì)開發(fā)者在設(shè)計(jì)時(shí)考慮好封裝問題。 而 Python 慣用的方式是下劃線標(biāo)識私有屬性, 難免會增加代碼量。

接下來如果再寫下去要一并引入很多對象模型的重點(diǎn)問題, 恐怕就要被標(biāo)記 TL;DR 了。 所以先到這吧。

  1. 未來談及方法解析的時(shí)候會引入 per-instance 的方法定義, 從而毀掉這個(gè)不嚴(yán)格的描述。

  2. 但是你沒法通過自定義 __dict__ 返回值來擾亂屬性專有字典。  是的, 在這兩種語言元編程的能力下, 可以做出很多出格的事情來。 本文只能在假設(shè)開發(fā)者不會積極地亂來的基調(diào)下展開討論。

  3. 當(dāng)然你可以用 instance_variable_{get,set,s} 等方法來訪問。 避而不談的理由見另一個(gè)腳注。

  4. object 類自己卻沒有定義 __dict__, 其實(shí)例也沒有。 所以盡管這樣一個(gè)空的 New Style Class class Foo(object): pass 是 object 的直接子類, 兩個(gè)類的實(shí)例的行為卻大不相同。

到此,相信大家對“Ruby與Python的對象系統(tǒng)有什么區(qū)別”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI