1. 程式人生 > >python3之面向對象

python3之面向對象

ret 比較 classname 索引 __add__ zhang -- parent 裝飾器

1、面向對象術語

  • 類(Class): 用來描述具有相同的屬性和方法的對象的集合。它定義了該集合中每個對象所共有的屬性和方法。對象是類的實例。
  • 類屬性(類變量):類屬性在整個實例化的對象中是公用的。類屬性定義在類中且在函數體之外。類變量通常不作為實例變量使用。
  • 數據成員:類變量或者實例變量用於處理類及其實例對象的相關的數據。
  • 方法重寫:如果從父類繼承的方法不能滿足子類的需求,可以對其進行改寫,這個過程叫方法的覆蓋(override),也稱為方法的重寫。
  • 實例變量:定義在方法中的變量,只作用於當前實例的類。
  • 繼承:即一個派生類(derived class)繼承基類(base class)的字段和方法。繼承也允許把一個派生類的對象作為一個基類對象對待。例如,有這樣一個設計:一個Dog類型的對象派生自Animal類,這是模擬"是一個(is-a)"關系。
  • 實例化:創建一個類的實例,類的具體對象。
  • 方法:類中定義的函數。
  • 對象:通過類定義的數據結構實例。對象包括兩個數據成員(類變量和實例變量)和方法。

2、類定義

Python中的類提供了面向對象編程的所有基本功能:類的繼承機制允許多個基類,派生類可以覆蓋基類中的任何方法,方法中可以調用基類中的同名方法。

對象可以包含任意數量和類型的數據。

class test(object):   #定義一個類,在3.5中必須指定基類object
    i = 123       #類變量
    def func(self):   #類方法
        print(第一個類
) return hell python s = test() #通過類實例化對象 str = s.func() #對象調用類方法 print(test.i) #通過類名調用類變量 print(str) #類返回值 #output 第一個類 123 hell python

類實例化後,可以使用其屬性,實際上,創建一個類之後,可以通過類名訪問其屬性和方法;實例化類後可以使用其屬性,也可以動態的為實例對象添加屬性而不影響類對象。

可以使用點(.)來訪問對象的屬性,也可以使用函數的方式來訪問屬性:

class A(object):
    
def __init__(self,x): self.x = x def static_func(y=5): print(y) d = A(10) #類實例化對象 print(getattr(d,x)) #getattr訪問對象的屬性 print(hasattr(d,x)) #hasattr檢查對象屬性是否存在 print(setattr(d,y,zhang)) #設置對象的屬性,如果屬性不存在則創建新屬性 print(d.y) #打印實例對象屬性值 delattr(d,y) #defattr刪除對象屬性 print(hasattr(d,x)) #output 10 True None zhang True

python3內置類屬性:

__dict__:類的屬性(包含一個字典,由類的數據屬性組成)

__doc__:類的文檔字符串

__name__:類名

__module__:類定義所在的模塊(類的全名是‘__main__.className’,如果類位於一個導入模塊mymod中,那麽className.__module__等於mymod)

__bases__:類的所有父類構成元素(包含了以上所有父類組成的元組)

class myclass(object):
    class_n = foo
    def __init__(self,x,y,z):
        self.x = x
        self.y = y
        self.z = z
    def func_class(self):
        print(out:,self.x,self.y,self.z)

t = myclass(10,20,50)
t.func_class()   #調用實例方法

print(__dict__:,myclass.__dict__)   #返回類的屬性
print(__dict__:,t.__dict__)   #返回實例屬性
print(__name__:,myclass.__name__)  #返回類名
print(__doc__:,myclass.__doc__)   
print(__module__:,myclass.__module__)  #返回類屬在的模塊
print(__mro__:,myclass.__mro__)   
print(__bases__:,myclass.__bases__)  #返回類對象


#output
out: 10 20 50
__dict__: {__init__: <function myclass.__init__ at 0x0000004249F0F378>, __doc__: None, func_class: <function myclass.func_class at 0x0000004249F0F400>, class_n: foo, __dict__: <attribute __dict__ of myclass objects>, __module__: __main__, __weakref__: <attribute __weakref__ of myclass objects>}
__dict__: {x: 10, z: 50, y: 20}
__name__: myclass
__doc__: None
__module__: __main__
__mro__: (<class __main__.myclass>, <class object>)
__bases__: (<class object>,)

類的專有方法:

  • __init__ 構造函數,在生成對象時調用

  • __del__ 析構函數,釋放對象時使用

  • __repr__ 打印,轉換

  • __setitem__按照索引賦值

  • __getitem__按照索引獲取值

  • __len__獲得長度

  • __cmp__比較運算

  • __call__函數調用

  • __add__加運算

  • __sub__減運算

  • __mul__乘運算

  • __div__除運算

  • __mod__求余運算

  • __pow__乘方

__init__()方法是一種特殊的方法,被稱為類的構造函數或初始化方法,當創建了這個類的實例時就會調用該方法,類定義了__init__()方法後,類的實例化操作會自動調用__init__()方法,__init__()可以由參數,會傳遞到類的實例化操作上。

self代表類的實例,而非類本身,在類的內部,使用def關鍵字來定義一個方法,與一般函數定義不同,類方法必須包含self,且為第一個參數,self代表的是類的實例。

class test(object):
    def __init__(self,name,age,salary):  #初始化類屬性
        self.name = name
        self.age = age
        self.salary = salary   #實例化對象會將類初始化到實例對象上

    def buygo(self):
        print(%s的工資是%s元 %(self.name,self.salary))  #調用類屬性

#通過類實例化對象
zhansan = test(zhansan,20,8888)
lisi = test(lisi,22,6000)
#調用類方法
zhansan.buygo()
lisi.buygo()


#output:
#zhansan的工資是8888元
#lisi的工資是6000元
class test1(object):
    a = 10
    b = 20
    def get(self):
        print(取冪:,self.a.__pow__(self.b))
        print(求余數:,self.b.__mod__(self.a))
        print(乘:,self.b.__mul__(self.a))
        print(減:,self.b.__sub__(self.a))
        print(加:,self.b.__add__(self.a))
        print(輸出:,self.b.__repr__())

d = test1()
d.get()

#output
取冪: 100000000000000000000
求余數: 0
乘: 200
減: 10
加: 30
輸出: 20

實例方法,類方法,靜態方法,類屬性,實例屬性:

#實例方法,就是類的實例能夠使用的方法
class myclass(object):
    def __init__(self,name):
        self.name = name
    def instancefunc(self):
        print(調用實例方法%s%self.name)


if __name__ == "__main__":
    inst = myclass(zhangsan)   #通過類創建實例
    inst.instancefunc()   #實例使用實例方法
    myclass.instancefunc(inst)  #類使用實例方法,需要傳遞實例參數
#類方法是將類本身作為對象進行操作的方法,類方法使用@classmethod裝
#飾器定義,其第一個參數是類,約定為cls,也可以自己定義,類對象和實例
#都可以調用類方法,類方法只能調用類屬性,不能調用實例屬性。

class A(object):
    number = 10   #定義類屬性
    def __init__(self,name):   #初始化類屬性
        self.name = name
    def car(self):   #定義實例方法
        print(實例方法:%s%self.name)
    @classmethod   #定義類方法
    def cat(cls):  
        print(類方法:%s%cls.number)  #此處不能調用類屬性name,只能調用類屬性number

d = A(sb)
d.car()   #實例調用實例方法
d.cat()  #實例調用類方法
A.cat()  #類調用類方法

#output
實例方法:sb
類方法:10
類方法:10
#靜態方法是一種普通函數,就位於類定義的命名空間中,它不會對任何實例類
#型進行操作。使用裝飾器@staticmethod定義靜態方法。類對象和實例都可
#以調用靜態方法,靜態方法不能調用類屬性和實例屬性,但可以調用傳參。

class A(object):
    number = 10
    def __init__(self,name):
        self.name = name
    def car(self):
        print(實例方法:%s%self.name)
    @staticmethod   #定義靜態方法
    def cat(x,y):    #定義調用傳參
        print(靜態方法:%s%(x*y))

d = A(sb)   #實例化類
d.car()   #實例方法
d.cat(5,4)   #實例調用靜態方法
A.cat(6,3)   #類調用靜態方法

#output
實例方法:sb
靜態方法:20
靜態方法:18
#類屬性與實例屬性在實例方法,類方法,靜態方法中的調用關系
class A(object):
    number = 10   #定義類屬性
    def __init__(self,name):
        self.name = name   #實例屬性
    def car(self):  #實例方法可以調用類屬性和實例屬性
        print(實例方法:%s[%s]%(self.name,self.number))
    @classmethod
    def cae(cls):   #類方法只能調用類屬性
        print(類方法:%s%cls.number)

    @staticmethod
    def cat(x,y):   #靜態方法不能調用類屬性和實例屬性
        print(靜態方法:%s%(x*y))

d = A(sb)
d.car()
A.car(d)
d.cae()  #實例調用方法
A.cae()  #類調用方法
d.cat(5,4)
A.cat(6,3)

#output
實例方法:sb[10]
實例方法:sb[10]
類方法:10
類方法:10
靜態方法:20
靜態方法:18

3、類的封裝

封裝是面向對象的特征之一,是對象和類概念的主要特性。

封裝,也就是把客觀事物封裝成抽象的類,並且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。

python通過變量名命名來區分屬性和方法的訪問權限,默認權限相當於c++和java中的public

類的私有屬性: __private_attrs:兩個下劃線開頭,聲明該屬性為私有,不能在類地外部被使用或直接訪問。在類內部的方法中使用時self.__private_attrs

類的私有方法:__private_method:兩個下劃線開頭,聲明該方法為私有方法,不能在類地外部調用。在類的內部調用 self.__private_methods

class myclass(object):
    def __init__(self,name,age):  #構造方法,根據類創建對象時自動執行
        self.name = name
        self.age = age
    def func(self):
        print(%s今年%s%(self.name,self.age))

#根據類創建對象,會自動執行類的__init__方法
obj1 = myclass(zs,18)  #會將zs和18分別封裝到類的self的name和age屬性中
obj2 = myclass(ls,20)

print(obj1.name,obj1.age) #直接調用obj1對象的屬性
print(obj2.name,obj2.age)

obj1.func() #默認會將obj1傳遞給self參數,即:obj1.func(obj1),所以此方法的內部self=obj1,self.name是zs
obj2.func()

#output
zs 18
ls 20
zs今年18
ls今年20
class fater(object):
    __name = 私有屬性
    age = "公有屬性"
    def func(self):
        print(self.age)
        print(self.__name)
    def __foo(self):   #定義私有方法
        print(self.__name)
class son(fater):
    def show(self):
        print(fater.age)
        #print(fater.__name)

print(fater.age)    
print(----------------)

obj1 = fater()
obj1.func()
print(----------------)
#obj1.__foo()   #直接調用會報錯,只有通過"_類名__方法"的形式調用
obj1._fater__foo()  #調用私有方法
print(obj1.age)
#print(obj1.__name)  #直接調用會報錯,通過“_類名__屬性”方法調用
print(obj1._fater__name)  #調用私有屬性

print(-------son----)
obj2 = son()
obj2.show()  #調用父類屬性
obj2.func()
obj2.__foo()  #調用父類方法錯誤
obj2._fater__foo()  #正確調用父類方法

#output
公有屬性
----------------
func: 公有屬性
func: 私有屬性
----------------
__foo: 私有屬性
公有屬性
私有屬性
-------son----
show: 公有屬性
func: 公有屬性
func: 私有屬性
__foo: 私有屬性

4、類繼承

繼承是面向對象的重要特征之一,繼承是兩個類或者多個類之間的父子關系,子類繼承了父類的所有公有實例變量和方法。
繼承實現了代碼的重用。重用已經存在的數據和行為,減少代碼的重新編寫。
python在類名後用一對圓括號表示繼承關系,括號中的類表示父類或基類
#經典類和新式類的區別:當前類或者父類繼承了object類,那麽該類便是新式類,否則便是經典類。
class old:   #經典類寫法
    pass


class new(object):  #新式類寫法
    pass

在python中類繼承的特點:

1:在繼承中基類的構造(__init__()方法)不會被自動調用,它需要在其派生類的構造中親自專門調用。使用super().__init__()或parentClassName.__init__()

2:在調用基類的方法時,需要加上基類的類名前綴,且需要帶上self參數變量。區別於在類中調用普通函數時並不需要帶上self參數

3:Python總是首先查找對應類型的方法,如果它不能在派生類中找到對應的方法,它才開始到基類中逐個查找。(先在本類中查找調用的方法,找不到才去基類中找)。

如果在繼承元組中列了一個以上的類,那麽它就被稱作"多重繼承" 。

class test(object):   #定義父類
    def __init__(self,name,age,salary):
        self.name = name
        self.age = age
        self.salary = salary

    def buygo(self):
        print(%s[%s]歲就有%s元的工資了 %(self.name,self.age,self.salary))

class test_student(test):   #調用父類
    def __init__(self,name,age,salary,nb):  
        test.__init__(self,name,age,salary)  #重寫父類構造方法
        self.nb = nb
    def buygo(self):   #覆寫類方法
        print(%s[%s]歲就有%s元的工資了,很%s %(self.name,self.age,self.salary,self.nb))


#通過類實例化對象
zhansan = test_student(zhansan,20,8888,牛逼哦)
lisi = test_student(lisi,22,6000,得瑟吧)

zhansan.buygo()
lisi.buygo()

#output:
zhansan[20]歲就有8888元的工資了,很牛逼哦
lisi[22]歲就有6000元的工資了,很得瑟吧

如果父類中的方法名相同於子類中的方法名,子類方法將覆蓋父類方法。

多繼承的優先級順序是:在新式類中是從左往右查找,找到即停止;而經典類是深度查找的從左到右如:A(B,C),B(D),那麽順序是A->B->D->C

5、多態

多態依賴於繼承,多態的作用,就是為了類在繼承和派生的時候,保證繼承類中實例的某個屬性或方法的調用,實現了接口的重用。class A(object): def __init__(self):

        self.name = ZHANGSAN
    def show(self):
        print(A.show:,self.name)
class B(A):
    def show(self):
        print(show_b:,self.name)
class C(A):
    def show(self):
        print(show_c:,self.name)

def func(obj):   #定義函數,傳遞對象
    obj.show()   #通過類實例對象調用類下的方法

A_obj = A()
B_obj = B()
C_obj = C()

func(A_obj)
func(B_obj)
func(C_obj)

#output

A.show: ZHANGSAN
show_b: ZHANGSAN
show_c: ZHANGSAN

 

6、總結

  • 面向對象的知識總計如下:
  • 面向對象時一個編程方式,此編程方式的實現是基於對類和對象的使用
  • 類是一個模版,模版中包裝了多個‘函數’供使用
  • 對象根據模塊創建實例,實例可以調用被包裝在類中的函數
  • 繼承實現了多個類直接的方法屬性調用,減少代碼的重用性
  • 多態在繼承的基礎上解決了方法調用的重用,而不被子類給覆蓋。
  • 面向對象的三大特性:封裝、繼承和多態

python3之面向對象