Python自動化運維之十一、面向對象基礎

1、簡介

  面向對象編程是一種編程方式,使用 「類」 和 「對象」 來實現,因此,面向對象編程其實就是對 「類」 和 「對象」 的使用。類就是一個模板,模板裏能夠包含多個方法(函數),方法裏實現各類各樣的功能,對象則是根據模板建立的實例,經過實例,對象能夠執行類中的方法,每一個對象都擁有相同的方法,但各自的數據可能不一樣。java

2、類、對象和方法

  在Python中,定義類是經過class關鍵字,class後面緊接着是類名,類名一般是大寫開頭的單詞,緊接着是('要繼承的類名'),表示該類是從哪一個類繼承下來的,能夠有多個父類(基類),一般若是沒有合適的繼承類,就使用object類,這是全部類最終都會繼承的類,也能夠不寫。python

class F1(object):   
    def __init__(self,name,age):   
        self.name = name  
        self.age = age
	
f1 = F1('python',27)	
	
上面的這個__init__()叫作初始化方法(或構造方法), 在類實例化時,這個方法(雖然它是函數形式,但在類中就不叫函數了,叫方法)會自動執行,
進行一些初始化的動做,因此咱們這裏寫的__init__(self,name,age)就是要在建立一個角色時給它設置這些屬性。

參數self有什麼用呢?

1.在內存中開闢一塊空間指向f1這個變量名
2.實例化F1這個類首先執行其中的__init__()方法,至關於F1.__init__(f1,'python',27),是爲了把'python',27這2個值跟剛開闢的f1關聯起來,由於關聯起來後,你就能夠直接f1.name, f1.age 這樣來調用啦。因此,爲實現這種關聯,在調用__init__方法時,就必須把f1這個變量也傳進去,不然__init__不知道要把那2個參數跟誰關聯,self其實就是實例化對象f1被看成參數傳遞了。
3.因此這個__init__(…)構造方法裏的,self.name = name , self.age = age 等等就是要把這幾個值存到f1的內存空間裏。 程序員

3、面向對象三大特性,封裝、繼承和多態。  

一、封裝

  面向對象有3大特性,首先咱們來講第一個特性,封裝,封裝通常是經過在類中封裝數據,而經過對象或者self獲取。和其餘面向對象的語言相似,也是經過構造函數來進行數據封裝。下面來看一下代碼。 數據庫

class A:
    def __init__(self,name):        # 構造函數,初始化數據,
        self.name=name              # 封裝數據
 
    def f1(self):
        print(self.name)           # 經過self間接獲取封裝的數據
 
a=A('json')                        # 至關於A.__init__(a,'json')將'json'封裝到a中的name屬性中
print(a.name)                      # 直接調用a對象的name屬性
a.f1()                             # python會把a看成參數傳遞給a.f1(a),因此print(a.name)

還有一種封裝的方式,使用私用的屬性來封裝數據,看一下具體的用法,編程

class A:
    name='Jason'
    __age=18                        # 私有類屬性
    def __init__(self):
        self.__like='soccer'        # 私有實例屬性
        self.hobby='kkkk'
 
    def f1(self):
        print(self.__age)         # 私有類屬性,私有實例屬性只能被類中的方法調用
        print(self.__like)
# A.__age                         # 外部獲取不到私有類屬性,數據被封裝起來
a=A()                             # soccer
a.f1()                            # 18
print(a.hobby)

複雜的封裝(必定要搞清楚): 將類封裝進對象中  json

class c1:

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

class c2:

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

    def show(self):
        print(self.name)

class c3:

    def __init__(self,a1):
        self.money = 123
        self.aaa = a1

c2_obj = c2('aa',12)          # 將字符串'aa',數字12封裝到c2_obj.name和c2_obj.age中
c1_obj = c1('python',c2_obj)  # 將字符串'python'封裝到c1_obj.name中,將c2_obj中的屬性c2_obj.name,c2_obj.age封裝到c1_obj.obj中
c3_obj = c3(c1_obj)           # 將c1_obj中的全部屬性,包括(c2_obj的所全部方法和屬性)

print(c3_obj.aaa.obj.name)    #c3類中找到c2類中的屬性
ret = c3_obj.aaa.obj.show()   #c3類中找到c2類中的方法執行並接收返回值
print(ret)

二、繼承  

  繼承的本質是將父類中的方法所有複製一份到子類中。Python裏面的繼承能夠多繼承,經過繼承,能夠得到父類的功能,繼承的時候,若是父類中有重複的方法,優先找本身c#

經過繼承建立的新類稱爲「子類」或「派生類」。被繼承的類稱爲「基類」、「父類」或「超類」。

函數式編程

(1)、Python的類能夠繼承多個類,Java和C#中則只能繼承一個類函數

(2)、Python的類若是繼承了多個類,那麼其尋找方法的方式有兩種,分別是:深度優先廣度優先spa

  • 當類是經典類時,多繼承狀況下,會按照深度優先方式查找,Python2.x分爲經典類和新式類(默認是經典類,繼承了object父類則爲新式類)
  • 當類是新式類時,多繼承狀況下,會按照廣度優先方式查找,Python3.x 統一都是新式類

經典類和新式類,從字面上能夠看出一個老一個新,新的必然包含了跟多的功能,也是以後推薦的寫法,從寫法上區分的話,若是 當前類或者父類繼承了object類,那麼該類即是新式類,不然即是經典類。

繼承的執行過程例子:

class A:
    def f(self):
        print('a')
class B:
    def f(self):
        print('b')
 
    def f1(self):
        print('bbbb')
 
class C(A,B):
    def f1(self):
        print('c')
cc=C()
cc.f()         # 結果爲a,在C類中沒有f()這個方法時,繼承時A基類寫在前面,因此優先找A類中的f()方法
cc.f1()        # 結果爲c,在C類中有f1()方法,則優先執行本身的方法
 

下面是重點和難點,在其餘源碼都是這麼幹的  

class A:
    def bar(self):
        print('bar')
        self.f1()
 
class B(A):
    def f1(self):
        print('b')
 
class C():
    def f1(self):
        print('c')
class D(B):
    def f1(self):
        print('d')
 
class E(C,D):
    pass
 
d=D()
d.bar()             

上述繼承的執行過程:

  • 1. 對象d是D()的實例,d.bar()首先在D()中找有沒有bar()方法
  • 2. 沒有則到D()類繼承的父類B()類中找有沒有bar()方法
  • 3. 沒有繼續向上一層找B()類繼承的父類A()類中找有沒有bar()方法
  • 4. A()類中有bar()方法則執行了bar()方法
  • 5. bar()執行了作了兩件事:(1)、打印print('c')    (2)、執行了self.f1()
  • 6. 執行了self.f1(),記住self是d對象,迴歸到最初 d=D()
  • 7. 則執行了D()中的f1()方法,因此結果是bar和d 

(3)、除了繼承方法,還能夠繼承父類的構造函數  

# 繼承構造方法
class A:
    def __init__(self):
        self.name='jason'
 
class B(A):
    def __init__(self):
        self.age='16'
        super(B,self).__init__()
        # A.__init__(self)          #另外一種繼承構造函數的方法
 
d=B()

(4)、強制使用父類中的方法(很是有用)使用:super(子類類名,self).父類中的方法

class C1:

    def f1(self):
        print('c1.f1')
        return 123

class C2(C1):

    def f1(self):
        # 主動執行父類的f1方法
        ret = super(C2,self).f1()
        print('c2.f1')
        return ret

        # C1.f1(self) 第二種方法,主動執行父類的方法,不經常使用

obj = C2()
obj.f1()

 

3、多態 

   Pyhon不支持Java和C#這一類強類型語言中多態的寫法,python自己就是支持多態的,因此在Python面向對象裏面討論多態並無什麼意義,其Python崇尚「鴨子類型」。

class F1:
    pass

class S1(F1):

    def show(self):
        print('S1.show')

class S2(F1):

    def show(self):
        print('S2.show')

def Func(obj):   
    print(obj.show())

s1_obj = S1()
Func(s1_obj)

s2_obj = S2()
Func(s2_obj)

在java,c#中定義參數是須要強制定義一個參數是什麼類型的參數,相似下面的代碼

class A:
    pass

class B(A):
    pass

class C(A):
    pass

# arg參數:必須是A類型或A的子類
def func(A arg):
    print(arg)
    
# obj = B()
# obj = C()
obj = A()
func(obj)

總結 

以上就是本節對於面向對象初級知識的介紹,總結以下:

  • 面向對象是一種編程方式,此編程方式的實現是基於對  和 對象 的使用
  • 類 是一個模板,模板中包裝了多個「函數」供使用
  • 對象,根據模板建立的實例(即:對象),實例用於調用被包裝在類中的函數
  • 面向對象三大特性:封裝、繼承和多態

問答專區

問題一:什麼樣的代碼纔是面向對象?

答:從簡單來講,若是程序中的全部功能都是用 類 和 對象 來實現,那麼就是面向對象編程了。

問題二:函數式編程 和 面向對象 如何選擇?分別在什麼狀況下使用?

答:須知:對於 C# 和 Java 程序員來講不存在這個問題,由於該兩門語言只支持面向對象編程(不支持函數式編程)。而對於 Python 和 PHP 等語言卻同時支持兩種編程方式,且函數式編程能完成的操做,面向對象均可以實現;而面向對象的能完成的操做,函數式編程不行(函數式編程沒法實現面向對象的封裝功能)。

因此,通常在Python開發中,所有使用面向對象 或 面向對象和函數式混合使用

面向對象的應用場景:

  • 多函數需使用共同的值,如:數據庫的增、刪、改、查操做都須要鏈接數據庫字符串、主機名、用戶名和密碼
class SqlHelper:

    def __init__(self, host, user, pwd):

        self.host = host
        self.user = user
        self.pwd = pwd

    def 增(self):
        # 使用主機名、用戶名、密碼(self.host 、self.user 、self.pwd)打開數據庫鏈接
        # do something
        # 關閉數據庫鏈接

    def 刪(self):
        # 使用主機名、用戶名、密碼(self.host 、self.user 、self.pwd)打開數據庫鏈接
        # do something
        # 關閉數據庫鏈接

    def 改(self):
        # 使用主機名、用戶名、密碼(self.host 、self.user 、self.pwd)打開數據庫鏈接
        # do something
        # 關閉數據庫鏈接

    def 查(self):
    # 使用主機名、用戶名、密碼(self.host 、self.user 、self.pwd)打開數據庫鏈接
        # do something
        # 關閉數據庫鏈接# do something
  • 須要建立多個事物,每一個事物屬性個數相同,可是值的需求

        如:張3、李4、楊五,他們都有姓名、年齡、血型,但其都是不相同。即:屬性個數相同,但值不相同

class Person:

    def __init__(self, name ,age ,blood_type):

        self.name = name
        self.age = age
        self.blood_type = blood_type


    def detail(self):
        temp = "i am %s, age %s , blood type %s " % (self.name, self.age, self.blood_type)
        print temp

zhangsan = Person('張三', 18, 'A')
lisi = Person('李四', 73, 'AB')
yangwu = Person('楊五', 84, 'A')

問題三:類和對象在內存中是如何保存?

答:類以及類中的方法在內存中只有一份,而根據類建立的每個對象都在內存中須要存一份,大體以下圖:

如上圖所示,根據類建立對象時,對象中除了封裝 name 和 age 的值以外,還會保存一個類對象指針,該值指向當前對象的類。

當經過 obj1 執行 【方法一】 時,過程以下:

  1. 根據當前對象中的 類對象指針 找到類中的方法
  2. 將對象 obj1 看成參數傳給 方法的第一個參數 self 
相關文章
相關標籤/搜索