1. 程式人生 > >python0.16------構造函數/析構函數/self詳解/重寫/訪問限制/對象屬性和類屬性/@property/運算符重載

python0.16------構造函數/析構函數/self詳解/重寫/訪問限制/對象屬性和類屬性/@property/運算符重載

動態添加 輸出 自然 表示 不可 spa type 錯誤 特點

構造函數:__init__()
引子:因為每個人一出生都是不一樣的。因此,如果在Person類中直接給類元素賦值有問題,它會導致每個人的初始狀態相同,這不符合大自然的邏輯。應該根據每個人的特點,給每個出生的人不一樣的特性。可以通過構造函數實現這個想法。__init__()函數在使用類創建對象自動調用。註意:如果不顯式寫出構造函數,默認會添加一個空的構造函數。

使用構造函數:
def __init__(self,name,age,height,weight):#一般定義屬性在構造函數裏面定義。
  self.name=name #self.name表示給當前對象創造一個屬性。
  self.age=age #self.age表示給當前對象創造一個屬性。


  self.height=height #self.height表示給當前對象創造一個屬性。
  self.weight=weight #self.weight表示給當前對象創造一個屬性。
  #當在person後面加實參時,實際上是調用了__init__()函數。

#調用

per1=Person(‘qie‘,18,180,60)。
per2=Person(‘bob‘,22,170,65)。
這樣,per1和per2在出生的時候就不一樣了。


析構函數:(編程時用得很少)
__del__() 表示釋放對象時自動調用。
對象釋放的原理:引用計數器原理。在創建對象的時候,有一個屬性num=1,當有一個地方要用它,就有一個強指針指向它,num+1,釋放一個強指針,num-1。當num為0時,系統自動釋放這個對象。然後會調用析構函數。


當程序結束時,對象會被釋放,會調用析構函數。
若強制釋放對象,用del指令。然後系統會調用析構函數。
再函數裏面定義的對象,會在函數結束時自動釋放,這樣可以用來減少內存空間的浪費。然後調用析構函數。

self詳解:
self不是關鍵字,self可以由任何標識符代替,但是一般都用self。
self代表類的實例而非類。
哪個對象調用方法,那麽該方法中的self就代表哪個對象。
self.__class__ 代表類名,只能在類的定義裏面使用哦
例如:
def run(self):
per=self.__class__(‘bob‘,1,1,1)
print(per)
表示在run方法裏面創建一個對象叫做per。


重寫

:將類定義的方法重新寫一遍。

引子:如果一個對象,有100個屬性,想把它們都打印出來,那麽一般來說應該寫成:print(per.a,per.b,per.c,per.d,..........,per.n100)。但是屬性太多,這樣輸出寫代碼很累。如果能夠用print(per)直接打印出所有屬性就好了。因此,重寫__str__()和__repr__()就能夠滿足要求.

例如:重寫__str__()和__repr__()方法
__str__()方法  #它是給程序員用的,在調用執行print(對象名)時會被自動調用。
__repr__() 方法  #它是給機器用的,在python解釋器裏直接敲對象名後回車調用的。例如:在黑屏終端裏面,直接敲per對象,就會調用__repr__()。

註意:1: __str__(),__repr__()需要返回值,返回值直接取代print裏面的per!!!同時,若是沒有定義__str__()方法,只定義了__repr__()方法,那麽調用print(per)時會調用__repr__()方法。

訪問限制:
如果我這個對象有100塊錢的屬性,如果在類的外面可以直接修改,那麽別人可以輕松篡改我的零錢金額。這樣顯然不合理.要讓對象的屬性不在外部直接訪問.那麽可以在屬性前面加上兩個下劃線。在python中如果在屬性前面加上兩個下劃線,那麽這個屬性就相當於變成了私有屬性(private)。在外部不能訪問私有變量,在類內部可以訪問私有變量。
可以在類裏面更改money,通過自定義的方法對私有屬性賦值和取值:
例如:一個類有一個私有變量__money
def getMoney(self):
  return __money
def setMoney(self,money):
  if money<0:
    self.__money=0
  else:
    self.__money=money

不能直接訪問 per.__money 是因為python解釋器把 __money 解釋成了 __Person__money ,若直接訪問__Person__money,就可以成功。但是強烈建議不要這麽做。而且不同版本的解釋器可能存在解釋的變量名不一致的憂患。

在python中 __XXX__ 屬於特殊變量,不是私有變量,特殊變量的值可以直接訪問。表示系統已經寫好了,有一些特殊的含義。

在python中 _XXX 變量,外部也是可以訪問的。但是,按照約定的規則,當我看到這樣的變量時。意思是‘雖然我可以被訪問,但是請把我視作為私有變量,不要直接訪問我。

對象屬性和類屬性:

類屬性:
class Person(object):
  name="person" #類屬性
  def __init__(self,name):
    self.name=name #對象屬性

對象屬性的優先級高於類屬性。不要將對象屬性與類屬性同名。因為對象屬性會屏蔽掉類屬性。但是當刪除對象屬性後,再使用又會調用類屬性。這樣類屬性就不可控。

可以動態的給對象添加對象屬性,只針對當前對象生效,對於類創建的其它對象沒有作用。
例如:
class Person:
  pass
  person=Person()
#動態添加屬性:
person.name=‘bob‘

#動態添加方法:
先引入types類的 MethodType()方法
from types import MethodType() #偏函數,相當於將對象自己傳進去
def say(self):
  print(‘my name is ‘+self.name)
per.speak=MethodType(say,per) #此時per對象就有了speak方法。其實MethodType()函數就是一個偏置函數,讓say函數self默認賦值為對象名,再將修改後的函數賦值給speak變量。

註:如果想要限制實例的屬性只允許為name,age,weight,其它的屬性不能添加。那麽在定義類的時候,可以定義一個特殊的屬性(__slots__)。可以限制動態添加的屬性。
例如:
class Person:
  __slots__=(‘name‘,‘age‘) #這樣只能動態地增加name,age兩個屬性,包括方法。例如:人不會飛,因此不能給人飛的方法。

property:
用 對象.屬性 訪問和改變對象屬性 比 對象.方法() 去改變和訪問對象的屬性要方便。
例如:
class Person:
  def __init__(self,age):
    self.__age=age
@property #訪問
def age(self):
  return self.__age
@age.setter #修改
def age(self):
  if self.__age<0
    self.__age=0
  else:
    self.__name=age

print(per.age)   #相當於getAge()
per.age=1   #相當於SetAge(1)
註意,這並不等於直接操作私有變量,因為私有變量的賦值是有限制的。

運算符重載(‘+’運算符重載最常用):

引子:print(1+2) 輸出3
print(‘1‘+‘2‘) 輸出‘12’  #說明不同類型用加法會有不同的解釋,也就是‘+‘運算符在不同類型的對象中有不同的作用,即‘+‘運算符在每個類裏面都進行了重載。

#然而,新建一個自定義的類person的實例,卻不能進行相加,為什麽呢?因為沒有進行運算符重載!!!
per1=person(1)
per2=person(2)
print(per1+per2)   #輸出錯誤,因為‘+‘沒有對person類型的解釋。

#解決方法:

def __add__(self,other):
  return Person(self.num+other.num)   #運算符重載,記住一定要返回一個值哦,這裏返回的是一個初始值為3的對象哦。
def __str__(self):
  return ‘num=‘str(self.num)    #重寫__str__()方法,目的是當調用print(對象)時,直接打印有關對象的一些值。

調用:print(per1+per2)等價於print(per1.__add__(per2))

python0.16------構造函數/析構函數/self詳解/重寫/訪問限制/對象屬性和類屬性/@property/運算符重載