更加抽象

# coding:utf-8程序員


#--------------------------------------------------  對象魔力  -----------------------------------------express


#多態app


#多態方法dom

print 'abc'.count('a')ide

#1函數

print [1, 2, 'a'].count('a')工具

#1spa

#不用關心count('a')裏面是什麼類型數據,只要知道count方法,能夠返回a出現多少次,就好了,這就是多態方法設計

#choice函數,能夠從序列中隨機選出元素。對象

from random import choice

x = choice(['Hello, world!', [1, 2, 'e', 'e', 4]])

#x多是Hello,world字符串,多是[1, 2, 'e', 'e', 4]列表,不用關心究竟是哪一個類型,只要關心變量x中字符e出現了多少次。無論x是字符串仍是列表,均可以使用count函數。

print x.count('e')

#2              #本例中,看來列表勝出了。

#多態多種形式

#當面對對象不知道是什麼類型,但又要對對象作些何時,就會用到多態

#這不只限於方法,不少內建運算符和函數都有多態的性質。好比:

print 1 + 2

#3

print 'Fish' + 'license'

#Fishlicense

#這裏的加運算符對於數字和字符串都能起做用。

#爲說明這一點,假設有個叫作add的函數,它能夠將兩個對象相加。能夠直接將其定義成上面的形式。

def add(x, y):

   return x+y

#對於不少類型的參數均可以用:

print add(1, 2)

#3

print add('Fish', 'license')

#Fishlicense

#若是須要編寫打印對象長度消息的函數,只需對象具備長度(len函數可用)便可。

def length_message(x):

   print "The length of", repr(x), "is", len(x)

#能夠看到,函數中還使用了repr函數,repr函數是多態特性。

length_message('Fnord')

#The length of 'Fnord' is 5

length_message([1, 2, 3])

#The length of [1, 2, 3] is 3

#不少函數和運算符都是多態的---你寫的絕多數程序可能都是,即使你並不是有意這樣。只要使用多態函數和運算符,就會與「多態」發生關聯。

#事實上,惟一能毀掉多態的就是使用函數檢查類型,好比type,isinstance以及issubclass函數等。

#若是可能的話,應該盡力避免使用這些毀掉多態的方式。真正重要的是如何讓對象按照你所但願的方式工做,無論它是不是正確的類型(或者類)。


#封裝

#封裝是指向程序中的其餘部分隱藏對象的具體實現細節原則。

#接下面再論私有化進行詳細解釋


#繼承

#就是函數,類等調用,相同代碼不想重複寫,直接調用給其餘代碼,就是繼承。


#--------------------------------------------  類和類型 ------------------------------------------


#建立類

__metaclass__ = type           #肯定使用新式類,一種寫法格式,建立類寫上便可

class Person:

   def setName(self, name):

       self.name = name

   def getName(self):

       return self.name

   def greet(self):

       print "Hello, world! I'm %s." % self.name

#這個例子包含3個方法定義,除了它們是寫在class語句裏,一切都像是函數定義。Person是類的名字。class語句會在函數定義的地方建立本身的命名空間。

#self參數看起來有點奇怪,它是對於對象自身的引用。那麼它是什麼對象?建立一些實例看看:

foo = Person()

bar = Person()

foo.setName('Luke Skywalker')               #foo將本身爲第一個參數傳入到self裏

bar.setName('Anakin Skywalker')

foo.greet()

#Hello, world! I'm Luke Skywalker.

bar.greet()

#Hello, world! I'm Anakin Skywalker.

#在調用foo的setName和greet函數時,foo自動將本身做爲第一個參數傳入函數中---所以形象地命名爲self。對於這個變量,每一個人可能都會有本身的叫法,可是由於它老是對象本身,因此習慣上老是叫作self

#顯然這就是self的用處和存在的必要性。沒有它的話,成員方法就無法訪問它們要對其特性進行操做的對象自己了。

#特性能夠在外部訪問:

#就是setName函數裏的self.name = name

print foo.name

#Luke Skywalker

bar.name = 'Yoda'

bar.greet()

#Hello, world! I'm Yoda.

#若是知道foo是Person的實例的話,那麼能夠把foo.greet()寫成:

Person.greet(foo)           #方便的簡寫

#Hello, world! I'm Luke Skywalker.


#特性,函數,方法

__metaclass__ = type

class Class:

   def method(self):

       print 'I have a self!'

def function():

       print "I don't..."

instance = Class()              #調用類

instance.method()               #instance是實例,method是方法,有self參數

#I have a self!

instance.method = function      #綁定到一個普通函數上,沒有self參數

instance.method()

#I don't...

__metaclass__ = type

class Bird:

   song = 'Squaawk!'

   def sing(self):

       print self.song

bird = Bird()

bird.sing()

#Squaawk!

birdsong = bird.sing

birdsong()              #調用方法和函數十分類似,但變量綁定方法bird.sing仍是會對self參數進行訪問

#Squaawk!


#再論私有化,接上面的封裝

#使用上面類的例子:

__metaclass__ = type

class Person:

   def setName(self, name):

       self.name = name

   def getName(self):

       return self.name

   def greet(self):

       print "Hello, world! I'm %s." % self.name

o = Person()            #調用類

o.setName('Sir Lancelot')

print o.getName()

#Sir Lancelot

#變量o綁定到對象(Person類)上,可使用setName和getName方法。一切看起來很完美。可是假設變量o將它的名字存儲在全局變量globalName中:

#但假設變量o將它的名字存儲在全局變量globalName中:

#globalName

#'Sir Lancelot'

#這意味着在使用OpenObject類的實例時候,不得不關心globalName的內容。實際上要確保不會對它進行任何更改:

#globalName = 'Sir Gumby'

#o.getName()

#'Sir Gumby'

#若是建立了多個OpenObject實例的話就會出現問題,由於變量相同,因此可能會混淆:

#o1 = OpenObject()

#o2 = OpenObject()

#o1.setName('Robin Hood')

#o2.getName()

#'Robin Hood'

#設定一個名字後,其餘名字也自動設定了。

#爲了讓方法或者特性變成私有(外部沒法訪問),只要在它的名字前面加上雙下劃線便可。

__metaclass__ = type

class Secretive:

   def __inaccessible(self):            #讓方法變成私有化(外部沒法訪問),只要在它的名字前面加上雙下劃線便可

       print "Bet you can`t see me..."

   def accessible(self):

       print "The secret message is:"

       self.__inaccessible()           #內部調用

s = Secretive()

# s.__inaccessible()              #報錯沒法調用

s.accessible()                  #內部能夠調用

#The secret message is:

#Bet you can`t see me...

s._Secretive__inaccessible()       #也有外部調用方法,但不該該這麼作

#Bet you can`t see me...


#類的命名空間

__metaclass__ = type

class MemberCounter:

   members = 0

   def init(self):

       MemberCounter.members += 1

#上面代碼中,在類做用域內定義了一個可供全部成員(實例)訪問的變量(members),用來計算類的成員數量。注意init用來初始化全部實例。

m1 = MemberCounter()        #調用類

m1.init()

print MemberCounter.members

#1

m2 = MemberCounter()

m2.init()

print MemberCounter.members

#2

#類做用域內的變量也能夠被全部實例訪問:

print m1.members

#2

print m2.members

#2

m1.members = 'Two'              #新的numbers值被寫到了m1特性中,屏蔽了類範圍內的變量。這跟函數內的局部和全局變量的行爲十分相似。

print m1.members

#Two

print m2.members

#2


#指定超類

__metaclass__ = type

class Filter:           #寫一個過濾做用的類(超類)

   def init(self):

       self.blocked = []

   def filter(self, sequence):

       return [x for x in sequence if x not in self.blocked]  # 如何理解這句話,同等於下面註釋

#        l = []

#        for x in sequence:

#            if x not in self.blocked:

#                l.append(x)

#        return l

#Filter是個用於過濾序列的通用類,事實上它自身不能過濾任何東西

f = Filter()

f.init()

print f.filter([1, 2, 3])

#[1, 2, 3]

#Filter類的用處在於它能夠用做其餘類的(基類)超類,好比下面SPAMFilter類,能夠將序列中的'SPAM'過濾出去。

class SPAMFilter(Filter):               #繼承上面的類,能夠不用寫一大堆過濾的類,從上面繼承更加方便。SPAMFilter是Filter的子類,Filter是SPAMFilter的超類

   def init(self):                     #重寫超類Filter中的init方法

       self.blocked = ['SPAM']         #原本過濾關鍵字沒寫,如今寫入SPAM

s = SPAMFilter()

s.init()

print s.filter(['SPAM','SPAM','SPAM','eggs','bacon','SPAM'])

#['eggs', 'bacon']


#檢查繼承

#若是想要查看一個類是不是另一個的子類,可使用內建的issubclass的函數:

print issubclass(SPAMFilter, Filter)        #查看SPAMFilter是不是Failter的子類

#True

print issubclass(Filter, SPAMFilter)

#False

#若是想要知道已知類的基類(們)(注意下節解釋),可使用特殊特性__bases__:

print SPAMFilter.__bases__       #已知類的基類,使用__bases__

#(<class '__main__.Filter'>,)

print Filter.__bases__

#(<type 'object'>,)

#使用isinstance方法檢查一個對象是不是一個類的實例:

s = SPAMFilter()

print isinstance(s, SPAMFilter)

#True

print isinstance(s, Filter)

#True

print isinstance(s, str)

#False

#想知道一個對象屬於哪一個類,可使用__class__特性

print s.__class__

#<class '__main__.SPAMFilter'>


#多個超類

#上節提到一個類的基類(們),也就暗示它的基類可能會多於一個。事實上就是這樣,創建幾個新類來試試:

class Calculator:

   def calculate(self,expression):

       self.value = eval(expression)

class Talker:

   def talk(self):

       print 'Hi, my value is', self.value

class TalkingCalculator(Calculator, Talker):

   pass

#子類(TalkingCalculator)本身不作任何事,它從本身的超類繼承全部的行爲。它從Calculator類那裏繼承calculate方法,從Talker類那裏繼承talk方法,這樣它就成了會說話的計算器。

tc = TalkingCalculator()

tc.calculate('1+2*3')

tc.talk()

#Hi, my value is 7

#這種行爲稱爲多重繼承,是個很是有用的工具。但除非特別熟悉多重繼承,不然應該儘可能避免使用,由於有些時候會出現不可預見的麻煩。

#須要注意是若是一個方法從多個超類繼承(也就是說有兩個具備相同名字的不一樣方法),那麼必須注意下超類的順序(在class語句中):先繼承的類中的方法會重寫後繼承的類中的方法。

#若是前例中Calculator:類也有個叫talk方法(函數),那麼它會覆蓋Talker的talk方法(使其沒法訪問)。若是把它們順序掉過來,像下面這樣:

#class TalkingCalculator(Talker, Calculator): pass

#就會讓Talker的talk方法可用了。


#接口和內省

#能夠查看方法是否存在(接口)

print hasattr(tc, 'talk')

#True

print hasattr(tc, 'fnord')

#False


#小結

#對象

#對象包括特性和方法。特性只是做爲對象的一部分的變量,方法則是存儲在對象內的函數。(綁定)方法和其餘函數的區別在於方法老是將對象做爲本身的第一個參數,這個參數通常稱爲self。

#類

#類表明對象的集合(或一類對象),每一個對象(實例)都有一個類。類的主要任務是定義它的實例會用到方法。

#多態

#多態是實現將不一樣類型和類的對象進行一樣對待的特性---不須要知道對象屬於哪一個類就能調用的方法。

#封裝

#對象能夠將它們的內部狀態隱藏(或封裝)起來。在一些語言中,這意味着對象的狀態(特性)只對本身的方法可用。在Python中,全部的特性都是公開可用的,可是程序員應該在直接訪問對象狀態時謹慎行事,由於他們可能無心中使得這些特性在某些方面不一致。

#繼承

#一個類能夠是一個或者多個類的子類。子類從超類繼承全部方法。可使用多個超類,這個特性能夠用來組成功能的正交部分(沒有任何聯繫)。普通的實現方式是使用核心的超類和一個或者多個混合的超類。

#接口和內省

#通常來講,對於對象不用探討過深。程序猿能夠靠多態調用本身須要的方法。不過若是想要知道對象到底有什麼方法和特性,有些函數能夠幫助完成這項工做。

#面向對象設計

#關於如何(或者說是否應該進行)面向對象設計有不少的觀點。無論你持什麼觀點,徹底理解這個問題,而且建立容易理解的設計是很重要的。

相關文章
相關標籤/搜索