摘要:以這種方式實(shí)現(xiàn)對(duì)象系統(tǒng)的目的是展示使用對(duì)象隱喻并不需要特殊的編程語言。我們的實(shí)現(xiàn)并不遵循類型系統(tǒng)的明確規(guī)定。反之,它為實(shí)現(xiàn)對(duì)象隱喻的核心功能而設(shè)計(jì)。是分發(fā)字典,它響應(yīng)消息和。
2.6 實(shí)現(xiàn)類和對(duì)象
來源:2.6 Implementing Classes and Objects
譯者:飛龍
協(xié)議:CC BY-NC-SA 4.0
在使用面向?qū)ο缶幊谭妒綍r(shí),我們使用對(duì)象隱喻來指導(dǎo)程序的組織。數(shù)據(jù)表示和操作的大部分邏輯都表達(dá)在類的定義中。在這一節(jié)中,我們會(huì)看到,類和對(duì)象本身可以使用函數(shù)和字典來表示。以這種方式實(shí)現(xiàn)對(duì)象系統(tǒng)的目的是展示使用對(duì)象隱喻并不需要特殊的編程語言。即使編程語言沒有面向?qū)ο笙到y(tǒng),程序照樣可以面向?qū)ο蟆?/p>
為了實(shí)現(xiàn)對(duì)象,我們需要拋棄點(diǎn)運(yùn)算符(它需要語言的內(nèi)建支持),并創(chuàng)建分發(fā)字典,它的行為和內(nèi)建對(duì)象系統(tǒng)的元素差不多。我們已經(jīng)看到如何通過分發(fā)字典實(shí)現(xiàn)消息傳遞行為。為了完整實(shí)現(xiàn)對(duì)象系統(tǒng),我們需要在實(shí)例、類和基類之間發(fā)送消息,它們?nèi)慷际呛袑傩缘淖值洹?/p>
我們不會(huì)實(shí)現(xiàn)整個(gè) Python 對(duì)象系統(tǒng),它包含這篇文章沒有涉及到的特性(比如元類和靜態(tài)方法)。我們會(huì)專注于用戶定義的類,不帶有多重繼承和內(nèi)省行為(比如返回實(shí)例的類)。我們的實(shí)現(xiàn)并不遵循 Python 類型系統(tǒng)的明確規(guī)定。反之,它為實(shí)現(xiàn)對(duì)象隱喻的核心功能而設(shè)計(jì)。
2.6.1 實(shí)例我們從實(shí)例開始。實(shí)例擁有具名屬性,例如賬戶余額,它可以被設(shè)置或獲取。我們使用分發(fā)字典來實(shí)現(xiàn)實(shí)例,它會(huì)響應(yīng)“get”和“set”屬性值消息。屬性本身保存在叫做attributes的局部字典中。
就像我們?cè)谶@一章的前面看到的那樣,字典本身是抽象數(shù)據(jù)類型。我們使用列表來實(shí)現(xiàn)字典,我們使用偶對(duì)來實(shí)現(xiàn)列表,并且我們使用函數(shù)來實(shí)現(xiàn)偶對(duì)。就像我們以字典實(shí)現(xiàn)對(duì)象系統(tǒng)那樣,要注意我們能夠僅僅使用函數(shù)來實(shí)現(xiàn)對(duì)象。
為了開始我們的實(shí)現(xiàn),我們假設(shè)我們擁有一個(gè)類實(shí)現(xiàn),它可以查找任何不是實(shí)例部分的名稱。我們將類作為參數(shù)cls傳遞給make_instance。
>>> def make_instance(cls): """Return a new object instance, which is a dispatch dictionary.""" def get_value(name): if name in attributes: return attributes[name] else: value = cls["get"](name) return bind_method(value, instance) def set_value(name, value): attributes[name] = value attributes = {} instance = {"get": get_value, "set": set_value} return instance
instance是分發(fā)字典,它響應(yīng)消息get和set。set消息對(duì)應(yīng) Python 對(duì)象系統(tǒng)的屬性賦值:所有賦值的屬性都直接儲(chǔ)存在對(duì)象的局部屬性字典中。在get中,如果name在局部attributes字典中不存在,那么它會(huì)在類中尋找。如果cls返回的value為函數(shù),它必須綁定到實(shí)例上。
綁定方法值。make_instance中的get_value 使用get尋找類中的具名屬性,之后調(diào)用bind_method。方法的綁定只在函數(shù)值上調(diào)用,并且它會(huì)通過將實(shí)例插入為第一個(gè)參數(shù),從函數(shù)值創(chuàng)建綁定方法的值。
>>> def bind_method(value, instance): """Return a bound method if value is callable, or value otherwise.""" if callable(value): def method(*args): return value(instance, *args) return method else: return value
當(dāng)方法被調(diào)用時(shí),第一個(gè)參數(shù)self通過這個(gè)定義綁定到了instance的值上。
2.6.2 類類也是對(duì)象,在 Python 對(duì)象系統(tǒng)和我們這里實(shí)現(xiàn)的系統(tǒng)中都是如此。為了簡化,我們假設(shè)類自己并沒有類(在 Python 中,類本身也有類,幾乎所有類都共享相同的類,叫做type)。類可以接受get和set消息,以及new消息。
>>> def make_class(attributes, base_class=None): """Return a new class, which is a dispatch dictionary.""" def get_value(name): if name in attributes: return attributes[name] elif base_class is not None: return base_class["get"](name) def set_value(name, value): attributes[name] = value def new(*args): return init_instance(cls, *args) cls = {"get": get_value, "set": set_value, "new": new} return cls
不像實(shí)例那樣,類的get函數(shù)在屬性未找到的時(shí)候并不查詢它的類,而是查詢它的base_class。類并不需要方法綁定。
實(shí)例化。make_class 中的new函數(shù)調(diào)用了init_instance,它首先創(chuàng)建新的實(shí)例,之后調(diào)用叫做__init__的方法。
>>> def init_instance(cls, *args): """Return a new object with type cls, initialized with args.""" instance = make_instance(cls) init = cls["get"]("__init__") if init: init(instance, *args) return instance
最后這個(gè)函數(shù)完成了我們的對(duì)象系統(tǒng)。我們現(xiàn)在擁有了實(shí)例,它的set是局部的,但是get會(huì)回溯到它們的類中。實(shí)例在它的類中查找名稱之后,它會(huì)將自己綁定到函數(shù)值上來創(chuàng)建方法。最后類可以創(chuàng)建新的(new)實(shí)例,并且在實(shí)例創(chuàng)建之后立即調(diào)用它們的__init__構(gòu)造器。
在對(duì)象系統(tǒng)中,用戶僅僅可以調(diào)用create_class,所有其他功能通過消息傳遞來使用。與之相似,Python 的對(duì)象系統(tǒng)由class語句來調(diào)用,它的所有其他功能都通過點(diǎn)表達(dá)式和對(duì)類的調(diào)用來使用。
2.6.3 使用所實(shí)現(xiàn)的對(duì)象我們現(xiàn)在回到上一節(jié)銀行賬戶的例子。使用我們實(shí)現(xiàn)的對(duì)象系統(tǒng),我們就可以創(chuàng)建Account類,CheckingAccount子類和它們的實(shí)例。
Account類通過create_account_class 函數(shù)創(chuàng)建,它擁有類似于 Python class語句的結(jié)構(gòu),但是以make_class的調(diào)用結(jié)尾。
>>> def make_account_class(): """Return the Account class, which has deposit and withdraw methods.""" def __init__(self, account_holder): self["set"]("holder", account_holder) self["set"]("balance", 0) def deposit(self, amount): """Increase the account balance by amount and return the new balance.""" new_balance = self["get"]("balance") + amount self["set"]("balance", new_balance) return self["get"]("balance") def withdraw(self, amount): """Decrease the account balance by amount and return the new balance.""" balance = self["get"]("balance") if amount > balance: return "Insufficient funds" self["set"]("balance", balance - amount) return self["get"]("balance") return make_class({"__init__": __init__, "deposit": deposit, "withdraw": withdraw, "interest": 0.02})
在這個(gè)函數(shù)中,屬性名稱在最后設(shè)置。不像 Python 的class語句,它強(qiáng)制內(nèi)部函數(shù)和屬性名稱之間的一致性。這里我們必須手動(dòng)指定屬性名稱和值的對(duì)應(yīng)關(guān)系。
Account類最終由賦值來實(shí)例化。
>>> Account = make_account_class()
之后,賬戶實(shí)例通過new消息來創(chuàng)建,它需要名稱來處理新創(chuàng)建的賬戶。
>>> jim_acct = Account["new"]("Jim")
之后,get消息傳遞給jim_acct ,來獲取屬性和方法。方法可以調(diào)用來更新賬戶余額。
>>> jim_acct["get"]("holder") "Jim" >>> jim_acct["get"]("interest") 0.02 >>> jim_acct["get"]("deposit")(20) 20 >>> jim_acct["get"]("withdraw")(5) 15
就像使用 Python 對(duì)象系統(tǒng)那樣,設(shè)置實(shí)例的屬性并不會(huì)修改類的對(duì)應(yīng)屬性:
>>> jim_acct["set"]("interest", 0.04) >>> Account["get"]("interest") 0.02
繼承。我們可以創(chuàng)建CheckingAccount子類,通過覆蓋類屬性的子集。在這里,我們修改withdraw方法來收取費(fèi)用,并且降低了利率。
>>> def make_checking_account_class(): """Return the CheckingAccount class, which imposes a $1 withdrawal fee.""" def withdraw(self, amount): return Account["get"]("withdraw")(self, amount + 1) return make_class({"withdraw": withdraw, "interest": 0.01}, Account)
在這個(gè)實(shí)現(xiàn)中,我們?cè)谧宇惖?b>withdraw 中調(diào)用了基類Account的withdraw函數(shù),就像在 Python 內(nèi)建對(duì)象系統(tǒng)那樣。我們可以創(chuàng)建子類本身和它的實(shí)例,就像之前那樣:
>>> CheckingAccount = make_checking_account_class() >>> jack_acct = CheckingAccount["new"]("Jack")
它們的行為相似,構(gòu)造函數(shù)也一樣。每筆取款都會(huì)在特殊的withdraw函數(shù)中收費(fèi) $1,并且interest也擁有新的較低值。
>>> jack_acct["get"]("interest") 0.01 >>> jack_acct["get"]("deposit")(20) 20 >>> jack_acct["get"]("withdraw")(5) 14
我們的構(gòu)建在字典上的對(duì)象系統(tǒng)十分類似于 Python 內(nèi)建對(duì)象系統(tǒng)的實(shí)現(xiàn)。Python 中,任何用戶定義類的實(shí)例,都有個(gè)特殊的__dict__屬性,將對(duì)象的局部實(shí)例屬性儲(chǔ)存在字典中,就像我們的attributes字典那樣。Python 的區(qū)別在于,它區(qū)分特定的特殊方法,這些方法和內(nèi)建函數(shù)交互來確保那些函數(shù)能正常處理許多不同類型的參數(shù)。操作不同類型參數(shù)的函數(shù)是下一節(jié)的主題。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/38137.html
摘要:類似消息傳遞中的分發(fā)字典,對(duì)象響應(yīng)行為請(qǐng)求。消息傳遞和點(diǎn)表達(dá)式方法定義在類中,而實(shí)例屬性通常在構(gòu)造器中賦值,二者都是面向?qū)ο缶幊痰幕驹亍J褂脦в袃?nèi)建對(duì)象系統(tǒng)語言的優(yōu)點(diǎn)是,消息傳遞能夠和其它語言特性,例如賦值語句無縫對(duì)接。 2.5 面向?qū)ο缶幊? 來源:2.5 Object-Oriented Programming 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 面向?qū)ο缶幊?..
摘要:對(duì)象表示信息,但是同時(shí)和它們所表示的抽象概念行為一致。通過綁定行為和信息,對(duì)象提供了可靠獨(dú)立的日期抽象。名稱來源于實(shí)數(shù)在中表示的方式浮點(diǎn)表示。另一方面,對(duì)象可以表示很大范圍內(nèi)的分?jǐn)?shù),但是不能表示所有有理數(shù)。 2.1 引言 來源:2.1 Introduction 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 在第一章中,我們專注于計(jì)算過程,以及程序設(shè)計(jì)中函數(shù)的作用。我們看到了...
摘要:為通用語言設(shè)計(jì)解釋器的想法可能令人畏懼。但是,典型的解釋器擁有簡潔的通用結(jié)構(gòu)兩個(gè)可變的遞歸函數(shù),第一個(gè)求解環(huán)境中的表達(dá)式,第二個(gè)在參數(shù)上調(diào)用函數(shù)。這一章接下來的兩節(jié)專注于遞歸函數(shù)和數(shù)據(jù)結(jié)構(gòu),它們是理解解釋器設(shè)計(jì)的基礎(chǔ)。 3.1 引言 來源:3.1 Introduction 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 第一章和第二章描述了編程的兩個(gè)基本元素:數(shù)據(jù)和函數(shù)之間的...
摘要:的最常見的作用是構(gòu)造異常實(shí)例并拋出它。子句組只在執(zhí)行過程中的異常產(chǎn)生時(shí)執(zhí)行。每個(gè)子句指定了需要處理的異常的特定類。將強(qiáng)制轉(zhuǎn)為字符串會(huì)得到由返回的人類可讀的字符串。 3.4 異常 來源:3.4 Exceptions 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 程序員必須總是留意程序中可能出現(xiàn)的錯(cuò)誤。例子數(shù)不勝數(shù):一個(gè)函數(shù)可能不會(huì)收到它預(yù)期的信息,必需的資源可能會(huì)丟失,或者網(wǎng)...
摘要:另一個(gè)賦值語句將名稱關(guān)聯(lián)到出現(xiàn)在莎士比亞劇本中的所有去重詞匯的集合,總計(jì)個(gè)。表達(dá)式是一個(gè)復(fù)合表達(dá)式,計(jì)算出正序或倒序出現(xiàn)的莎士比亞詞匯集合。在意圖上并沒有按照莎士比亞或者回文來設(shè)計(jì),但是它極大的靈活性讓我們用極少的代碼處理大量文本。 1.1 引言 來源:1.1 Introduction 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 計(jì)算機(jī)科學(xué)是一個(gè)極其寬泛的學(xué)科。全球的分布...
閱讀 2847·2021-09-10 10:51
閱讀 2215·2021-09-02 15:21
閱讀 3206·2019-08-30 15:44
閱讀 869·2019-08-29 18:34
閱讀 1652·2019-08-29 13:15
閱讀 3322·2019-08-26 11:37
閱讀 2697·2019-08-26 10:46
閱讀 1107·2019-08-26 10:26