13. 面向對象(多態/封裝)

[TOC]

多態

同一種事物的多種形態
增加了程序的靈活性
增加了程序的可擴展性

封裝

封裝數據:保護隱私
封裝方法:隔離復雜度

第一種封裝:
什么都不做

第二種封裝:
雙下劃線的隱藏屬性
語法糖:_xxx====>類__xxx #這個過程就是變形

特性

@property #xxx = property(xxx)
def xxx():
pass

class Squera:      #定義一個正方形的類
    def __init__(self,lenth):   #定義一個邊長參數
        self.lenth = lenth

    @property     #使用特性裝飾器,不用調用外部模塊,因為可以在內置模塊中看到property()函數,這個裝飾器的實現效果其實就是area = property(area)
    def area(self):
        return self.lenth*self.lenth

    @property
    def perimeter(self):
        return 4* self.lenth

s = Squera(10)
# print(s.area())    #如果不添加property,打印這個面積需要使用調用函數的方法,但是實際上,為了統一這些參數的調用,并且規范調用方式,所以才使用property
# print(s.perimeter())

print(s.area)
print(s.perimeter)

除了如上注釋中描述的優點,我們需要注意,這個area和perimeter看起來像作為一個參數屬性在引用,但是實際上他本質上仍然是一個計算函數的結果。
所以在修改了lenth的長度之后,再次調用print(s.area)就會發現結果已經改變了。

被property裝飾的屬性會優于對象的屬性被引用。并且property的相關方法也會關聯一些語句,并且優先走有關聯語句的部分,例如下面代碼的xxx.name = 'xxxxx'就指向了name.setter函數,無論這個賦值是多少,優先運行name.setter的函數內容。
如果說這個name.setter中并沒有賦值相關的操作,那么這個動作就按照name.setter來運行。不執行賦值。

class Name:
    def __init__(self,NAME):
        self.__name = NAME

    @property   #將一個隱藏屬性定義成一個函數,并且把這個函數的計算結果返回出來
    def name(self):
        print(self.__name)

    @name.setter  #setter接口,用于設置之前property裝飾的函數,在函數內部修改被隱藏的值
    def name(self,value):  #定義一個可用值傳入
        if type(value)==str:
            self.__name = value   #將隱藏值在函數內部修改,如果在外部直接修改name,因為name是被property裝飾的一個函數,所以無法修改,起到了保護原隱藏值的作用。
        else:
            raise TypeError('please enter str type')

    @name.deleter
    def name(self):   #定義刪除原隱藏值函數
        del self.__name

peo1 = Name('scott')
#定義對象peo1
print(peo1.name)
#輸出對象名,由于__name 被隱藏,所以這里輸出的其實是name()的運算結果
peo1.name = 'jerry'
#當出現針對name(其實是函數)的賦值動作,被setter裝飾的函數運行;擴展:可以進行添加age隱藏參數,同__name,也給age添加修改方法,但是添加name.setter,看修改的是哪個值。需要注意setter方法前需要注明修改的對象
print(peo1.name)#查看結果
peo1.name = 123     #輸入錯誤類
print(peo1.name)
del peo1.name    #出現刪除操作的時候,執行.deleter裝飾的方法
print(peo1.name)

str

class people:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __str__(self):
        return 'name:%s,age:%s'%(self.name,self.age)

p1 = people('scott',23)
print(p1)

>>>name:'scott',age:23

定義在類的內部,必須返回一個字符串類型。
打印有這個類產生的對象時,會觸發執行。
其實str(p1)=========>p1.str()

staticmethod解除綁定方法

添加了@staticmethod之后,類中的方法就不再是綁定方法了,也就不存在self自動傳值的動作。
在類中,需要定義一個函數,就是給類使用的,而不和對象綁定,就要用到staticmethod。如果需要調用一個類的方法,并且不傳入self(也就是不綁定對象),也沒有使用staticmethod,那么在實例調用的時候,就會報缺少參數的錯。

import time
class Date:
    def __init__(self,year,month,day):# 定義一個基礎函數,傳入年月日
        self.year = year
        self.month = month
        self.day = day

    def test():            #定義一個test()方法,這個方法不與類綁定,在調用的時候與對象傳參無關(不接受對象的傳參)這時候其實test會有紅線提示,不規范的寫法
        print('from test') #返回一個標識結果

    @staticmethod          #靜態方法(用于將裝飾的函數從類中解除綁定)
    def now():             #定義的函數無需self傳值,但仍然可以作為類中的方法被對象調用
        t = time.localtime()    #.localtime()地方法傳給t,是一個類,包含著年月日時間參數
        obj = Date(t.tm_year,t.tm_mon,t.tm_mday) #將t的年月日信息傳給Date類,生成obj對象
        return obj     #返回,將now()的結果變成obj對象

    @staticmethod
    def tomorrow():
        t = time.localtime(time.time()+86400)
        return Date(t.tm_year,t.tm_mon,t.tm_mday)

class EuroDate(Date):
    def __str__(self):
        return '%s year %s month %s day'%((self.year,self.month,self.day))

d = Date(17,4,20)     #設置對象
d.test()              #報錯,對象不能調用test方法
#TypeError: test() takes 0 positional arguments but 1 was given
Date.test()           #類可以調用方法,但是沒有意義,此時的test和類外部的函數一樣。

靜態方法的引用:

t = d.now()
print(t.year,t.month,t.day)
l = time.localtime()
print(type(l))

結果

2017 4 21
<class 'time.struct_time'>

實例也可以使用,但通常靜態方法都是給類用的,實例在使用時喪失了自動傳值的機制

在類中,如果沒被裝飾器裝飾過,就是綁定方法

import time
class Date:
    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day
    @staticmethod
    def now():
        t=time.localtime()
        return Date(t.tm_year,t.tm_mon,t.tm_mday)

class EuroDate(Date):
    def __str__(self):
        return 'year:%s month:%s day:%s' %(self.year,self.month,self.day)

e=EuroDate.now()
print(e) #我們的意圖是想觸發EuroDate.__str__,但是結果為
'''
輸出結果:
<__main__.Date object at 0x1013f9d68>
'''

classmethod

@classmethod
http://blog.csdn.net/handsomekang/article/details/9615239#

把一個方法綁定給類

一般來說,要使用某個類的方法,需要先實例化一個對象再調用方法。

而使用@staticmethod或@classmethod,就可以不需要實例化,直接類名.方法名()來調用。

這有利于組織代碼,把某些應該屬于某個類的函數給放到那個類里去,同時有利于命名空間的整潔。

既然@staticmethod和@classmethod都可以直接類名.方法名()來調用,那他們有什么區別呢

從它們的使用上來看,

  • @staticmethod不需要表示自身對象的self和自身類的cls參數,就跟使用函數一樣。
  • @classmethod也不需要self參數,但第一個參數需要是表示自身類的cls參數。

如果在@staticmethod中要調用到這個類的一些屬性方法,只能直接類名.屬性名或類名.方法名。

而@classmethod因為持有cls參數,可以來調用類的屬性,類的方法,實例化對象等,避免硬編碼。

差別:綁定給對象的,第一個位置不用傳參staticmethod
綁定給類的(類.綁定給類的方法()),會把類本身當作第一個參數(原self)傳給類

class A(object):
    bar = 1
    def foo(self):
        print 'foo'

    @staticmethod
def static_foo():
    print 'static_foo'
    print A.bar

@classmethod
def class_foo(cls):
    print 'class_foo'
    print cls.bar
    cls().foo()

A.static_foo()
A.class_foo() 

拿到一個類的內存地址后,就可以實例化或者引用類的屬性了。

小結:

在類內部定義的函數無非三種用途
一:綁定到對象的方法
    只要是在類內部定義的,并且沒有被任何裝飾器修飾過的方法,都是綁定到對象的

    class Foo:
        def test(self): #綁定到對象的方法
            pass
        def test1(): #也是綁定到對象的方法,只是對象.test1(),會把對象本身自動傳給test1,因test1沒有參數所以會拋出異常
            pass

    綁定到對象,指的是:就給對象去用,
    使用方式:對象.對象的綁定方法(),不用為self傳值
    特性:調用時會把對象本身當做第一個參數傳給對象的綁定方法

二:綁定到類的方法:classmethod
    在類內部定義的,并且被裝飾器@classmethod修飾過的方法,都是綁定到類的

#用來計算類被實例化的次數
# def get_no_(cls_obj):
#     return cls_obj.times_inst

class Exm_cls:
   #實例化次數的初始值為0
   times_inst = 0
   #類被實例化一次,就+1
   def __init__(self):
       Exm_cls.times_inst +=1

   #在內部定義這個函數,并且把他綁定到類
   @classmethod
   def get_no_(cls):
       return cls.times_inst


exm1 = Exm_cls()
exm2 = Exm_cls()

print(Exm_cls.get_no_())
# print(get_no_(Exm_cls))    
    綁定到對象,指的是:就給對象去用,
    使用方式:對象.對象的綁定方法()
    特性:調用時會把對象本身當做第一個參數傳給對象的綁定方法

三:解除綁定的方法:staticmethod
    既不與類綁定,也不與對象綁定,不與任何事物綁定
    綁定的特性:自動傳值(綁定到類的就是自動傳類,綁定到對象的就自動傳對象)
    解除綁定的特性:不管是類還是對象來調用,都沒有自動傳值這么一說了

    所以說staticmethod就是相當于一個普通的工具包

class Foo:
    def test1(self):
        pass
    def test2():
        pass

    @classmethod
    def test3(cls):
        pass
    @classmethod
    def test4():
        pass

    @staticmethod
    def test5():
        pass

test1與test2都是綁定到對象方法:調用時就是操作對象本身
    <function Foo.test1 at 0x0000000000D8E488>
    <function Foo.test2 at 0x0000000000D8E510>
test3與test4都是綁定到類的方法:調用時就是操作類本身
    <bound method Foo.test3 of <class '__main__.Foo'>>
    <bound method Foo.test4 of <class '__main__.Foo'>>
test5是不與任何事物綁定的:就是一個工具包,誰來都可以用,沒說專門操作誰這么一說
    <function Foo.test5 at 0x0000000000D8E6A8>

反射
getattr
setattr
delattr
hasattr

定制

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,460評論 6 538
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,067評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,467評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,468評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,184評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,582評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,616評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,794評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,343評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,096評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,291評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,863評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,513評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,941評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,190評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,026評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,253評論 2 375

推薦閱讀更多精彩內容

  • 國家電網公司企業標準(Q/GDW)- 面向對象的用電信息數據交換協議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,067評論 6 13
  • @(python)[筆記] 目錄 前言 在python中,一切皆對象面向對象的程序設計的核心就是對象;面向對象的程...
    CaiGuangyin閱讀 603評論 0 5
  • 今天看了charlotte,說真的,第一集確實有些討厭,不過男主的帥氣和那個時不時出現的攝影機還是吸引了我,于是繼...
    小潯閱讀 218評論 0 0
  • 文/紅線 第一次拜讀丹尼爾·平克的作品,這本書名聲在外,對于我這個社會小白、職場小白來說,還是有很多影響力的。因為...
    紅線533閱讀 1,373評論 0 0
  • 之前培訓就聽過這句話,不要用放大鏡去看下屬的缺點,明明是一件小事,卻被放大無數倍,導致我們對下屬各種不信任。...
    姜楊Ada閱讀 220評論 0 0