python物件導向程式設計基礎

ckxllf發表於2019-12-05

  先看看物件導向-----在現如今的程式語言中大部分都已經具備了完善的物件導向思想。例如C++、java這兩大主流程式語言。這兩個是現如今使用量最大,且將物件導向發揮到極致的語言。

  python面向的物件最主要的類--而python類中最主要包括 欄位、方法、屬性

  先來看看如何建立一個python類

  class Pager:

  def __init__(self, current_page):

  # 使用者當前請求的頁碼(第一頁、第二頁...)

  self.current_page = current_page

  # 每頁預設顯示10條資料

  self.per_items = 10

  def start(self):

  val = (self.current_page - 1) * self.per_items

  return val

  def end(self):

  val = self.current_page * self.per_items

  return val

  tips: python中一個類只能有一個建構函式存在。定義多個構造方法時,例項化類只例項化最後的構造方法,

  即後面的構造方法會覆蓋前面的構造方法,並且需要更具最後一個構造方法的形式進行例項化

  接下來分片看看類中的三大將

  欄位分為------普通欄位 和 靜態欄位

  普通欄位-----(普通欄位屬於類物件擁有)

  靜態欄位-----(靜態欄位屬於當前類,靜態欄位在記憶體中只儲存一份;普通欄位在每個物件中都要儲存一份)

  class province:

  #靜態欄位

  country = "China"

  def __init__(self,name):

  #普通欄位

  self.name = name

  #訪問普通欄位方法

  obj = province("shan'xi")

  print(obj.name)

  #訪問靜態欄位方法

  print(province.country)

  方法分為------普通方法、靜態方法 和 類方法

  普通方法:由物件呼叫;至少一個self引數;執行普通方法時,自動將呼叫該方法的物件賦值給self;

  類方法: 由類呼叫;至少一個cls引數;執行類方法時,自動將呼叫該方法的類複製給cls;

  靜態方法:由類呼叫;無預設引數

  class testFun:

  #建構函式

  def __init__(self,name):

  self.name = name

  def orderFunc(self):

  """普通方法,至少一個self引數 """

  print("普通方法")

  @classmethod

  def classFunc(cls):

  """類方法,至少一個cls引數 """

  print("類方法")

  @staticmethod

  def staticmethod():

  """靜態方法,沒有預設引數 """

  print("靜態方法")

  #1.呼叫普通方法

  test = testFun("xi'an") #建立物件

  test.orderFunc()

  #2.呼叫類方法

  testFun.classFunc()

  #3.呼叫靜態方法

  testFun.staticmethod()

  屬性------類的普通方法的變種

  1:在普通方法的基礎上新增 @property 裝飾器;

  2:屬性僅有一個self引數;

  3:呼叫時,無需括號

  屬性存在意義:訪問屬性時可以製造出和訪問欄位完全相同的假象

  class testProtertyFun:

  #建構函式

  def __init__(self,name):

  self.name = name

  #定義屬性

  @property

  def propertyFunc(self):

  """屬性方法,至少一個self引數 """

  print("屬性方法")

  test = testProtertyFun("xi'an")

  #呼叫屬性

  test.propertyFunc

  再來看幾個案例,看看屬性和方法的區別到底在哪一塊

  #對某一個數值進行改變,計算其開始與結束後的值。

  class Pager:

  def __init__(self, current_):

  # 使用者當前請求的頁碼(第一頁、第二頁...)

  self.current_ = current_

  # 每頁預設顯示10條資料

  self.per_items = 10

  @property

  def start(self):

  val = (self.current_ - 1) * self.per_items

  return val

  @property

  def end(self):

  val = self.current_ * self.per_items

  return val

  # ############### 呼叫 ###############

  p = Pager(1)

  p.start #就是起始值,即:m

  p.end #就是結束值,即:n

  屬性兩種定義方式(裝飾器模式、靜態欄位)

  裝飾器方式:在類的普通方法上應用@property裝飾器

  tips:Python中的類有經典類和新式類,新式類的屬性比經典類的屬性豐富。( 如果類繼object,那麼該類是新式類 )

  經典類,具有一種@property裝飾器

  class Goods:

  @property

  def price(self):

  return "wupeiqi"

  obj = Goods()

  # 自動執行 @property 修飾的 price 方法,並獲取方法的返回值

  result = obj.price

  新式類,具有三種@property裝飾器

  #新式類,具有三種@property裝飾器

  class NewerPropertyClass:

  @property

  def Func1(self):

  print("@property")

  @property

  def Func2(self):

  pass

  #設定屬性裝飾器時,被設定的setter deleter必須有一個被property修飾的函式

  @Func2.setter

  def Func2(self,value):

  newvalue = value

  print("@property.setter")

  @Func2.deleter

  def Func3(self):

  print("@property.deleter")

  obj = NewerPropertyClass()

  obj.Func1 # 自動執行 @property 修飾的 Func1 方法,並獲取方法的返回值

  obj.Func2 = 123 # 自動執行 @price.setter 修飾的 Func2 方法,並將 123 賦值給方法的引數

  del obj.Func3 # 自動執行 @price.deleter 修飾的 Func3 方法

  tips:綜上新式類會將屬性設定為對同一個操作分為:獲取、修改、刪除. 而Setter必須有個引數,保證可以傳入引數值。且setter、deleter的函式必須有一個被@property修飾的函式

  靜態欄位模式-------當使用靜態欄位的方式建立屬性時,經典類和新式類無區別

  class Foo:

  def get_bar(self):

  return 'wupeiqi'

  #靜態欄位模式

  BAR = property(get_bar)

  obj = Foo()

  # 自動呼叫get_bar方法,並獲取方法的返回值

  reuslt = obj.BAR

  print(reuslt)

  property的構造方法中有個四個引數

  第一個引數是方法名,呼叫 物件.屬性 時自動觸發執行方法

  第二個引數是方法名,呼叫 物件.屬性 = XXX 時自動觸發執行方法

  第三個引數是方法名,呼叫 del 物件.屬性 時自動觸發執行方法

  第四個引數是字串,呼叫 物件.屬性.__doc__ ,此引數是該屬性的描述資訊

  看這個例子:

  class TestClass:

  def get_bar(self):

  print("get_bar")

  return ("wupeiqi")

  # *必須兩個引數

  def set_bar(self, value):

  print("set_bar:" + value)

  return ('set value' + value)

  def del_bar(self):

  value = 0

  print("del_bar:" + str(value))

  return (value)

  BAR = property(get_bar,set_bar,del_bar,"description...")

  obj = TestClass()

  obj.BAR # 自動呼叫第一個引數中定義的方法:get_bar

  obj.BAR = "alex" # 自動呼叫第二個引數中定義的方法:set_bar方法,並將“alex”當作引數傳入

  print(obj.BAR.__doc__)#呼叫 物件.屬性.__doc__ ,

  # 此引數是該屬性的描述資訊(此處呼叫需要放在del obj.BAR這句之前)

  del obj.BAR # 自動呼叫第三個引數中定義的方法:del_bar方法

  類成員的修飾符 (公有成員---私有成員)

  公有成員,在任何地方都能訪問

  私有成員,只有在類的內部才能方法;私有成員命名時,前兩個字元是下劃線 __(特殊成員除外,例如:__init__、__call__、__dict__等)

  如果想要強制訪問私有欄位,可以透過 【物件._類名__私有欄位明 】訪問(如:obj._C__foo),不建議強制訪問私有成員。

  靜態欄位:

  公有靜態欄位:類可以訪問;類內部可以訪問;派生類中可以訪問

  私有靜態欄位:僅類內部可以訪問

  訪問類的公有成員欄位

  class CClass:

  name = "公有靜態欄位"

  def func(self):

  print (CClass.name)

  class DClass(CClass): #DClass繼承CClass

  def show(self):

  print (CClass.name)

  CClass.name # 類訪問

  obj = CClass()

  obj.func() # 類內部可以訪問

  obj_son = DClass()

  obj_son.show() # 派生類中可以訪問

  訪問類的公有成員欄位

  class CClass:

  __name = "私有靜態欄位"

  def func(self):

  print (CClass.name)

  class DClass(CClass): #DClass繼承CClass

  def show(self):

  print (CClass.name)

  CClass.name # 類訪問==> 錯誤

  obj = CClass()

  obj.func() # 類內部可以訪問 ==> 正確

  obj_son = DClass()

  obj_son.show() # 派生類中可以訪問 ==> 錯誤

  普通欄位

  公有普通欄位:物件可以訪問;類內部可以訪問;派生類中可以訪問

  私有普通欄位:僅類內部可以訪問;

  訪問類的公有欄位

  class AClass:

  def __init__(self):

  self.foo="公有欄位"

  def func(self):

  print (self.foo) # 類內部訪問

  class BClass(AClass):

  def show(self):

  print (self.foo) #派生類中訪問

  obj = AClass()

  obj.foo # 透過物件訪問

  obj.func() # 類內部訪問

  obj_son = BClass();

  obj_son.show() # 派生類中訪問

  class AClass:

  def __init__(self):

  self.__foo = "私有欄位"

  def func(self):

  print (self.foo) # 類內部訪問

  class BClass(AClass):

  def show(self):

  print (self.foo) #派生類中訪問

  obj = AClass()

  obj.__foo # 透過物件訪問 ==> 錯誤

  obj.func() # 類內部訪問 ==> 正確

  obj_son = BClass();

  obj_son.show() # 派生類中訪問 ==> 錯誤

  方法、屬性的訪問於上述方式相似,即:私有成員只能在類內部使用;---非要訪問私有屬性的話,可以透過 物件._類__屬性名

  還有幾個類的特殊欄位需要清楚的

  1. __doc__ 表示類的描述資訊

  class Foo:

  """ 描述類資訊,這是用於看片的神奇 """

  def func(self):

  pass

  print (Foo.__doc__)

  #輸出:類的描述資訊

  2. __module__ 和 __class__

  __module__ 表示當前操作的物件在那個模組

  __class__ 表示當前操作的物件的類是什麼

  #!/usr/bin/env python

  # -*- coding:utf-8 -*-

  class C:

  def __init__(self):

  self.name = 'wupeiqi'

  from lib.aa import C

  obj = C()

  print (obj.__module__) # 輸出 lib.aa,即:輸出模組

  print (obj.__class__) # 輸出 lib.aa.C,即:輸出類

  3. __init__

  # 構造方法,透過類建立物件時,自動觸發執行。

  class Foo:

  def __init__(self, name):

  self.name = name

  self.age = 18

  obj = Foo('wupeiqi') # 自動執行類中的 __init__ 方法

  4. __del__

  析構方法,當物件在記憶體中被釋放時,自動觸發執行。

  #注:此方法一般無須定義,因為Python是一門高階語言,程式設計師在使用時無需關心記憶體的分配和釋放,因為此工作都是交給Python直譯器來執行,

  #所以,解構函式的呼叫是由直譯器在進行垃圾回收時自動觸發執行的。

  class Foo:

  def __del__(self):

  pass5. __call__

  # 物件後面加括號,觸發執行。

  #注:構造方法的執行是由建立物件觸發的,即:物件 = 類名() ;而對於 __call__ 方法的執行是由物件後加括號觸發的,即:物件() 或者 類()()

  class Foo:

  def __init__(self):

  pass

  def __call__(self, *args, **kwargs):

  print ('__call__')

  obj = Foo() # 執行 __init__

  obj() # 執行 __call__

  6. __dict__

  # 類或物件中的所有成員

  #上文中我們知道:類的普通欄位屬於物件;類中的靜態欄位和方法等屬於類,即

  class Province:

  country = 'China'

  def __init__(self, name, count):

  self.name = name

  self.count = count

  def func(self, *args, **kwargs):

  print ('func')

  # 獲取類的成員,即:靜態欄位、方法、

  print (Province.__dict__)

  # 輸出:{'country': 'China', '__module__': '__main__', 'func': , '__init__': , '__doc__': None}

  obj1 = Province('HeBei',10000)

  print (obj1.__dict__)

  # 獲取 物件obj1 的成員

  # 輸出:{'count': 10000, 'name': 'HeBei'}

  obj2 = Province('HeNan', 3888)

  print (obj2.__dict__)

  # 獲取 物件obj1 的成員

  # 輸出:{'count': 3888, 'name': 'HeNan'}

  7. __str__

  # 如果一個類中定義了__str__方法,那麼在列印 物件 時,預設輸出該方法的返回值。

  class Foo:

  def __str__(self):

  return 'wupeiqi'

  obj = Foo()

  print (obj)

  # 輸出:wupeiqi

  8、__getitem__、__setitem__、__delitem__

  #用於索引操作,如字典。以上分別表示獲取、設定、刪除資料

  #!/usr/bin/env python

  # -*- coding:utf-8 -*-

  class Foo(object):

  def __getitem__(self, key):

  print ('__getitem__',key)

  def __setitem__(self, key, value):

  print ('__setitem__',key,value)

  def __delitem__(self, key):

  print ('__delitem__',key)

  obj = Foo()

  result = obj['k1'] # 自動觸發執行 __getitem__

  obj['k2'] = 'wupeiqi' # 自動觸發執行 __setitem__

  del obj['k1'] # 自動觸發執行 __delitem__

  9、__getslice__、__setslice__、__delslice__

  # 該三個方法用於分片操作,如:列表

  #!/usr/bin/env python

  # -*- coding:utf-8 -*-

  class Foo(object):

  def __getslice__(self, i, j):

  print ('__getslice__',i,j)

  def __setslice__(self, i, j, sequence):

  print ('__setslice__',i,j)

  def __delslice__(self, i, j):

  print ('__delslice__',i,j)

  obj = Foo()

  obj[-1:1] # 自動觸發執行 __getslice__

  obj[0:1] = [11,22,33,44] # 自動觸發執行 __setslice__

  del obj[0:2] # 自動觸發執行 __delslice__

  10. __iter__

  #用於迭代器,之所以列表、字典、元組可以進行for迴圈,是因為型別內部定義了 __iter__

  #第一步

  class Foo(object):

  pass

  obj = Foo()

  for i in obj:

  print (i)

  # 報錯:TypeError: 'Foo' object is not iterable

  #第二步

  #!/usr/bin/env python

  # -*- coding:utf-8 -*-

  class Foo(object):

  def __iter__(self):

  pass

  obj = Foo()

  for i in obj:

  print (i)

  # 報錯:TypeError: iter() returned non-iterator of type 'NoneType'

  #第三步 鄭州做人流多少錢

  #!/usr/bin/env python

  # -*- coding:utf-8 -*-

  class Foo(object):

  def __init__(self, sq):

  self.sq = sq

  def __iter__(self):

  return iter(self.sq)

  obj = Foo([11,22,33,44])

  for i in obj:

  print (i)

  #以上步驟可以看出,for迴圈迭代的其實是 iter([11,22,33,44]) ,所以執行流程可以變更為:

  #!/usr/bin/env python

  # -*- coding:utf-8 -*-

  obj = iter([11,22,33,44])

  for i in obj:

  print (i)

  #For迴圈語法內部

  #!/usr/bin/env python

  # -*- coding:utf-8 -*-

  obj = iter([11,22,33,44])

  while True:

  val = obj.next()

  print (val)

  #11. __new__ 和 __metaclass__

  #閱讀以下程式碼:

  class Foo(object):

  def __init__(self):

  passobj = Foo() # obj是透過Foo類例項化的物件

  #上述程式碼中,obj 是透過 Foo 類例項化的物件,其實,不僅 obj 是一個物件,Foo類本身也是一個物件,因為在Python中一切事物都是物件。

  #如果按照一切事物都是物件的理論:obj物件是透過執行Foo類的構造方法建立,那麼Foo類物件應該也是透過執行某個類的 構造方法 建立。

  print (type(obj)) # 輸出: 表示,obj 物件由Foo類建立

  print (type(Foo)) # 輸出: 表示,Foo類物件由 type 類建立

  #所以,obj物件是Foo類的一個例項,Foo類物件是 type 類的一個例項,即:Foo類物件 是透過type類的構造方法建立。

  #那麼,建立類就可以有兩種方式:

  #a). 普通方式

  class Foo(object):

  def func(self):

  print ('hello wupeiqi')

  #b).特殊方式(type類的建構函式)

  def func(self):

  print ('hello wupeiqi')

  Foo = type('Foo',(object,), {'func': func})

  #type第一個引數:類名

  #type第二個引數:當前類的基類

  #type第三個引數:類的成員

  # 類 是由 type 類例項化產生

  #那麼問題來了,類預設是由 type 類例項化產生,type類中如何實現的建立類?類又是如何建立物件?

  #答:類中有一個屬性 __metaclass__,其用來表示該類由 誰 來例項化建立,所以,我們可以為 __metaclass__ 設定一個type類的派生類,從而檢視 類 建立的過程。

  class MyType(type):

  def __init__(self, what, bases=None, dict=None):

  super(MyType, self).__init__(what, bases, dict)

  def __call__(self, *args, **kwargs):

  obj = self.__new__(self, *args, **kwargs)

  self.__init__(obj)

  class Foo(object):

  __metaclass__ = MyType

  def __init__(self, name):

  self.name = name

  def __new__(cls, *args, **kwargs):

  return object.__new__(cls, *args, **kwargs)

  # 第一階段:直譯器從上到下執行程式碼建立Foo類

  # 第二階段:透過Foo類建立obj物件

  obj = Foo()


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69945560/viewspace-2667024/,如需轉載,請註明出處,否則將追究法律責任。

相關文章