28面向對象3_繼承_linkedlist

 

目錄java

inheritance繼承:... 1node

繼承中的訪問控制:... 5python

繼承中的初始化:... 9算法

多繼承:... 13編程

mixin... 16json

習題:... 23設計模式

single linkedlist. 25網絡

double linkedlist... 28app

習題:... 32編程語言

 

 

 

inheritance繼承:

人類和豬類都繼承自動物類;

個體繼承自父母,繼承了父母的一部分特徵,但也能夠有本身的個性;

在面向對象的世界中,從父類繼承,就可直接擁有父類的屬性和方法,這樣可減小代碼、多複用;

子類可定義本身的屬性和方法;

 

子類繼承父類的特徵,特徵即類屬性、類方法、靜態方法、實例屬性;

公共的屬性和方法,包括_開頭的;

隱私屬性和方法是__開頭的,對外暴露提供的方法要爲屬性裝飾器的方法;

 

open-close-principle開閉原則:

對擴展開放(繼承開放),擴展個性化的地方;

修改關閉;

 

繼承也稱派生

class Cat(Animal)這種形式就是從父類繼承,括號中寫繼承的類的列表;

繼承可以讓子類從父類獲取特徵(屬性和方法);

父類Animal就是Cat的父類,也稱基類超類

子類Cat就是Animal的子類,也稱派生類

 

定義:

class 子類(基類1[,基類2,...]):

         語句塊

若是定義類時,沒有基類列表,等同於繼承自object,在python3中,object是全部對象的根基類,倒置的根;

python2中有古典類(舊式類)、新式類,3.0全是新式類;

python支持多繼承,繼承也能夠多級,多級展開即tree,不必定是二叉樹;

單繼承(一條鏈串起來);多繼承;

 

單繼承關係圖:

子類指向父類;

1.jpg

 

繼承的特殊屬性和方法:

__base__,類的基類,過期了;

__bases__,類的基類元組;

__mro__,多繼承時用,顯示方法查找順序,基類的元組,多繼承中很是重要,mro()方法的結果會放在__mro__

mro(),多繼承時用,同上,int.mro()在類上用該方法,實例上不能用

__subclasses__(),類的子類列表,int.__subclasses__()

 

python不一樣版本的類:

py2.2以前,類是沒有共同的祖先的,以後,引入object類,它是全部類的共同祖先類object

py2爲了兼容,分爲古典類(舊式類)和新式類;

py3中全是新式類;

新式類都是繼承自object類的,新式類可以使用super()

py2py3版本不一樣,不只是語法方面,還有類構建方面;

 

例:

class Animal(object):   #等價於class Animal:,默認繼承自object,若加上object則兼容python2

    x = 123

    def __init__(self):

        self.name = 'tom'

 

    def getname(self):

        return self.name

 

class Cat(Animal):

    pass

 

class Dog():

    pass

 

tom = Cat()

print(tom.name)

print(tom.__dict__)

print(tom.getname())

 

dog = Dog()

# print(dog.name)

# print(dog.getname())

輸出:

tom

{'name': 'tom'}

tom

 

例:

class Animal(object):

    x = 123

    def __init__(self,name):

        self._name = name

 

    @property   #裝飾後的也能繼承,終歸Animal類的管轄

    def name(self):

        return self._name   #公共屬性

 

    def shout(self):

        print('Animal shout')

 

class Cat(Animal):

    x = 'cat'   #override覆蓋

    def shout(self):   #override覆蓋(重寫),與rewrite是兩碼事

        print('miao')

 

class Dog(Animal):

    pass

 

class Garfield(Cat):

    pass

 

class PersiaCat(Cat):

    # def __init__(self):   #call to __init__ of super class is missed,需調用父類方法

    #     self.eyes = 'blue'

    pass

 

tom = Cat('tom')

print(tom.name)

print(tom.__dict__)

tom.shout()   #自有的,體現個性

 

dog = Dog('ahuang')

dog.shout()   #本身沒有的,用繼承的'Animal shout'

 

gf = Garfield(Cat)

gf.shout()

 

pc = PersiaCat('persiacat')

print(pc.__dict__)

# pc.name = 'persiacat'   #不可修改

pc.eyes = 'blue,green'

pc.shout()

print(pc.name,pc.eyes)

print(pc.__dict__)

輸出:

tom

{'_name': 'tom'}

miao

Animal shout

miao

{'_name': 'persiacat'}

miao

persiacat blue,green

{'_name': 'persiacat', 'eyes': 'blue,green'}

 

例:

gf = Garfield(Cat)

gf.shout()

print('gf.mro={}'.format(gf.__class__.mro()))   #mro()方法,只能在類上用,不能在實例上用

print('gf.mro={}'.format(gf.__class__.__mro__))

print('gf.bases={}'.format(gf.__class__.__bases__))

輸出:

miao

gf.mro=[<class '__main__.Garfield'>, <class '__main__.Cat'>, <class '__main__.Animal'>, <class 'object'>]

gf.mro=(<class '__main__.Garfield'>, <class '__main__.Cat'>, <class '__main__.Animal'>, <class 'object'>)

gf.bases=(<class '__main__.Cat'>,)

 

例:

In [1]: int.__subclasses__()

Out[1]: [bool, sre_constants._NamedIntConstant, <enum 'IntEnum'>]

In [2]: int.__bases__

Out[2]: (object,)

In [3]: int.__base__

Out[3]: object

In [4]: int.mro()   #返回int自身

Out[4]: [int, object]

In [5]: int.__mro__

Out[5]: (int, object)

 

 

 

繼承中的訪問控制:

從父類繼承,本身沒有的,就可到父類中找;

私有的都是不可訪問的,本質上是改了名並放入所在類的__dict__中,知道這個新名稱就可直接找到這個隱藏的變量,這是個黑魔法技巧,慎用;

 

繼承時,公有的(除__開頭的),子類和實例均可隨意訪問;私有的,被隱藏,子類和實例不可直接訪問,私有變量所在的類內有方法,則可訪問這個私有變量;

python經過本身一套實現,實現和其它語言同樣的面向對象的繼承機制;

 

屬性查找順序:

實例的__dict__-->__dict__,有繼承-->父類__dict__

若是搜索這些地方後沒找到就拋異常,先找到就當即返回了;

 

方法的重寫(覆蓋)override

super(),新式類中提供了該方法,可訪問到父類的屬性,具體原理後續;

Animal.__init__(self,name)py2寫法;

super().__init__(name),至關於super(Cat,self).__init__(name)完整寫法,py3寫法,

self.__class__.__base__.__init__(self,name),不推薦使用;

 

例:

class Animal(object):

    x = 123

    def __init__(self,name):

        self._name = name

        self.__age = 10

 

class Cat(Animal):

    x = 'cat'

 

class Garfield(Cat):

    pass

 

tom = Garfield('tom')

print(tom.__dict__)   #輸出隱私屬性_Animal__age_父類的名字__屬性,誰有這個屬性編譯器就更名字爲誰,當前只Animal類上有

print(Garfield.__dict__)   #子類先找本身的實例,再依次往上找父類

print(Cat.__dict__)   #類中找不到_Animal__age,該屬性在實例裏,self即爲實例,實例屬性的__dict__,方法是在類中

輸出:

{'_name': 'tom', '_Animal__age': 10}

{'__module__': '__main__', '__doc__': None}

{'__module__': '__main__', 'x': 'cat', '__doc__': None}

 

例(方法的重寫(覆蓋)):

class Animal(object):

    x = 123

    def __init__(self,name):

        self._name = name

        self.__age = 10

 

    @property

    def name(self):

        return self._name

 

    def shout(self):

        print('Animal shout')

 

class Cat(Animal):

    x = 'cat'

    def __init__(self,name):

        # super(Cat,self).__init__(name)

        # super().__init__(name)

        Animal.__init__(self,name)   #子類中也初始化,python2寫法;py3寫法爲super().__init__(name),新式類推薦使用此種寫法;兩種方式等價;

        #self._name = name   #2個屬性{'_name': 'tom', '_Animal__age': 10}

                   #self.catname = name   #3個屬性{'_name': 'tom', '_Animal__age': 10, 'catname': 'tom'}

                   self._name = 'cat' + name   #2個屬性{'_name': 'cattom', '_Animal__age': 10}

 

tom = Cat('tom')

print(tom.name)

print(tom.__dict__)

輸出:

#tom

#{'_name': 'tom', '_Animal__age': 10}

#tom

#{'_name': 'tom', '_Animal__age': 10, 'catname': 'tom'}

cattom

{'_name': 'cattom', '_Animal__age': 10}

 

例(方法的重寫(覆蓋)):

class Animal:

    def shout(self):

        print('Animal shout')

 

class Cat(Animal):

    def shout(self):

        print('miao')

 

    def shout(self):   #覆蓋了自身的shout,以前的完全沒有了;Animal中的shout仍在本身內部,在調用時遮蓋了;這兩次覆蓋有差別

        print('cat shout')

        print(super())

        print(super(Cat,self))   #等價於super()

        super().shout()

        self.__class__.__base__.shout(self)   #不推薦使用,等價於super()

 

cat = Cat()

cat.shout()

輸出:

cat shout

<super: <class 'Cat'>, <Cat object>>

<super: <class 'Cat'>, <Cat object>>

Animal shout

Animal shout

 

例:

class Animal(object):

    x = 123

    def __init__(self,name):

        self._name = name

        self.__age = 10

 

    @property

    def name(self):

        return self._name

 

    def shout(self):

        print('Animal shout')

 

class Cat(Animal):

    x = 'cat'

    def __init__(self,name):

        # self._name = name

        self._name = 'cat' + name   #前後有影響

        Animal.__init__(self, name)

 

tom = Cat('tom')

print(tom.name)

print(tom.__dict__)

輸出:

tom

{'_name': 'tom', '_Animal__age': 10}

 

例:

class Animal:

    @classmethod

    def clsmtd(cls):

        print(cls,cls.__name__)

 

class Cat(Animal):

    def __init__(self,name):

        self.name = name

    @classmethod

    def clsmtd(cls):

        print(cls,cls.__name__)

 

class Garfield(Cat): pass

 

tom = Garfield('tom')

tom.clsmtd()   #多態,多態前提要繼承,用哪一個類建立的實例就是哪一個類

 

print(tom.__dict__)

print(Cat.__dict__)

print(Animal.__dict__)   #公有的(除__開頭),父類的都是你的,py內部會自動逐級找(可理解爲繼承的就是個人),傳什麼就打印什麼,用哪一個類建立的實例就是哪一個類,雖有父類的特徵在都繼承下來

輸出:

<class '__main__.Garfield'> Garfield

{'name': 'tom'}

{'__module__': '__main__', '__init__': <function Cat.__init__ at 0x7f1993df3488>, 'clsmtd': <classmethod object at 0x7f1993df5be0>, '__doc__': None}

{'__module__': '__main__', 'clsmtd': <classmethod object at 0x7f1993df5b70>, '__dict__': <attribute '__dict__' of 'Animal' objects>, '__weakref__': <attribute '__weakref__' of 'Animal' objects>, '__doc__': None}

 

 

 

繼承中的初始化:

好習慣 ,在子類中只要有初始化__init__方法,就要把父類的寫上,如super().__init__(name),即若是父類中定義了__init__方法,子類中也有__init__,就該在子類的__init__中調用它;

 

建議:少在繼承中使用私有變量;

 

例:

class A:

    def __init__(self,a):

        self.a = a

 

class B(A):   #B定義時聲明繼承自類A,則在類B__bases__中可看到類A,但這和是否調用類A的構造方法是兩回事

    def __init__(self,b,c):   #若是B中調用了A的構造方法super().__init__(a)就可擁有父類的屬性了,查看b__dict__

        self.b = b

        self.c = c

 

    def printv(self):

        print(self.b)

        print(self.c)

        # print(self.a)   #AttributeError: 'B' object has no attribute 'a'

 

b = B(20,30)

b.printv()

print(B.__bases__)

 

print(B.__dict__)

print(A.__dict__)

輸出:

20

30

(<class '__main__.A'>,)

{'__module__': '__main__', '__init__': <function B.__init__ at 0x7fd7e7023158>, 'printv': <function B.printv at 0x7fd7e7023488>, '__doc__': None}

{'__module__': '__main__', '__init__': <function A.__init__ at 0x7fd7e70230d0>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}

 

解決上例問題:

class A:

    def __init__(self,a):

        self.a = a

 

class B(A):

    def __init__(self,b,c):

        super().__init__(b+c)   #等價於A.__init__(self,b+c)

        self.b = b

        self.c = c

 

    def printv(self):

        print(self.b)

        print(self.c)

        print(self.a)

 

b = B(20,30)

b.printv()

print(B.__bases__)

 

print(b.__dict__)

print(B.__dict__)

print(A.__dict__)

輸出:

20

30

50

(<class '__main__.A'>,)

{'a': 50, 'b': 20, 'c': 30}

{'__module__': '__main__', '__init__': <function B.__init__ at 0x7f0e00935158>, 'printv': <function B.printv at 0x7f0e00935488>, '__doc__': None}

{'__module__': '__main__', '__init__': <function A.__init__ at 0x7f0e009350d0>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}

 

例:

class A:

    def __init__(self,a,d):

        self.a = a

        self.__d = d

 

class B(A):

    def __init__(self,b,c):

        super().__init__(b+c,c-b)

        self.b = b

        self.c = c

        self.__d = b + c + 1

 

    def printv(self):

        print(self.b)

        print(self.c)

        print(self.a)

        print(self.__d)

 

b = B(20,30)

b.printv()

print(b.__class__.__bases__)

 

print(b.__dict__)

print(B.__dict__)

print(A.__dict__)

輸出:

20

30

50

51

(<class '__main__.A'>,)

{'a': 50, '_A__d': 10, 'b': 20, 'c': 30, '_B__d': 51}   #實例b__dict__中有的私有屬性,要查看該私有屬性必須在該實例所在類中有方法,若是該實例的類中沒有訪問方法,父類中有一樣屬性的訪問方法,那最終訪問的是父類中的屬性

{'__module__': '__main__', '__init__': <function B.__init__ at 0x7fadc3ca8158>, 'printv': <function B.printv at 0x7fadc3ca8488>, '__doc__': None}

{'__module__': '__main__', '__init__': <function A.__init__ at 0x7fadc3ca80d0>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}

 

例:

class Animal:

    def __init__(self,age):

        print('Animal init')

        self.__age = age

 

    def show(self):

        print(self.__age)

 

class Cat(Animal):

    def __init__(self,age,height):

        print('Cat init')

        super().__init__(age)

        self.__age = age + 1

        self.__height = height

 

c = Cat(10,20)

c.show()   #show方法在Animal中定義,__age會被解釋爲_Animal__age,這樣設計很差,Cat的實例應顯示本身的屬性值

print(c.__dict__)

print(Cat.__dict__)

print(Animal.__dict__)

輸出:

Cat init

Animal init

10

{'_Animal__age': 10, '_Cat__age': 11, '_Cat__height': 20}

{'__module__': '__main__', '__init__': <function Cat.__init__ at 0x7fad21a10488>, '__doc__': None}

{'__module__': '__main__', '__init__': <function Animal.__init__ at 0x7fad21a100d0>, 'show': <function Animal.show at 0x7fad21a10158>, '__dict__': <attribute '__dict__' of 'Animal' objects>, '__weakref__': <attribute '__weakref__' of 'Animal' objects>, '__doc__': None}

 

解決上例問題:

一個原則,本身的私有屬性,就該本身的方法讀取和修改,不要藉助其它類的方法,即便是父類或派生類的方法;

class Animal:

    def __init__(self,age):

        print('Animal init')

        self.__age = age

 

    def show(self):

        print(self.__age)

 

class Cat(Animal):

    def __init__(self,age,height):

        print('Cat init')

        super().__init__(age)

        self.__age = age + 1

        self.__height = height

 

    def show(self):

        print(self.__age)

        print(self.__height)

 

c = Cat(10,20)

c.show()

print(c.__dict__)

print(Cat.__dict__)

print(Animal.__dict__)

輸出:

Cat init

Animal init

11

20

{'_Animal__age': 10, '_Cat__age': 11, '_Cat__height': 20}

{'__module__': '__main__', '__init__': <function Cat.__init__ at 0x7f565534f488>, 'show': <function Cat.show at 0x7f565534f510>, '__doc__': None}

{'__module__': '__main__', '__init__': <function Animal.__init__ at 0x7f565534f0d0>, 'show': <function Animal.show at 0x7f565534f158>, '__dict__': <attribute '__dict__' of 'Animal' objects>, '__weakref__': <attribute '__weakref__' of 'Animal' objects>, '__doc__': None}

 

 

 

多繼承:

ocp原則,open-closed principle多繼承、少修改

繼承的用途:加強基類、實現多態;

 

多態:

在面向對象中,父類、子類經過繼承聯繫在一塊兒,若是可經過一套方法,就可實現不一樣表現,就是多態;

一個類繼承自多個類,就是多繼承,它將具備多個類的特徵;

 

多繼承弊端:

多繼承很好的模擬了世界,由於事物不多是單一繼承,可是捨棄簡單,必然引入複雜性,帶來了衝突;

如同一個孩子繼承了來自父母雙方的特徵,那麼到底眼睛像爸爸仍是媽媽呢?孩子更像誰多一點?

多繼承的實現會致使編譯器設計的複雜度增長,因此如今不少語言也捨棄了類的多繼承,C++支持多繼承,java捨棄了多繼承;

 

java中,一個類可實現多個接口,一個接口也可繼承多個接口,java的接口很純粹,只是方法的聲明,繼承者必須實現這些方法,就具備了這些能力,就能幹什麼;

 

多繼承可能會帶來二異性,如貓和狗都繼承自動物類,若是一個類多繼承了貓類和狗類,貓和狗都有shout方法,子類空間繼承誰的shout呢?

解決方案:

實現多繼承的語言,可解決二義性,深度優先廣度優先

 2.jpg


注:單一繼承;

 

3.jpg

多繼承,分開看兩條均單繼承:

MyClass-->D-->B-->A,深度優先;

MyClass-->D-->C-->B-->A,廣度優先;

 

多繼承帶來路徑選擇問題,究竟繼承哪一個父類的特徵呢?

py使用MROmethod resolution order,解決基類搜索順序問題;

歷史緣由,MRO有三個搜索算法:

經典算法,按定義從左到右,深度優先策略,2.2以前,MyClass->D->B->A->C->A

新式類算法,經典算法的升級,重複的只保留一個,2.2MyClass->D->B->C->A->object

C3算法,在類被建立出來時,就計算出一個MRO有序列表,2.3以後,py3惟一支持的算法MyClass->D->B->C->A->object

 

多繼承的缺點:

當類不少,繼承複雜的狀況下,繼承路徑太多,很難說清什麼樣的繼承路徑;

py語法容許多繼承,但py代碼是解釋執行,只有執行到的時候才發現錯誤;

團隊協做開發,若是引入多繼承,那代碼將不可控;

無論編程語言是否支持多繼承,都應避免多繼承;

py的面向對象,太靈活了,太開放了,因此要團隊守規矩,類增長要規範;

規範化、文檔化、大量重構;

 

多繼承定義:

class ClassName(基類列表):

         類體

 

 

 

mixin

UML中,面向對象中的高級部分;

 

例:

4.jpg

Document類是其它全部文檔類的抽象基類;

WordPdfDocument類的子類;

要求:

document子類提供打印能力;

 

思路1

Document類中提供print方法;

基類提供的方法不該該具體實現,由於它未必適合子類的打印,子類中須要覆蓋重寫;

print算是一種能力——打印功能,不是全部的Document的子類都須要的,因此,從這個角度出發,有問題

 

思路2

須要打印的子類上增長

若是在子類上直接增長,違反了ocp原則,因此應該繼承後增長

5.jpg

如下兩種不一樣的繼承思路,不一樣場景下用:

方一:用於項目正在開發中,直接加到所屬類裏;

方二:用於已開發完成項目或第三方庫,用繼承方式新增類;

看似不錯,若是還要提供其它能力,如何繼承?

應用於網絡,文檔應該具有序列化的能力,類上就應該實現序列化;

可序列化還可能分爲使用picklemessagepackjson等;

這時發現,類可能太多了,繼承的方式不是很好了,功能太多,A類須要某幾樣功能,B類須要另幾樣功能,很繁瑣;

 

思路3

裝飾器,用處極廣;

優勢:簡單方便,在須要的地方動態增長;

用裝飾器加強一個類,把功能給類附加上去,哪一個類須要,就裝飾它;

 

思路4

mixin,本質上就是多繼承實現的;

mixin體現的是一種組合的設計模式;

在面向對象的設計中,一個複雜的類,每每須要不少功能,而這些功能由來自不一樣的類提供,這就要將不少的類組合在一塊兒;

從設計模式的角度來講,多組合(混在一塊兒,如PrintableWord(PrintableMixin,Word))、少繼承,組合優於繼承;

6.jpg

 

mixin類的使用原則:

mixin類中不該該顯式的出現__init__初始化方法(是混進去加強功能的,不用初始化,通常是用來加強類屬性,而不是加強實例的,實例缺的東西應在其類上或繼承的類上,而不是混進去的);

mixin類一般不能獨立工做(不完整),由於它是準備混入別的類中的部分功能實現;

mixin類若有繼承,該mixin類的祖先類也應是mixin類;

 

使用時,mixin類一般在繼承列表的第一個位置,如class SuperPrintablePdf(SuperPrintableMixin,Pdf): pass

 

mixin類和裝飾器:

這兩種方式均可使用,看我的喜愛;

若是還須要繼承,就要使用mixin類方式;

簡單用裝飾器;複雜用mixin類;

實現方式不一樣,結果同樣(異曲同工);

 

 

思路2:方一:

class Document:

    def __init__(self,content):

        self.content = content

 

    def print(self):

        print(self.content)

 

class Word(Document):   #用於項目正在開發中,直接加到所屬類裏

    def print(self):

        print('word print: {}'.format(self.content))

 

class Pdf(Document):

    def print(self):

        print('pdf print: {}'.format(self.content))

 

print(Word.mro())

word = Word('test\nabc')

word.print()

print(Word.__dict__)

輸出:

[<class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>]

word print: test

abc

{'__module__': '__main__', 'print': <function Word.print at 0x7f87e34ed488>, '__doc__': None}

 

思路2:方二1

class Document:   #第三方庫

    def __init__(self,content):

        self.content = content

 

    def print(self):

        print(self.content)

 

class Word(Document): pass   #第三方庫

 

class PrintableWord(Word):

    def print(self):

        print('word print: {}'.format(self.content))

 

class Pdf(Document): pass   #第三方庫

 

class PrintablePdf(Pdf):

    def print(self):

        print('pdf print: {}'.format(self.content))

 

print(PrintableWord.mro())

word = PrintableWord('test\nabc')

word.print()

print(word.__dict__)

print(PrintableWord.__dict__)

輸出:

[<class '__main__.PrintableWord'>, <class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>]

word print: test

abc

{'content': 'test\nabc'}

{'__module__': '__main__', 'print': <function PrintableWord.print at 0x7fbbc301e488>, '__doc__': None}

 

思路2:方二2

class Printable:

    def _print(self):

        print(self.content)

 

class Document:

    def __init__(self,content):

        self.content = content

 

    def print(self):

        print(self.content)

 

class Word(Document): pass

 

class PrintableWord(Printable,Word): pass

 

class Pdf(Document): pass

 

class PrintablePdf(Printable,Pdf): pass

 

print(PrintableWord.mro())

word = PrintableWord('test\nabc')

word.print()

print(word.__dict__)

print(PrintableWord.__dict__)

輸出:

[<class '__main__.PrintableWord'>, <class '__main__.Printable'>, <class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>]

test

abc

{'content': 'test\nabc'}

{'__module__': '__main__', '__doc__': None}

 

思路3(函數裝飾器):

def printable(cls):

    # def _print(self):

    #     print(self.content)

    # cls.print = _print   #等價於下面一行

    cls.print = lambda self: print(self.content)

    return cls

 

class Document:

    def __init__(self,content):

        self.content = content

 

    def print(self):

        print(self.content)

 

class Word(Document): pass

 

class Pdf(Document): pass

 

@printable

class PrintableWord(Word): pass

 

@printable

class PrintablePdf(Pdf): pass

 

word = PrintableWord('test\nabc')

word.print()

print(word.__class__.mro())

print(word.__dict__)

print(PrintableWord.__dict__)

輸出:

test

abc

[<class '__main__.PrintableWord'>, <class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>]

{'content': 'test\nabc'}

{'__module__': '__main__', '__doc__': None, 'print': <function printable.<locals>.<lambda> at 0x7f32371490d0>}

 

思路4

class PrintableMixin:

    def print(self):   #該行和下一行的print,與builtins中衝突?不衝突,這是自定義類中的方法;若把該函數寫在與class同級下,就與builtins衝突了

        print('~~~~~~~~~~~~~~~~')

        print(self.content)

        print('~~~~~~~~~~~~~~~~')

 

class Document:

    def __init__(self,content):

        self.content = content

 

class Word(Document): pass

 

class PrintableWord(PrintableMixin,Word): pass   #PrintableMixin只能在前邊,如在右邊將不起做用,屬多繼承,本質上是改變了__mro__中的順序

 

class Pdf(Document): pass

 

class PrintablePdf(PrintableMixin,Pdf): pass

 

class SuperPrintableMixin(PrintableMixin):   #mixin是類,可繼承

    def print(self):

        print('#####################')

        print(self.content)

        print('#####################')

 

class SuperPrintablePdf(SuperPrintableMixin,Pdf): pass

 

word = PrintableWord('test\nabc')

word.print()

print(word.__class__.mro())   #查看搜索順序

print(word.__dict__)

print(word.__class__.__dict__)

 

pdf = SuperPrintablePdf('pdf\npdf')

pdf.print()

print(pdf.__class__.mro())

print(pdf.__dict__)

print(pdf.__class__.__dict__)

輸出:

~~~~~~~~~~~~~~~~

test

abc

~~~~~~~~~~~~~~~~

[<class '__main__.PrintableWord'>, <class '__main__.PrintableMixin'>, <class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>]

{'content': 'test\nabc'}

{'__module__': '__main__', '__doc__': None}

#####################

pdf

pdf

#####################

[<class '__main__.SuperPrintablePdf'>, <class '__main__.SuperPrintableMixin'>, <class '__main__.PrintableMixin'>, <class '__main__.Pdf'>, <class '__main__.Document'>, <class 'object'>]

{'content': 'pdf\npdf'}

{'__module__': '__main__', '__doc__': None}

 

 

 

習題:

1shape基類,要求全部子類都必須提供面積的計算,子類有三角形、矩形、圓;

2、上題圓類的數據可序列化;

3、用面向對象實現linked list鏈表:

單向鏈表實現appenditernodes

雙向鏈表實現appendpopinsertremoveiternodes

 

7.jpg

 

注:

pycharm中格式化,Code-->Reformat Code

文檔字符串通常用""",雙引號三引號;

 

1

import math

 

class Shape:

    @property

    def area(self):

        # return

        raise NotImplementedError('base class is not implement')   #技巧,基類中未實現該方法,即這個父類就是不容許調用

 

class Triangle(Shape):

    def __init__(self,bottom,height):

        self.bottom = bottom

        self.height = height

 

    @property

    def area(self):

        return self.bottom * self.height / 2

 

class Rectangle(Shape):

    def __init__(self,length,width):

        self.length = length

        self.width = width

 

    @property

    def area(self):

        return self.length * self.width

 

class Circle(Shape):

    def __init__(self,radius):

        self.radius = radius

 

    @property

    def area(self):

        return math.pi * (self.radius ** 2)

 

triangle = Triangle(3,2)

print(triangle.area)

 

rectangle = Rectangle(5,4)

print(rectangle.area)

 

circle = Circle(2)

print(circle.area)

輸出:

3.0

20

12.566370614359172

 

2

import json

import msgpack

from class_practice_8 import Circle

 

class SerializableMixin:

    def dumps(self,t='json'):

        if t == 'json':

            return json.dumps(self.__dict__)

        elif t == 'msgpack':

            return msgpack.dumps(self.__dict__)

        else:

            raise NotImplementedError('Not implemented serializable')

 

class SerializableCircleMixin(SerializableMixin,Circle): pass

 

scm = SerializableCircleMixin(2)

print(scm.area)

 

print(scm.__dict__)

s = scm.dumps('msgpack')

print(s)

輸出:

12.566370614359172

{'radius': 2}

b'\x81\xa6radius\x02'

 

single linkedlist

鏈表與列表?鏈表爲何用列表實現?

列表中僅保存的是鏈表中每一個元素內存地址的引用;

鏈表中每一個元素之間是靠自身內部的next聯繫的;

 

單向鏈表,手拉手,有序,內存中是亂的、分散的;

list,內存中有序;

 

3

single linkedlist1

class SingleNode:

    def __init__(self,val,next=None):

        self.val = val

        self.next = next

 

    def __repr__(self):

        return str(self.val)

 

    def __str__(self):

        return str(self.val)

 

class LinkedList:

    def __init__(self):

        # self.nodes = []

        self.head = None

        self.tail = None

 

    def append(self,val):

        node = SingleNode(val)

        if self.tail is None:

            self.head = node

        else:

            self.tail.next = node

        # self.nodes.append(node)

        self.tail = node

 

    def iternodes(self):

        current = self.head

        while current:

            yield current

            current = current.next

 

ll = LinkedList()

node = SingleNode(5)

ll.append(node)

node = SingleNode(6)

ll.append(node)

for node in ll.iternodes():

    print(node)

輸出:

5

6

 

single linkedlist2

class SingleNode:   #表明一個節點

    def __init__(self,val,next=None):   #最後一個爲None

        self.val = val

        self.next = next   #實例屬性,類中print和裝飾器中的_print

 

    def __repr__(self):

        return str(self.val)

 

    __str__ = __repr__

 

class LinkedList:   #容器類,某種方式存儲一個個節點

    def __init__(self):

        self.items = []   #保存每一個節點的地址;可用索引,便於查詢,檢索方便,但insertremove不方便,[]適合讀多寫少;業務中若是頻繁插入元素則不用列表

        self.head = None

        self.tail = None   #追加方便

 

    def append(self,val):

        node = SingleNode(val)

        if self.tail is None:   #尾巴是空則該鏈表爲空

            self.head = node

        else:

            self.tail.next = node

        self.tail = node

        self.items.append(node)

       

    def iternodes(self):   #要知道鏈表中的元素必須迭代;技巧:generator

        current = self.head

        while current:

            yield current

            current = current.next

 

    def __getitem__(self, item):   #僅用於容器,提供一種方便的接口,如索引或其它方式來用

        return self.items[item]

 

         def __len__(self):   #不多拿長度,頻繁操做長度一直在變,只是大概

        return len(self.items)

 

ll = LinkedList()

node = SingleNode(5)

ll.append(node)

node = SingleNode(6)

ll.append(node)

for node in ll.iternodes():

    print(node)

 

print(ll[0])

輸出:

5

6

5

2

 

 

 

double linkedlist

 

技巧:

generator

三目運算符;

enumerate()

 

class SingleNode:

    def __init__(self,val,next=None,prev=None):

        self.val = val

        self.next = next

        self.prev = prev

 

    def __repr__(self):

        return str(self.val)

 

    __str__ = __repr__

 

class LinkedList:

    def __init__(self):

        # self.items = []

        self.head = None

        self.tail = None

 

    def append(self,val):

        node = SingleNode(val)

        if self.tail is None:   #第一個nodethe first node

            self.head = node

        else:

            self.tail.next = node

            node.prev = self.tail   #當前節點的上一個節點

        self.tail = node

        # self.items.append(node)

 

    def iternodes(self,reverse=False):

        current = self.tail if reverse else self.head   #2個技巧,generator函數和類三目運算符

        while current:

            yield current

            current = current.prev if reverse else current.next

 

    def pop(self):

        if self.tail is None:   #鏈表中元素爲0

            raise Exception('Empty')

        tail = self.tail

        prev = tail.prev

        # next = tail.next   #用不上,尾巴的下一個元素必定爲None

        if prev is None:   #尾巴的前一個元素爲空,說明該鏈表僅一個元素

            self.head = None

            self.tail = None   #把當前尾巴的元素清空後,鏈表就爲空

        else:   #鏈表中元素>1

            self.tail = prev

            prev.next = None

        return tail.val

 

    def getitem(self,index):

        if index < 0:

            return None

        current = None

        for i,node in enumerate(self.iternodes()):   #技巧

            if i == index:

                current = node

                break

        if current is None:   #以下四行可簡寫爲if current is not None: return current

            return None

        else:

            return current

 

    def insert(self,index,val):   #考慮當前鏈表,0個元素,1個元素(index01時),尾部追加

        if index < 0:

            raise Exception('Error')

        current = None

        for i,node in enumerate(self.iternodes()):

            if i == index:

                current = node

                break

        if current is None:   #鏈表中無元素,index只要大於邊界就往裏追加

            self.append(val)

            return

        prev = current.prev

        # next = current.next

        node = SingleNode(val)

        if prev is None:   #前加、中間加、尾部加

            self.head = node

            node.next = current

            current.prev = node

        else:

            node.prev = prev

            node.next = current

            current.prev = node

            prev.next = node

 

    def remove(self,index):

        if self.tail is None:

            raise Exception('Empty')

        if index < 0:

            raise ValueError('Wrong Index{}'.format(index))

        current = None

        for i,node in enumerate(self.iternodes()):

            if i == index:

                current = node

                break

        if current is None:

            raise ValueError('Wrong Index {} out of memory'.format(index))

        prev = current.prev

        next = current.next

        if prev is None and next is None:

            self.head = None

            self.tail = None

        elif prev is None:

            self.head = next

            next.prev = None

        elif next is None:

            self.tail = prev

            prev.next = None

        else:

            prev.next = next

            next.prev = prev

        del current

 

 

ll = LinkedList()

node1 = SingleNode('abc')

ll.append(node1)

node2 = SingleNode(4)

ll.append(node2)

node3 = SingleNode(5)

ll.append(node3)

node4 = SingleNode(6)

ll.append(node4)

node5 = SingleNode('end')

ll.append(node5)

 

for node in ll.iternodes():

    print(node)

print('~'*20)

ll.pop()

ll.pop()

ll.pop()

ll.insert(0,'start')   #各類測試,前、中、尾,元素爲空,元素爲1

ll.insert(8,'end')

ll.insert(1,123)

ll.insert(2,456)

ll.remove(5)

ll.remove(0)

for node in ll.iternodes(reverse=True):

    print(node)

輸出:

abc

4

5

6

end

~~~~~~~~~~~~~~~~~~~~

4

abc

456

123

 

 

 

習題:

1、將鏈表,封裝成容器:

要求:

1)提供__getitem__()__iter__()__setitem__()

2)使用一個列表,輔助完成上面的方法;

3)進階:不使用列表,完成上面的方法;

 

2、實現類property裝飾器,類名稱爲Property

 

1、方一(容器實現):

 

class SingleNode:

    def __init__(self,val,next=None,prev=None):

        self.val = val

        self.next = next

        self.prev = prev

 

    def __repr__(self):

        return str(self.val)

 

    __str__ = __repr__

 

class LinkedList:

    def __init__(self):

        self.items = []

        self.head = None

        self.tail = None

        self.size = 0

 

    def append(self,val):

        node = SingleNode(val)

        if self.tail is None:

            self.head = node

        else:

            self.tail.next = node

            node.prev = self.tail

        self.tail = node

        self.items.append(node)

        self.size += 1

 

    def iternodes(self,reverse=False):

        current = self.tail if reverse else self.head

        while current:

            yield current

            current = current.prev if reverse else current.next

 

    def pop(self):

        if self.tail is None:

            raise Exception('Empty')

        tail = self.tail

        prev = tail.prev

        # next = tail.next

        if prev is None:

            self.head = None

            self.tail = None

        else:

            self.tail = prev

            prev.next = None

        self.items.pop()

        self.size -= 1

        return tail.val

 

    def getitem(self,index):

        if index < 0:

            return None

        current = None

        for i,node in enumerate(self.iternodes()):

            if i == index:

                current = node

                break

        if current is None:

            return None

        else:

            return current

 

    def insert(self,index,val):

        if index < 0:

            raise Exception('Error')

        current = None

        for i,node in enumerate(self.iternodes()):

            if i == index:

                current = node

                break

        if current is None:

            self.append(val)

            return

        prev = current.prev

        # next = current.next

        node = SingleNode(val)

        if prev is None:

            self.head = node

            node.next = current

            current.prev = node

        else:

            node.prev = prev

            node.next = current

            current.prev = node

            prev.next = node

        self.items.insert(index,val)

        self.size += 1

 

    def remove(self,index):

        if self.tail is None:

            raise Exception('Empty')

        if index < 0:

            raise ValueError('Wrong Index{}'.format(index))

        current = None

        for i,node in enumerate(self.iternodes()):

            if i == index:

                current = node

                break

        if current is None:

            raise ValueError('Wrong Index {} out of memory'.format(index))

        prev = current.prev

        next = current.next

        if prev is None and next is None:

            self.head = None

            self.tail = None

        elif prev is None:

            self.head = next

            next.prev = None

        elif next is None:

            self.tail = prev

            prev.next = None

        else:

            prev.next = next

            next.prev = prev

        del current

        self.items.pop(index)

        self.size -= 1

 

    def __len__(self):

        return self.size

 

    # def __iter__(self):

    #     return iter(self.items)

    __iter__ = iternodes

 

    def __getitem__(self, item):

        return self.items[item]

 

    def __setitem__(self, key, value):

        self.items[key].val = value   #若是出錯,借用列表來拋異常,不需本身實現

 

ll = LinkedList()

node1 = SingleNode('abc')

ll.append(node1)

node2 = SingleNode(4)

ll.append(node2)

node3 = SingleNode(5)

ll.append(node3)

node4 = SingleNode(6)

ll.append(node4)

# ll.remove(3)

node5 = SingleNode('end')

ll.append(node5)

 

for node in ll.iternodes():

    print(node)

print('~'*20)

ll.pop()

node6 = SingleNode('head')

ll.insert(0,node6)

node7 = SingleNode('middle')

ll.insert(3,node7)

ll.remove(3)

# print(len(ll))

for node in ll:

    print(node)

# print(node7.next)   #None

 

 

1、方二(非容器實現):

 

class SingleNode:

    def __init__(self,val,next=None,prev=None):

        self.val = val

        self.next = next

        self.prev = prev

 

    def __repr__(self):

        return str(self.val)

 

    __str__ = __repr__

 

class LinkedList:

    def __init__(self):

        # self.items = []

        self.head = None

        self.tail = None

        self.size = 0

 

    def append(self,val):

        node = SingleNode(val)

        if self.tail is None:

            self.head = node

        else:

            self.tail.next = node

            node.prev = self.tail

        self.tail = node

        # self.items.append(node)

        self.size += 1

 

    def iternodes(self,reverse=False):

        current = self.tail if reverse else self.head

        while current:

            yield current

            current = current.prev if reverse else current.next

 

    def pop(self):

        if self.tail is None:

            raise Exception('Empty')

        tail = self.tail

        prev = tail.prev

        # next = tail.next

        if prev is None:

            self.head = None

            self.tail = None

        else:

            self.tail = prev

            prev.next = None

        # self.items.pop()

        self.size -= 1

        return tail.val

 

    def getitem(self,index):

        if index < 0:

            return None

        current = None

        for i,node in enumerate(self.iternodes()):

            if i == index:

                current = node

                break

        if current is None:

            return None

        else:

            return current

 

    def insert(self,index,val):

        if index < 0:

            raise Exception('Error')

        current = None

        for i,node in enumerate(self.iternodes()):

            if i == index:

                current = node

                break

        if current is None:

            self.append(val)

            return

        prev = current.prev

        # next = current.next

        node = SingleNode(val)

        if prev is None:

            self.head = node

            node.next = current

            current.prev = node

        else:

            node.prev = prev

            node.next = current

            current.prev = node

            prev.next = node

        # self.items.insert(index,val)

        self.size += 1

 

    def remove(self,index):

        if self.tail is None:

            raise Exception('Empty')

        if index < 0:

            raise ValueError('Wrong Index{}'.format(index))

        current = None

        for i,node in enumerate(self.iternodes()):

            if i == index:

                current = node

                break

        if current is None:

            raise ValueError('Wrong Index {} out of memory'.format(index))

        prev = current.prev

        next = current.next

        if prev is None and next is None:

            self.head = None

            self.tail = None

        elif prev is None:

            self.head = next

            next.prev = None

        elif next is None:

            self.tail = prev

            prev.next = None

        else:

            prev.next = next

            next.prev = prev

        del current

        # self.items.pop(index)

        self.size -= 1

 

    def __len__(self):

        return self.size

 

    # def __iter__(self):

    #     return iter(self.items)

    __iter__ = iternodes   #可用partial解決reverse傳參問題

 

    # def __getitem__(self, item):

    #     return self.items[item]

    def __getitem__(self, index):

        # for i,node in enumerate(self.iternodes()):

        #     if i == index:

        #         return node

        # for i,node in enumerate(self.iternodes(True),1):

        #     if -i = index:

        #         return node

        flag = False if index >= 0 else True

        start = 0 if index >= 0 else 1

        for i,node in enumerate(self.iternodes(flag),start):

            if i == abs(index):

                return node

 

    # def __setitem__(self, key, value):

    #     self.items[key] = value

    def __setitem__(self, key, value):

                   #self.items[key] = value   #X錯誤,self.items[key]的結果爲SingleNode的實例不能賦值,賦值得是實例.val=value,即self.items[key].val = value

        # node = self[key]   #self[key]利用了__getitem__(),同node = self.items[key];此處兩行可簡寫爲self[key].val = value

        # node.val = value

        self[key].val = value

 

ll = LinkedList()

node1 = SingleNode('abc')

ll.append(node1)

node2 = SingleNode(4)

ll.append(node2)

node3 = SingleNode(5)

ll.append(node3)

node4 = SingleNode(6)

ll.append(node4)

# ll.remove(3)

node5 = SingleNode('end')

ll.append(node5)

 

for node in ll.iternodes():

    print(node)

print('~'*20)

ll.pop()

node6 = SingleNode('head')

ll.insert(0,node6)

node7 = SingleNode('middle')

ll.insert(3,node7)

ll.remove(3)

# print(len(ll))

ll[2]=1

ll[-1]=3

ll[-2]=2

ll[0]='head1'

ll[0]=123

for node in ll:

    print(node)

# print(node7.next)   #None

 

 

 

2

 

class Property:

    def __init__(self,fget,fset=None):

        self.fget = fget

        self.fset = fset

 

    def __get__(self, instance, owner):

        if instance is not None:

            return self.fget(instance)

        return self

 

    def __set__(self, instance, value):

        if callable(self.fset):

            self.fset(instance,value)

        else:

            raise AttributeError('attribute error')

 

    def setter(self,fn):

        self.fset = fn

        return self

 

class A:

    def __init__(self,data):

        self._data = data

 

    @Property

    def data(self):

        return self._data

 

    @data.setter

    def data(self,value):

        self._data = value

 

a = A(100)

print(a.data)

a.data = 200

print(a.data)

輸出:

100

200

相關文章
相關標籤/搜索