python物件導向的學習筆記

來源:互聯網
上載者:User


建立類:


#!/usr/bin/python
# Filename: simplestclass.py
 
class Person:
    pass # An empty block
 
p = Person()
print p
$ python simplestclass.py
<__main__.Person instance at 0xf6fcb18c>

我們使用類名後跟一對圓括弧來建立一個對象/執行個體。為了驗證,我們簡單地列印了這個變數的類型。它告訴我們我們已經在__main__模組中有了一個Person類的執行個體。
可以注意到儲存物件的電腦記憶體位址也列印了出來。這個地址在你的電腦上會是另外一個值,因為Python可以在任何空位儲存物件。

對象中的方法

我們已經討論了類/對象可以擁有像函數一樣的方法,這些方法與函數的區別只是一個額外的self變數。現在我們來
學習一個例子。


#!/usr/bin/python
# Filename: method.py
 
class Person:
    def sayHi(self):
        print 'Hello, how are you?'
 
p = Person()
p.sayHi()
$ python method.py
Hello, how are you?

這裡我們看到了self的用法。注意sayHi方法沒有任何參數,但仍然在函數定義時有self。

__init__方法:

__init__方法在類的一個對象被建立時,馬上運行。這個方法可以用來對你的對象做一些你希望的 初始化 。


#!/usr/bin/python
# Filename: class_init.py
 
class Person:
    def __init__(self, name):
        self.name = name
    def sayHi(self):
        print 'Hello, my name is', self.name
 
p = Person('Swaroop')
p.sayHi()
$ python class_init.py
Hello, my name is Swaroop

類與對象的方法

我們已經討論了類與對象的功能部分,現在我們來看一下它的資料部分。事實上,它們只是與類和對象的名稱空間 綁定 的普通變數,即這些名稱只在這些類與對象的前提下有效。
有兩種類型的 域 ——類的變數和對象的變數,它們根據是類還是對象 擁有 這個變數而區分。
類的變數 由一個類的所有對象(執行個體)共用使用。只有一個類變數的拷貝,所以當某個對象對類的變數做了改動的時候,這個改動會反映到所有其他的執行個體上。
對象的變數 由類的每個對象/執行個體擁有。因此每個對象有自己對這個域的一份拷貝,即它們不是共用的,在同一個類的不同執行個體中,雖然對象的變數有相同的名稱,但是是互不相關的。通過一個例子會使這個易於理解。

使用類與對象的變數


#!/usr/bin/python
# Filename: objvar.py
 
class Person:
    '''Represents a person.'''
    population = 0
 
    def __init__(self, name):
        '''Initializes the person's data.'''
        self.name = name
        print '(Initializing %s)' % self.name
 
        # When this person is created, he/she
        # adds to the population
        Person.population += 1
 
    def __del__(self):
        '''I am dying.'''
        print '%s says bye.' % self.name
 
        Person.population -= 1
 
        if Person.population == 0:
            print 'I am the last one.'
        else:
            print 'There are still %d people left.' % Person.population
 
    def sayHi(self):
        '''Greeting by the person.
 
        Really, that's all it does.'''
        print 'Hi, my name is %s.' % self.name
 
    def howMany(self):
        '''Prints the current population.'''
        if Person.population == 1:
            print 'I am the only person here.'
        else:
            print 'We have %d persons here.' % Person.population
 
swaroop = Person('Swaroop')
swaroop.sayHi()
swaroop.howMany()
 
kalam = Person('Abdul Kalam')
kalam.sayHi()
kalam.howMany()
 
swaroop.sayHi()
swaroop.howMany()
$ python objvar.py
(Initializing Swaroop)
Hi, my name is Swaroop.
I am the only person here.
(Initializing Abdul Kalam)
Hi, my name is Abdul Kalam.
We have 2 persons here.
Hi, my name is Swaroop.
We have 2 persons here.
Abdul Kalam says bye.
There are still 1 people left.
Swaroop says bye.
I am the last one.

使用繼承:


#!/usr/bin/python
# Filename: inherit.py
 
class SchoolMember:
    '''Represents any school member.'''
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print '(Initialized SchoolMember: %s)' % self.name
 
    def tell(self):
        '''Tell my details.'''
        print 'Name:"%s" Age:"%s"' % (self.name, self.age),
 
class Teacher(SchoolMember):
    '''Represents a teacher.'''
    def __init__(self, name, age, salary):
        SchoolMember.__init__(self, name, age)
        self.salary = salary
        print '(Initialized Teacher: %s)' % self.name
 
    def tell(self):
        SchoolMember.tell(self)
        print 'Salary: "%d"' % self.salary
 
class Student(SchoolMember):
    '''Represents a student.'''
    def __init__(self, name, age, marks):
        SchoolMember.__init__(self, name, age)
        self.marks = marks
        print '(Initialized Student: %s)' % self.name
 
    def tell(self):
        SchoolMember.tell(self)
        print 'Marks: "%d"' % self.marks
 
t = Teacher('Mrs. Shrividya', 40, 30000)
s = Student('Swaroop', 22, 75)
 
print # prints a blank line
 
members = [t, s]
for member in members:
    member.tell() # works for both Teachers and Students
$ python inherit.py
(Initialized SchoolMember: Mrs. Shrividya)
(Initialized Teacher: Mrs. Shrividya)
(Initialized SchoolMember: Swaroop)
(Initialized Student: Swaroop)

Name:"Mrs. Shrividya" Age:"40" Salary: "30000"
Name:"Swaroop" Age:"22" Marks: "75"

Python不會自動調用基本類的constructor

Python物件導向特徵總結


一、封裝

物件導向程式設計中的術語對象(Object)基本上可以看做資料(特性)以及由一系列可以存取、操作這些資料的方法所組成的集合。傳統意義上的“程式=資料結構+演算法”被封裝”掩蓋“並簡化為“程式=對象+訊息”。對象是類的執行個體,類的抽象則需要經過封裝。封裝可以讓調用者不用關心對象是如何構建的而直接進行使用。

一個簡單的Python類封裝如下:


Encapsulation
 

上面簡單的範例程式碼可以看出,Python中的類包含了一般物件導向程式設計語言的主要元素,比如構造方法、Binder 方法、靜態方法、屬性等,如果深入下去,還可以發現Python中內建了很多物件導向的“進階”主題,比如迭代器、反射、特性等等,提供了封裝的直接構造要素。

 

二、繼承

1、類繼承

繼承給人的直接感覺是這是一種複用代碼的行為。繼承可以理解為它是以普通的類為基礎建立專門的類對象,子類和它繼承的父類是IS-A的關係。一個簡單而不失經典的樣本如下:


Inheritance
 

一個顯而易見的特點是,Python的物件導向的繼承特徵是基於類(class)的,比javascript基於原型(prototype)的繼承更容易組織和編寫代碼,也更容易讓人接受和理解。

ps:最近幾天Anders大神搞出來的TypeScript橫空出世,看它的語言規範裡繼承也是基於類的:


TypeScript-SimpleInheritance
 

感覺基於類的繼承的語言好像在實現OO的可讀性和編程體驗上都不太差,據傳說javascript是碼農最想噴也是噴過最多f**k的語言。

2、多重繼承

不同於C#,Python是支援多重類繼承的(C#可繼承自多個Interface,但最多繼承自一個類)。多重繼承機制有時很好用,但是它容易讓事情變得複雜。一個多重繼承的樣本如下:


MultInheritance
 

如你所看到的那樣,多重繼承的好處顯而易見,我們可以輕而易舉地通過類似“組合”的方式複用代碼構造一個類型。

有個需要注意的地方,即如果一個方法從多個超類繼承,那麼務必要小心繼承的超類(或者基類)的順序:


MultInheritance
 

我們為動物和機器各實現一個相同名稱的move方法,但是輸出因為繼承的順序而有所不同,Python在尋找給定方法或者特性時訪問超類的順序被稱為MRO(Method Resolution Order,方法判定順序)。

三、多態

多態意味著可以對不同的對象使用同樣的操作,但它們可能會以多種形態呈現出結果。在Python中,任何不知道對象到底是什麼類型,但又需要對象做點什麼的時候,都會用到多態。

能夠直接說明多態的兩段範例程式碼如下:

1、方法多態


Method-Polymorphism
 

對於一個臨時對象obj,它通過Python的隨機函數取出來,不知道具體類型(是字串、元組還是自訂類型),都可以調用count方法進行計算,至於count由誰(哪種類型)去做怎麼去實現我們並不關心。

有一種稱為”鴨子類型(duck typing)“的東西,講的也是多態:


DuckTyping
就in_the_forest函數而言,參數對象是一個鴨子類型,它實現了方法多態。但是實際上我們知道,從嚴格的抽象來講,Person類型和Duck完全風馬牛不相及。

2、運算子也多態


Operator-Polymorphism
 

上例中,顯而易見,Python的加法運算子是”多態“的,理論上,我們實現的add方法支援任意支援加法的對象,但是我們不用關心兩個參數x和y具體是什麼類型。

一兩個範例程式碼當然不能從根本上說明多態。普遍認為物件導向最有價值最被低估的特徵其實是多態。我們所理解的多態的實現和子類的虛函數地址綁定有關係,多態的效果其實和函數地址運行時動態綁定有關。在C#中實現多態的方式通常有重寫和重載兩種,從上面兩段代碼,我們其實可以分析得出Python中實現多態也可以變相理解為重寫和重載。在Python中很多內建函數和運算子都是多態的。

號外:在C#中,我們熟知介面(Interface)和多態相關,在處理多態對象時,只要關心它的介面(或者稱為“協議”)而不需要顯式指定特定實作類別型即可,這也是IoC中面向介面(抽象)而不依賴於具體實現編程的基礎。可惜在Python中根本沒有Interface(有抽象類別)。而在TypeScript的Specification中引入了Interface的概念:


TypeScript-Interface
 

TypeScript語言規範裡對Interface的定義是命名的物件類型(Programmers can give names to object types; we call named object types interfaces. )。它直接等價於下面的Ojbect Type:

var Friend: () => {
    name: string; favoriteColor?: string;
};
上面這個Object Type在Playgound中等價的javascript代碼如下:

var Friend;
在TypeScript編程規範文檔裡,對Interface的一些說明:

Interfaces provide the ability to give names to object types and the ability to compose existing named object types into new ones.
Interfaces have no run-time representation—they are purely a compile-time construct. Interfaces are particularly useful for documenting and validating the required shape of properties, objects passed as parameters, and objects returned from functions.

Interface可以繼承自Interface:


TypeScript-InterfaceInheritInterface
 

我們嘗試讓類繼承自Interface:


interface Mover
{
    move(): void;
}

class SimpleMover  extends Mover{
    move() {
  alert("move")
    }
 
 
}

var mover=new SimpleMover();
mover.move();
 

實踐證明類是不能繼承實現Interface的:A export class may only extend other classes, Mover is an interface.

現在大家知道TypeScript裡的Interface和我們所認識和理解的介面的區別了嗎?相同的一個名詞Interface,不同語境下意義並不完全相同,看上去好像是挺傻的,但是學習和使用語言不做對比幾乎是不可能的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.