Python面向?qū)ο?/h2>

概念

類(Class) :用來描述具有相同屬性和方法的對象的集合。它定義了該集合中每個對象所共有的屬性和方法。其中的對象被稱作類的實例。
實例/對象:通過類定義的初始化方法,賦予具體的值,成為一個"有血有肉的實體"。
實例化:類--->對象 的過程或操作。

類變量:類變量是所有實例公有的變量。類變量定義在類中,但在方法體之外。
實例變量:定義在實例中的變量,只作用于當前實例。

實例方法:至少有一個參數(shù)并且以實例對象(self)作為其第一個參數(shù)的方法。
靜態(tài)方法:不需要實例化就可以由類執(zhí)行的方法。
類方法:類方法是將類本身作為對象進行操作的方法。

封裝:將內(nèi)部實現(xiàn)包裹起來,對外透明,提供api接口進行調(diào)用的機制。
繼承:即一個派生類(derived class)繼承父類(base class)的變量和方法。
多態(tài):根據(jù)對象類型的不同以不同的方式進行處理。

類的兩種作用

1.屬性引用(類名.屬性)
class Person: # 定義一個Person類
role = 'person' # 靜態(tài)屬性就是直接在類中定義的變量

def __init__(self,name):
    self.name = name  # 每一個角色都有自己的昵稱;
    
def walk(self):  # 動態(tài)屬性就是定義在類中的方法
    print("person is walking...")

print(Person.role) #查看人的role屬性
print(Person.walk) #引用人的走路方法,注意,這里不是在調(diào)用

2.實例化:類名加括號,自動觸發(fā)__init__函數(shù)的運行,為每個實例定制自己的特征

class 類名:
    類屬性 = None
    def __init__(self,參數(shù)1,參數(shù)2):
        self.對象屬性1 = 參數(shù)1
        self.對象屬性2 = 參數(shù)2
    
    def 方法名(self):
        pass

實例/對象名 = 類名(參數(shù)) # 對象就是實例,代表一個具體的東西
# 類名() : 類名+括號就是實例化一個類,相當于調(diào)用了__init__方法
# 括號里傳參數(shù),參數(shù)不需要傳self,其他與init中的形參一一對應
# 結(jié)果返回一個對象
實例/對象名.對象屬性 # 查看對象的屬性
實例/對象名.方法名() # 調(diào)用類中的方法

類的屬性和方法

類屬性/實例屬性(也叫類變量、實例變量)

1:實例屬性:
最好在__init__(self,...)中初始化
內(nèi)部調(diào)用時都需要加上self.
外部調(diào)用時用instancename.propertyname

2:類屬性:
在__init__()外初始化
在內(nèi)部用classname.類屬性名調(diào)用
外部既可以用classname.類屬性名又可以用instancename.類屬性名來調(diào)用

3:私有屬性:
1):單下劃線開頭:只是告訴別人這是私有屬性,外部依然可以訪問更改
2):雙下劃線
_開頭:外部不可通過instancename.propertyname來訪問或者更改
實際將其轉(zhuǎn)化為了_classname__propertyname

實例方法/靜態(tài)方法/類方法

實例方法:類的實例方法由實例調(diào)用,至少包含一個self參數(shù),且為第一個參數(shù)。執(zhí)行實例方法時,會自動將調(diào)用該方法的實例賦值給self。self代表的是類的實例,而非類本身
靜態(tài)方法:靜態(tài)方法由類調(diào)用,無默認參數(shù)。將實例方法參數(shù)中的self去掉,然后在方法定義上方加上@staticmethod,就成為靜態(tài)方法。它屬于類,和實例無關(guān)。建議只使用類名.靜態(tài)方法的調(diào)用方式。(雖然也可以使用實例名.靜態(tài)方法的方式調(diào)用)

class Foo:
    @staticmethod
    def static_method():
        pass

#調(diào)用方法
Foo.static_method()

類方法:類方法由類調(diào)用,采用@classmethod裝飾,至少傳入一個cls(代指類本身,類似self)參數(shù)。執(zhí)行類方法時,自動將調(diào)用該方法的類賦值給cls。建議只使用類名.類方法的調(diào)用方式。(雖然也可以使用實例名.類方法的方式調(diào)用)

class Foo:

    @classmethod
    def class_method(cls):
        pass

Foo.class_method()

綜合例子:

class Foo: 

    def __init__(self, name):
        self.name = name 

    def ord_func(self):
        """定義實例方法,至少有一個self參數(shù) """
        print('實例方法')

    @classmethod
    def class_func(cls):
        """ 定義類方法,至少有一個cls參數(shù) """
        print('類方法')

    @staticmethod
    def static_func():
        """ 定義靜態(tài)方法 ,無默認參數(shù)"""
        print('靜態(tài)方法') 

# 調(diào)用實例方法
f = Foo("Jack")
f.ord_func()
Foo.ord_func(f) # 請注意這種調(diào)用方式,雖然可行,但建議不要這么做!

# 調(diào)用類方法
Foo.class_func()
f.class_func()  # 請注意這種調(diào)用方式,雖然可行,但建議不要這么做!

# 調(diào)用靜態(tài)方法
Foo.static_func()
f.static_func() # 請注意這種調(diào)用方式,雖然可行,但建議不要這么做!

封裝、繼承、多態(tài)

封裝

封裝是指將數(shù)據(jù)與具體操作的實現(xiàn)代碼放在某個對象內(nèi)部,使這些代碼的實現(xiàn)細節(jié)不被外界發(fā)現(xiàn),外界只能通過接口使用該對象,而不能通過任何形式修改對象內(nèi)部實現(xiàn),正是由于封裝機制,程序在使用某一對象時不需要關(guān)心該對象的數(shù)據(jù)結(jié)構(gòu)細節(jié)及實現(xiàn)操作的方法。使用封裝能隱藏對象實現(xiàn)細節(jié),使代碼更易維護,同時因為不能直接調(diào)用、修改對象內(nèi)部的私有信息,在一定程度上保證了系統(tǒng)安全性。類通過將函數(shù)和變量封裝在內(nèi)部,實現(xiàn)了比函數(shù)更高一級的封裝。

繼承

Python3的繼承機制
子類在調(diào)用某個方法或變量的時候,首先在自己內(nèi)部查找,如果沒有找到,則開始根據(jù)繼承機制在父類里查找。
根據(jù)父類定義中的順序,以深度優(yōu)先的方式逐一查找父類!
繼承參數(shù)的書寫有先后順序,寫在前面的被優(yōu)先繼承。

多態(tài)(鴨子模式)

多態(tài)指的是一類事物有多種形態(tài)

import abc
class Animal(metaclass=abc.ABCMeta): #同一類事物:動物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal): #動物的形態(tài)之一:人
    def talk(self):
        print('say hello')

class Dog(Animal): #動物的形態(tài)之二:狗
    def talk(self):
        print('say wangwang')

class Pig(Animal): #動物的形態(tài)之三:豬
    def talk(self):
        print('say aoao')
        
peo=People()
dog=Dog()
pig=Pig()

# peo、dog、pig都是動物,只要是動物肯定有talk方法
# 于是我們可以不用考慮它們?nèi)叩木唧w是什么類型,而直接使用
peo.talk()
dog.talk()
pig.talk()

#更進一步,我們可以定義一個統(tǒng)一的接口來使用
def func(obj):
    obj.talk()  # 調(diào)用的邏輯都一樣,執(zhí)行的結(jié)果卻不一樣

talk(peo)
talk(dog)
talk(pig)

特殊成員和魔法方法

__init__ : 構(gòu)造函數(shù),在生成對象時調(diào)用
__del__ : 析構(gòu)函數(shù),釋放對象時使用
__repr__ : 打印,轉(zhuǎn)換
__setitem__ : 按照索引賦值
__getitem__: 按照索引獲取值
__len__: 獲得長度
__cmp__: 比較運算
__call__: 調(diào)用
__add__: 加運算
__sub__: 減運算
__mul__: 乘運算
__div__: 除運算
__mod__: 求余運算
__pow__: 冪

使用:

1.__getitem__()、__setitem__()、__delitem__()
a = 標識符[]?。?  執(zhí)行__getitem__方法
標識符[] = a  :   執(zhí)行__setitem__方法
del 標識符[] :   執(zhí)行__delitem__方法

class Foo:

    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']      # 自動觸發(fā)執(zhí)行 __getitem__
obj['k2'] = 'jack'      # 自動觸發(fā)執(zhí)行 __setitem__
del obj['k1']           # 自動觸發(fā)執(zhí)行 __delitem__

2.__str__(),__repr__()改變對象的字符串顯示
3.__format__自定制格式化字符串
4.__del__()析構(gòu)方法,當對象在內(nèi)存中被釋放時,自動觸發(fā)執(zhí)行
5.__new__單例模式
6.__call__()對象后面加括號,觸發(fā)執(zhí)行
7.__len__() len()時執(zhí)行
8.__module__ 表示當前操作的對象在屬于哪個模塊
9.__class__ 表示當前操作的對象屬于哪個類
10.__dict__列出類或?qū)ο笾械乃谐蓡T!非常重要和有用的一個屬性
11.__iter__這是迭代器方法!列表、字典、元組之所以可以進行for循環(huán),內(nèi)部定義了 __iter__()這個方法
12.__slots__限制實例可以添加的變量
... 

反射

反射(或自?。┲饕侵赋绦蚩梢栽L問、檢測、和修改它本身狀態(tài)或行為的一種能力,在python中,通過字符串的形式操作對象相關(guān)的屬性,python中的一切事物都是對象,即都可以使用反射。
反射4個內(nèi)置函數(shù)分別為:getattr、hasattr、setattr、delattr 獲取成員、檢查成員、設(shè)置成員、刪除成員

  • hasattr:hasattr(object,name)判斷一個對象是否有name屬性或者name方法。有就返回True,沒有就返回False
  • getattr:獲取對象的屬性或者方法,如果存在則打印出來。hasattr和getattr配套使用,需要注意的是,如果返回的是對象的方法,返回出來的是對象的內(nèi)存地址,如果需要運行這個方法,可以在后面添加一對()
  • setattr:給對象的屬性賦值,若屬性不存在,先創(chuàng)建后賦值
  • delattr:刪除該對象指定的一個屬性
  • isinstance(obj,cls)檢查是否obj是否是類 cls 的對象
  • issubclass(sub, super)檢查sub類是否是 super 類的派生類

Other

關(guān)于self
self:在實例化時自動將對象/實例本身傳給__init__的第一個參數(shù),你也可以給他起個別的名字。
實例(對象)只有一種作用:屬性引用
關(guān)于super
如果子類中實現(xiàn)了調(diào)用父類的方法:
在類內(nèi):super(子類,self).方法名() supper().__init__(參數(shù))
在類外:super(子類名,對象名).方法名()
零碎
getattr(obj,"name") = obj.name
Python內(nèi)置的@property裝飾器就是負責把一個方法變成屬性調(diào)用
super 是用來解決多重繼承問題的,直接用類名調(diào)用父類方法在使用單繼承的時候沒問題,
但是如果使用多繼承,會涉及到查找順序(MRO)、重復調(diào)用(鉆石繼承)等種種問題。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容