26面向對象1_類方法-靜態方法-訪問控制-猴子補丁

 

目錄java

面向對象三要素:... 3python

類對象及類屬性:... 4c++

實例化:... 6編程

instance實例對象:... 10安全

裝飾一個類:... 13數據結構

類方法、靜態方法:... 14app

訪問控制:... 16ide

猴子補丁:... 19函數

 

 

 

面向對象this

 

語言的分類:

面向機器:

抽象成機器的指令,機器容易理解;

表明:彙編語言;

 

面向過程:

流程式,第1步,第2...

問題規模小,能夠步驟化,循序漸進處理;

表明:C語言;

 

面向對象:

隨着計算機須要解決的問題的規模擴大,狀況愈來愈複雜,須要不少人、不少部門協做,面向過程編程不太適合了;

表明:C++javapython

 

什麼是面向對象?

一種認識世界,分析世界的方法論,將萬事萬物抽象爲類;

 

class類,是抽象的概念,是萬事萬物的抽象,是一類事物的共同特徵的集合;

用計算機語言來描述類,就是屬性和方法的集合;

 

instance實例,或,object對象,是類的具象,是一個實體;

對於咱們每一個人這個個體,都是抽象概念人類的不一樣的實體;

例:

你吃魚:

你,就是對象;

魚,也是對象;

吃,就是動做;

你是具體的人,是具體的對象,你屬於人類,人類是個抽象的概念,是無數具體的個體的抽象;

魚也是具體的對象,就是你吃的這一條具體的魚,這條魚屬於魚類,是無數的魚抽象出來的概念;

 

注:

數據<-->屬性;

動做<-->方法;

屬性和方法的集合體;

python中函數和方法要加以區分;

屬性也決定着方法的多少,有一些方法是爲內部屬性做操做的,有一些方法是對外的;

項目有多複雜,數據結構就有多複雜;

類是數據和動做,即屬性和方法的集合;

抽象?(數據和動做的集合);

具象?

吃,是動做,是操做,也是方法,這個吃是你的動做,也就是人類具備的方法;若是反過來,魚吃人,吃就是魚類的動做了;

吃,這個動做,不少動物都具備,人類和魚類都屬於動物類,而動物類是抽象的概念,是動物都有吃的動做,但吃法不一樣而已;

你駕駛車,這個車是車類的具體的對象(實例),駕駛這個動做是魚類不具備的,是人類具備的方法;

 

屬性,是對象狀態的抽象,用數據結構來描述;

操做(方法),是對象行爲的抽象,用操做名和實現該操做的方法來描述;

 

每一個人都有名字、身高、體重等信息,這些信息是我的的屬性,但這些信息不能保存在人類中,由於人類是抽象的概念,不能保留具體的值;

而人類的實例,是具體的人,他能夠存儲這些具體的屬性,並且不一樣人有不一樣的屬性;

 

哲學:

一切皆對象;

對象是數據(屬性)和操做(方法)的封裝;

對象是獨立的,但對象之間可相互做用;

目前,面向對象是最接近人類認知的編程範式;

 

UMLunified modeling language,統一建模語言;

 

 

 

面向對象三要素:

1、封裝:

組裝:將數據和操做組裝到一塊兒;

隱藏數據:對外只暴露一些接口,經過接口訪問對象;(如駕駛員使用汽車,不須要了解汽車的構造細節,只須要知道使用什麼部件怎麼駕駛就行,踩了油門就能跑,能夠不瞭解背後的機動原理);

 

encapsulation封裝:

面向對象的三要素之一;

將數據和操做組織到類中,即屬性和方法;

將數據隱藏起來,給使用者提供操做,使用者經過操做就可獲取或修改數據,gettersetter

經過訪問控制,暴露適當的數據和操做給用戶,該隱藏的隱藏起來,保護成員或私有成員;

 

 

2、繼承:

多複用,繼承是爲了複用,繼承來的就不須要本身寫了;

多繼承少修改,ocpopen-closed-principle開閉原則,使用繼承來改變,來體現個性;

多繼承慎用,問題失控,計算機所用技術,簡單就是美的;

 

注:

函數複用,如yield from

 

3、多態:

面向對象編程最靈活的地方,動態綁定;

python運行時才綁定(知道)類型;

 

人類就是封裝;

人類繼承自動物類,孩子繼承父母的特徵,分爲單一繼承、多繼承;

多態,繼承自動物類的人類,貓類的操做「吃」不一樣;

其它語言的繼承、多態與python不同,僅封裝同樣;

 

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

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

 

 

 

python的類:

定義:

class ClassName:

         語句塊

必須使用class關鍵字;

類名必須用大駝峯(首字母大寫)命名,習慣,不是語法強制;

類定義完成後,就產生了一個類對象,綁定到了ClassName上;

 

注:

區分:類對象和類的對象;

 

例:

class MyClass:

    '''a example class'''

    x = 'abc'   #類屬性,另有對象屬性(類的實例的屬性)

    def foo(self):   #類屬性foo(單從標識符講,foo是類屬性),同時也是方法,self必須做爲第1個參數

        print(self.x)

        return 'My class'

 

print(MyClass)

print(type(MyClass))

print(MyClass.__name__)

print(MyClass.x)   #不是內存地址,高級語言對能簡化的就簡化了

print(MyClass.foo)   #內存地址

print(MyClass().foo())

print(MyClass.__doc__)

輸出:

<class '__main__.MyClass'>

<class 'type'>

MyClass

abc

<function MyClass.foo at 0x7f05be5370d0>

abc

My class

a example class

 

 

 

類對象及類屬性:

類對象,類的定義就會生成一個類對象;

 

類的標識符:

類的屬性,類中定義的變量和類中定義的方法都是類的屬性;

類變量,上例中xMyClass的變量;

 

MyClass中,xfoo都是類的屬性,__doc__也是類的屬性

foo方法是類的屬性,如同吃是人類的方法,可是每個具體的人才能吃東西,也就是說吃是人類的實例才能調用的方法;

foomethod方法對象,不是普通的function函數對象,它必須至少有一個參數,且第一個參數必須是selfself可換名字),這個參數位置就留給了self

 

self指代當前實例自己,self這個名字只是一個慣例,它能夠修改,但請不要修改,不然影響代碼的可讀性;

 

注:

inspect中,isfunction()ismethod()

 

def bar():

class MyClass:

         example = bar   #語法雖容許,但不要這樣寫,破壞了封裝,不符合編程規範,方法就寫在類內部

 

例:

class MyClass:

    '''a example class'''

    x = 'abc'

    def foo(self):

        # print(self.x)

        print(self)

        # return 'My class'

 

# print(MyClass)

# print(type(MyClass))

# print(MyClass.__name__)

# print(MyClass.x)

# print(MyClass.foo)

print(MyClass().foo())

# print(MyClass.__doc__)

print(MyClass.foo(1))   #不判斷self的類型,1None

 

mycls = MyClass()   #實例化、初始化

print(mycls.foo())   #對象調用方法,至關於悄悄的把mycls放入foo(mycls)

print(mycls.x)   #實例可拿走類屬性

print(mycls.foo)   #對象綁定方法

輸出:

<__main__.MyClass object at 0x7f338d4ff438>

None

1

None

<__main__.MyClass object at 0x7f338d4ff438>

None

abc

<bound method MyClass.foo of <__main__.MyClass object at 0x7f338d4ff438>>

 

例:

class MyClass:

    '''a example class'''

    x = 'abc'

    def foo(self):   #self可更名

        # print(self.x)

        # print(self)

        print(id(self))

        # return 'My class'

        # return self

 

mycls = MyClass()

print(mycls.foo())

# print(mycls.x)

# print(mycls.foo)

print(id(mycls))

輸出:

140426199077888

None

140426199077888

 

經常使用:

print(MyClass.x)

mycls = MyClass()

print(mycls.x)

print(mycls.foo())

 

 

 

實例化:

mycls = MyClass()

在類對象名稱後面加(),就調用類的實例化方法,完成實例化;

實例化,就真正建立一個該類的對象(實例),如人類的實例tom,jerry

實例化後,得到的實例,是不一樣的實例,即便是使用一樣的參數實例化,也獲得不同的對象;

python類實例化後,會自動調用__init__(self)方法,這個方法第一個參數必須留給self,其它參數隨意;

 

__init__(self)方法:

MyClass實際上調用的是__init__(self)方法,能夠不定義,若是沒有定義會在實例化後隱式調用;

做用:對實例進行初始化;

__init__(self)方法與其它方法不同,返回值只能是None,通常不寫返回值,若是寫return只能兩種:returnreturn None,其它形式一概報錯;

初始化函數能夠多個參數,第一個參數必須self

初始化函數也稱構造器,構造方法,僅初始化,構造實例是__new__方法;

 

另,__new__(cls,*args,**kwargs),用於構建實例,極少用,類方法;

 

__init__(self)方法,默認的語句是:

def __init__(self):

         pass

 

例:

class MyClass:

    '''this is a example class'''

    x = 123

    def __init__(self):

        print('init')   #自定義初始化

 

    def foo(self):

        return 'foo = {}'.format(self.x)

 

a = MyClass()

print(a.foo())

輸出:

init

foo = 123

 

例:

class MyClass:

    '''this is a example class'''

    def __init__(self):

        print('self in init = {}'.format(id(self)))   #self就是調用者,即實例對象c

c = MyClass()

print('c = {}'.format(id(c)))

輸出:

self in init = 140190037407448

c = 140190037407448

 

例:

class Person:

    x = 'abc'

    def __init__(self,name,age=18):

        self.name = name   #實例屬性,對象的屬性

        self.age = age

 

    def showage(self):

        print('{} is {}'.format(self.name,self.age))

 

tom = Person('tom')

jerry = Person('jerry',20)

print(tom.name,tom.age)

print(jerry.name,jerry.age)

print(tom.x,jerry.x)

輸出:

tom 18

jerry 20

abc abc

 

例:

class Person:

    x = 'abc'

    def __init__(self,name,age=18):

        self.name = name

        self.age = age

 

    def showage(self):

        print('{} is {}'.format(self.name,self.age))

 

tom = Person('tom')

# jerry = Person('jerry',20)

# print(tom.name,tom.age)

# print(jerry.name,jerry.age)

# print(tom.x,jerry.x)

# print(tom == jerry)

jerry = Person('tom')

print(tom.name,tom.age)

print(jerry.name,jerry.age)

print(tom == jerry)   #tomjerry是不一樣的個體,儘管初始化時參數同樣

print(tom is jerry)

輸出:

tom 18

tom 18

False

False

 

例:

class Person:

    x = 'abc'

    def __init__(self,name,age=18):

        self.name = name

        # self.age = age

        self.y = age

 

    def showage(self,x,y):   #showage中的形參yself.y不同,self.y是實例在外部使用時用的,y是形參

        print('{} is {}. {} {}'.format(self.name,self.y,x,y))

        self.y = x

        Person.x = x   #類中的全部方法,包括特殊__init__(self)方法,均可對類屬性或實例屬性進行修改

 

tom = Person('tom')

jerry = Person('jerry',20)

# print(tom.name,tom.age)

# print(jerry.name,jerry.age)

# print(tom.x,jerry.x)

# print(tom == jerry)

# jerry = Person('tom')

# print(tom.name,tom.age)

# print(jerry.name,jerry.age)

# print(tom == jerry)

# print(tom is jerry)

print(tom.y,jerry.y)

tom.showage(100,'a')

jerry.showage(200,'b')

print(tom.y,jerry.y)

print(Person.x)

print(x)   #當前做用域中沒有x,也說明xPerson類中封裝着,要訪問x前面要加限定,如Person.x

輸出:

18 20

Traceback (most recent call last):

tom is 18. 100 a

jerry is 20. 200 b

100 200

200

  File "/home/python/magedu/projects/cmdb/example_class_Person.py", line 29, in <module>

    print(x)

NameError: name 'x' is not defined

 

 

 

instance實例對象:

類初始化後必定會得到一個對象,就是實例對象;

tomjerry就是Person類的實例;

__init__方法的第一個參數self,就是指代某一個實例;

類實例化出一個實例對象,實例對象會綁定方法,調用方法時採用jerry.showage()的方式;

在定義showage(self)時,不能少了self,這個self就是jerrypython會把方法的調用者做爲第一個參數self的實參傳入;

self.name就是jerry對象的namename是保存在了jerry對象上,而不是Person類上,因此稱爲實例變量

 

實例變量是每個實例本身的變量,是本身獨有的;

類變量是類的變量,是類的全部實例共享的屬性和方法;

 

類屬性保存在類的__dict__中;

實例屬性保存在實例的__dict__中;

若是從實例訪問類的屬性,須要藉助__class__找到所屬的類;

 

特殊屬性:

__name__,對象名;

__class__,對象的類型,python3__class__type()結果同樣;

__dict__,對象的屬性的字典;

__qualname__,類的限定名;

 

總結:

是類的,也是這個類全部實例的,其實例均可以訪問到類中定義的屬性和方法;是類的,就是你們的

是實例的,就是這個實例本身的,經過類訪問不到;是實例的,就是個體的

類變量,是屬於類的變量,這個類的全部實例能夠共享這個變量;

實例能夠動態的給本身添加或刪除一個屬性,實例.__dict__['變量名']實例.變量名均可訪問到;也可動態添加類方法,這些會破壞封裝,不要這麼作,雖語法容許,但從設計角度很差;

實例的變量會隱藏與其同名的類的變量(遮蓋),或者說是覆蓋了類變量;

 

實例屬性的查找順序:

實例使用.點來訪問屬性,會先找本身的__dict__

若是沒有,而後經過屬性__class__找到本身的類,再去類的__dict__中找;

若是實例使用__dict__['變量名']來訪問(直接翻字典),將不會按照上面的查找順序找變量;

 

通常類變量使用全大寫來命名;

tom.__class__.__dict__等價於Person.__dict__

 

例:

class Person:

    age = 18   #類變量,一般是一常量,不多用

    def __init__(self,name):

        self.name = name   #編程中,大量用的是實例變量,而不是類變量

 

# tom = Person('tom',20)   #X

tom = Person('tom')   #初始化、實例化

jerry = Person('jerry')

print(tom.name,tom.age)

print(jerry.name,jerry.age)

print(Person.age)

# print(Person.name)   #X

Person.age = 30   #在外部修改類屬性

print(tom.age,jerry.age,Person.age)

 

print(Person.__dict__)   #__weakref__弱引用,用.點查找屬性

print(tom.__dict__)   #每一個對象保存着本身的屬性,全部對象的操做方法是同樣的,無非是數據不同(傳入的參數不同)

print(jerry.__dict__)

print(tom.__dict__['name'])

 

print(sorted(Person.__dict__.items()),end='\n')

print(sorted(tom.__dict__.items()),end='\n')

 

# print(tom.__qualname__)   #某一對象並不擁有全部特殊屬性

print(tom.__class__.__qualname__,jerry.__class__.__qualname__)

print(isinstance(jerry,tom.__class__))

print(int.__class__)

print(Person.__class__)

print(isinstance(tom,int.__class__))

輸出:

tom 18

jerry 18

18

30 30 30

{'__module__': '__main__', 'age': 30, '__init__': <function Person.__init__ at 0x7f7b63da20d0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

{'name': 'tom'}

{'name': 'jerry'}

tom

[('__dict__', <attribute '__dict__' of 'Person' objects>), ('__doc__', None), ('__init__', <function Person.__init__ at 0x7f7b63da20d0>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Person' objects>), ('age', 30)]

[('name', 'tom')]

Person Person

True

<class 'type'>

<class 'type'>

False

 

例:

class Person:

    age = 3

    height = 170

    def __init__(self,name,age=18):   #方法中的第一個參數self,表示bound了對象(實例)

        self.name = name

        self.age = age

 

tom = Person('tom')

jerry = Person('jerry',20)

 

Person.age = 30

print(Person.age,tom.age,jerry.age)

print(Person.__dict__,tom.__dict__,jerry.__dict__,sep='\n')

print(Person.height,tom.height,jerry.height)

Person.height += 20

print(Person.height,tom.height,jerry.height)

print(Person.__dict__,tom.__dict__,jerry.__dict__,sep='\n')

 

tom.height = 168

print(Person.height,tom.height,jerry.height)

print(Person.__dict__,tom.__dict__,jerry.__dict__,sep='\n')

 

jerry.height += 20

print(Person.height,tom.height,jerry.height)

print(Person.__dict__,tom.__dict__,jerry.__dict__,sep='\n')

 

Person.weight = 70   #動態添加(刪除)屬性,靈活之處,也可動態添加方法,這些會破壞封裝,不要這麼作

print(Person.weight,tom.weight,jerry.weight)   #先找本身的__dict__,找不到再經過__class__找類中的__dict__,類中也沒有拋異常KeyError

print(tom.__dict__['weight'])   #XKeyError

輸出:

30 18 20

{'__module__': '__main__', 'age': 30, 'height': 170, '__init__': <function Person.__init__ at 0x7f9f7aad40d0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

{'name': 'tom', 'age': 18}

{'name': 'jerry', 'age': 20}

170 170 170

190 190 190

{'__module__': '__main__', 'age': 30, 'height': 190, '__init__': <function Person.__init__ at 0x7f9f7aad40d0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

{'name': 'tom', 'age': 18}

{'name': 'jerry', 'age': 20}

190 168 190

{'__module__': '__main__', 'age': 30, 'height': 190, '__init__': <function Person.__init__ at 0x7f9f7aad40d0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

{'name': 'tom', 'age': 18, 'height': 168}

{'name': 'jerry', 'age': 20}

190 168 210

{'__module__': '__main__', 'age': 30, 'height': 190, '__init__': <function Person.__init__ at 0x7f9f7aad40d0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

{'name': 'tom', 'age': 18, 'height': 168}

{'name': 'jerry', 'age': 20, 'height': 210}

70 70 70

Traceback (most recent call last):

  File "/home/python/magedu/projects/cmdb/example_class_var.py", line 29, in <module>

    print(tom.__dict__['weight'])

KeyError: 'weight'

 

 

 

裝飾一個類:

不是類裝飾器;

需求:爲一個類經過裝飾,增長一些類屬性;

用於老項目,不動類定義,經過裝飾器動態的添加類屬性;

 

def setnameproperty(name):

    def wrapper(cls):

        cls.NAME = name

        return cls

    return wrapper

 

@setnameproperty('MYCLASS')   #MyClass = setnameproperty('MYCLASS')(MyClass)

class MyClass:

    pass

 

print(MyClass.__dict__)

輸出:

{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None, 'NAME': 'MYCLASS'}

 

 

 

類方法、靜態方法:

類方法,用裝飾器@classmethod,在定義時,第1個參數留給類自己,如def clsmtd(cls),與類bound(相似對象方法,第1個參數self,與實例bound);

類中普通方法,def bar(),雖語法容許,不推薦使用,若非要不帶參數,用靜態方法替代;

靜態方法,用裝飾器@staticmethod

 

python中類方法,至關於其它語言的靜態方法;javac++中的靜態方法指的是python中的類方法;

 

類方法,如datetime.datetime(...)建立時間對象;

靜態方法,從概念上歸類管轄,實際使用能夠與類沒有關係,不多用;

 

__init__()等方法,這些自己都是類的屬性,第一個參數必須是self,而self必須指向一個對象,即類必須實例化後,由實例來調用這個方法;

 

普通方法:

MyClass.bar(),先查看MyClass.__dict__,這個方法只是被MyClass這個名詞空間管理的一個普通的方法,barMyClass的一個屬性而已,因爲bar在定義時沒有指定self,這樣即沒有完成與實例對象的綁定,不能用a.bar()MyClass().bar()調用,這種雖語法對,但沒人這麼用,禁止這樣定義def bar()

 

類方法:

在類定義中,用@classmethod裝飾器修飾的方法;

pycharm中,定義時會自動補全cls參數,必須至少有一個參數,且第一個參數留給了clscls指代調用者即對象自身;

cls這個標識符能夠是任意合法名稱,可是爲了易讀,請不要修改;

經過cls可直接操做類的屬性,沒法經過cls操做類的實例;

類方法,相似c++java中的靜態方法;

 

靜態方法:

在類定義中用@staticmethod裝飾器修飾的方法;

調用時,不會隱式的傳入參數

靜態方法,只是代表這個方法屬於類這個名詞空間,函數歸在一塊兒,方便組織管理;

 

注:

實例可調用類中定義的方法(包括類方法、靜態方法),靜態方法和類方法須要找到實例的類;

實例不可調用類中的普通方法,如a.bar(),解釋器會自動將a傳到bar(a)內,而bar在定義時沒有self,即沒有綁定實例;

 

例:

class MyClass:

    XXX = 'xxx'

    def __init__(self):

        print('init')

 

    def foo(self):

        print('foo')

 

    def bar():

        print('bar')

 

    @classmethod

    def clsmtd(cls):   #類方法,cls爲類自己,或是實例的類

        print('{},xxx={}'.format(cls.__name__,cls.XXX))

 

    @staticmethod

    def staticmtd():

    # def staticmtd(x):

        print('static')

 

a = MyClass()

a.foo()

MyClass.bar()   #V,能夠這樣用,bar是在MyClass類下定義的

# a.bar()   #Xfoobar都是functionbar中形參沒有self,爲類中的普通函數,這樣調用會自動把a做爲形參傳入到bar(a)會出錯

print(MyClass.__dict__)

 

MyClass.clsmtd()   #a.foo(),會將類自己MyClass傳入clsmtd(MyClass)類方法的第一個參數

a.clsmtd()   #是類的,就是你們的,因此實例能夠用,至關於a.__class__.clsmtd()

 

MyClass.staticmtd()   #V

a.staticmtd()   #是類的,就是你們的

# a.staticmtd(4)

 

輸出:

init

foo

bar

{'__module__': '__main__', 'XXX': 'xxx', '__init__': <function MyClass.__init__ at 0x7f97c11f30d0>, 'foo': <function MyClass.foo at 0x7f97c11f3158>, 'bar': <function MyClass.bar at 0x7f97c11f3488>, 'clsmtd': <classmethod object at 0x7f97c11f5c18>, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}

MyClass,xxx=xxx

MyClass,xxx=xxx

static

static

 

例:

class Person:

    @classmethod

    def cls_method(cls):

        print('class = {0.__name__} ({0})'.format(cls))

        cls.HEIGHT = 170   #可操做類的屬性,不能操做實例的屬性

 

    @staticmethod

    def static_method():

        print(Person.HEIGHT)

 

Person.cls_method()

print(Person.__dict__)

Person.static_method()

輸出:

class = Person (<class '__main__.Person'>)

{'__module__': '__main__', 'cls_method': <classmethod object at 0x7fdfe7ec4710>, 'static_method': <staticmethod object at 0x7fdfe7ec9400>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, 'HEIGHT': 170}

170

 

 

 

訪問控制:

private,私有屬性,雙下劃線開頭的屬性名;

私有變量的本質:類定義的時候,若是聲明一個實例變量使用雙下劃線開頭,python解釋器會將其更名,轉換名稱爲_類名__變動名,因此在外部用原來的名字(__age)訪問不到了,但仍可經過__dict__訪問或修改;其它語言不是這樣,是確確實實看不到,python中仍然可在外部經過_Person__age訪問或修改;

 

保護變量

在變動名前加一個下劃線,查看__dict__,解釋器不作任何特殊處理,這只是開發者共同的約定,看見這種變量,就如同私有變量,不要直接使用;

 

私有方法

雙下劃線開頭的方法,解釋器會更名,更名策略和私有變量相同,_類名__方法名;

單下劃線的方法,只是開發者之間的約定,解釋器不做任何改變;

方法變量都在類的__dict__中可找到;

 

私有成員的總結:

python中使用___來標識一個成員被保護或被私有化隱藏起來,可是無論使用什麼樣的訪問控制,都不能真正的阻止用戶修改類的成員,python中沒有絕對的安全的保護成員或私有成員;

所以前導的下劃線只是一種警告或提醒,請遵照這個約定,除非真有必要,不要修改或者使用保護成員或私有成員;

以上是在類中使用___,若是是在函數中使用則不起做用;

 

publicprotectprivate,其它語言的訪問控制,而python中的訪問控制只是假象;

 

例:

class Person:

    def __init__(self,name,age=18):

        self.name = name

        self.age = age

 

    def growup(self,incr):

        if 0 < incr < 150:   #控制邏輯

            self.age += incr

 

tom = Person('tom')

tom.growup(20)

tom.age = 160   #未用私有屬性,會繞過控制邏輯,外部可見,外部可定義和修改,越過咱們定義的範圍

print(tom.age)

輸出:

160

 

例:

class Person:

    def __init__(self,name,age=18):

        # self.name = name

        self._name = name

        # self.age = age

        self.__age = age   #對象字典中的key表現爲_Person__age,自動對應的

 

    def growup(self,incr):

        if 0 < incr < 150:

            # self.age += incr

            self.__age += incr

 

    def getage(self):

        return self.__age

 

tom = Person('tom')

tom.growup(2)

# tom.age = 160

# print(tom.age)

# print(tom.__age)   #X,不能直接訪問私有屬性,報AttributeError: 'Person' object has no attribute '__age'

print(tom.getage())   #經過方法訪問私有屬性,沒多大用處

 

print(Person.__dict__)

print(tom.__dict__)

 

tom._Person__age = 200   #破壞封裝

print(tom.getage())

 

tom.__age = 300   #破壞封裝,從新定義的__age,與對象字典的_Person__age不是同一個key,不會被覆蓋

print(tom.getage())

print(tom.__dict__)

print(tom.__age)

 

輸出:

20

{'__module__': '__main__', '__init__': <function Person.__init__ at 0x7fde68b150d0>, 'growup': <function Person.growup at 0x7fde68b15158>, 'getage': <function Person.getage at 0x7fde68b15488>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

{'_name': 'tom', '_Person__age': 20}

200

200

{'_name': 'tom', '_Person__age': 200, '__age': 300}

300

tom

{'_name': 'tom', '_Person__age': 200, '__age': 300}

 

 

 

猴子補丁:

可經過修改或者替換類的成員;

使用者調用的方式沒有改變,但類提供的功能可能已經改變了;

適用於上線後的緊急或臨時修復上,通常下次變動時會合併到代碼中;

 

monkey patch,猴子補丁,在運行時對屬性進行動態替換;

黑魔法,慎用;

 

類方法中的名字,get*讀,set*寫,慣例;

 

例:

使用monkey patch,替換getscore方法,返回模擬的數據;

 

test2.py

class Person:

    def __init__(self,chinese,english,history):

        self.chinese = chinese

        self.english = english

        self.history = history

 

    def getscore(self):

        return self.chinese,self.english,self.history

 

test3.py

def getscore(self):

    return dict(chinese=self.chinese,english=self.english,history=self.history)

 

test1.py

from test2 import Person

from test3 import getscore

 

def monkeypatch4Person():

    Person.getscore = getscore

 

stu1 = Person(80,90,88)

print(stu1.getscore())

 

monkeypatch4Person()

 

stu2 = Person(70,80,90)

print(stu2.getscore())

輸出:

(80, 90, 88)

{'chinese': 70, 'english': 80, 'history': 90}

相關文章
相關標籤/搜索