1. 程式人生 > >Python3 從零單排16_面向物件基礎

Python3 從零單排16_面向物件基礎

  面向過程概述
  定義:指解決問題的步驟,第一步第二步一直走下去,直到解決問題。好比流水線,是一種機械式的思維。
  優點:複雜問題流程化,進而簡單化(一個複雜的問題,分成一個個小的步驟去實現,實現小的步驟將會非常簡單)
  缺點:一旦解決問題的步驟都確定好了後,不好擴充套件,好比如體制化後要改革非常難,改其中一個步驟,其他步驟都必須得聯動,擴充套件性極差。
  應用:實用於一些不會輕易變化的場景,比如需要寫一些簡單的指令碼做些一次性任務,面向過程實用。但如果處理非常複雜且需求多變的任務時就不好使了。

  面向物件概述
  定義:萬物皆物件,物件就是特徵與技能的集合(比如孫悟空,毛臉雷公嘴是特徵,七十二變是技能)

  優點:可擴充套件性強
  缺點:程式設計複雜度高,極容易出現過度設計的問題,而且在一些擴充套件性要求低的場景使用面向物件會徒增程式設計難度
  應用:實用於客戶需求頻繁變化,如網際網路/遊戲/企業應用

  類概述
  在程式裡實質就是一個模板,定義好類的特徵/技能,就可以生成具有這些特徵/技能的物件,這個過程就是類的例項化
  定義:類就是一系列物件相似的特徵與技能的結合體
  強調:站在不同的角度,得到的分類不一樣
# 定義類
# 知識點 類在定義的時候會執行裡面的程式碼,跟函式不一樣,函式在定義的時候只是儲存在記憶體裡,加括弧的時候才會呼叫
class BeijingStudent:
    school 
= "beijing_university" #類的資料屬性 print(school) def learn(self): #類的函式屬性 print("learning") def sleep(self): print("sleeping") # 產生物件 即例項化 stu1 = BeijingStudent() #BeijingStudent()跟函式呼叫是一樣的,但這裡不是執行類體裡面的程式碼,只是得到一個物件 stu2 = BeijingStudent() stu3 = BeijingStudent() print
(stu1) # <__main__.BeijingStudent object at 0x10bc56080> 生成的是一個物件 print(stu2) # <__main__.BeijingStudent object at 0x10db5f048> 都是同一個類生成的物件,記憶體地址不一樣 # 檢視類的名稱空間 類內部:變數就是上面說的特徵 函式就是上面說的技能 print(BeijingStudent.__dict__) # 類的名稱空間是一個字典形式 「'school': 'beijing_university', 'learn': <function BeijingStudent.learn at 0x109c152f0>」 # 查屬性 print(BeijingStudent.__dict__['school']) # 既然名稱空間是一個字典,那麼就可以用字典的方式拿到資料 print(BeijingStudent.__dict__['learn']) # 既然名稱空間是一個字典,那麼就可以用字典的方式拿到資料,函式也一樣,只要是屬性就可以這樣訪問 #python提供了特別的訪問方式,直接點就可以訪問類裡的屬性 print(BeijingStudent.school) # 實質就是上面那種訪問方式,只是python簡化了,跟模組一樣,直接time.time(),本質都是一樣的 print(BeijingStudent.learn) # BeijingStudent.country = "China" print(BeijingStudent.__dict__['country']) print(BeijingStudent.country) # del BeijingStudent.country # BeijingStudent.school = "Qinghua_university"
 
使用物件
# __init__ 為物件定製物件自己的特徵  __init__ 建構函式
class BeijingStudent:
    school = "beijing_university"
                #stu1,name,sex,age  例項化的時候類會自動呼叫__init__函式,將物件本身和傳遞的引數一起放進來
    def __init__(self,name,sex,age):
        self.Name = name
        self.Sex = sex
        self.Age = age

        # stu1.Name = name  # 例項化時,實際就是做了這步操作
        # stu1.Sex = sex
        # stu1.Age = age

    def learn(self):
        print("learning")

    def sleep(self):
        print("sleeping")

# 產生物件  即例項化
stu1 = BeijingStudent("王大錘","",18)
print(stu1.__dict__)  # >> {'Name': '王大錘', 'Sex': '男', 'Age': 18}
#
print(stu1.Name)
#
stu1.Name = "隔壁老王"
print(stu1.Name)
#
del stu1.Name
print(stu1.__dict__)
#
stu1.weight = "70KG"
print(stu1.__dict__)
print(stu1.weight)

  屬性/方法查詢

  類中的方法,是給物件使用的,哪個物件呼叫就把那個物件本身作為第一個引數傳遞給方法,也就是給self。
x = "global_x"

class BeijingStudent:
    school = "beijing_university"

    def __init__(self,name,sex,age):
        self.Name = name
        self.Sex = sex
        self.Age = age

    def learn(self):
        print("learning")

    def sleep(self):
        print("%s is sleeping"%self.Name)

stu1 = BeijingStudent("王大錘","",18)
stu2 = BeijingStudent("張全蛋","",38)

#類中的資料屬性是所有物件所共有的,也就是所有物件在訪問類中的資料變數時,都是同一個變數,即記憶體地址都是相同的
print(BeijingStudent.school,id(BeijingStudent.school))  # beijing_university 4556931120
print(stu1.school,id(stu1.school))                      # beijing_university 4556931120
print(stu2.school,id(stu2.school))                      # beijing_university 4556931120

#類中的函式屬性:是繫結給物件使用的,繫結到不同的物件是不同的繫結方法,物件在呼叫方法時,會把物件本身當作第一個引數傳給self
#類中定義的函式(沒有被任何裝飾器裝飾的)是類的函式屬性,類也可以呼叫,但必須遵循函式的引數規則,有幾個引數需要傳幾個引數
print(BeijingStudent.learn) #<function BeijingStudent.learn at 0x10f179730>
print(stu1.learn)    #<bound method BeijingStudent.learn of <__main__.BeijingStudent object at 0x10f19a6a0>>
print(stu2.learn)    #<bound method BeijingStudent.learn of <__main__.BeijingStudent object at 0x10f19a9b0>>
#learn這個函式在類和不同物件中的記憶體地址都不一樣,也就是每一個物件都有了自己的learn方法,可以理解為不同學生在學習的時候感悟都是不一樣的。

# 類不能呼叫類中定義的物件方法,因為上面說了,物件在呼叫方法的時候,程式自動把物件本身作為第一個引數傳給了self
# BeijingStudent.learn() #報錯,因為少了一個傳參 self
BeijingStudent.learn("fgas") #當然你可以隨便傳一個引數給self就可以呼叫
# BeijingStudent.sleep("fgas") #但是sleep的時候又報錯了,因為沒有 fgas.Name這個屬性,一般類不調物件方法,只給例項化後的物件使用
stu1.learn()  # 等價於 BeijingStudent.learn(stu1)

# 名稱空間優先順序 首先在物件本身中查詢,找不到往類中找,類找不到往父類找,所有父類中找不到就報錯,不會像函式一樣往全局裡去找了
print(stu1.x)  #報錯,雖然全域性變數中有x這個變數,但是物件的作用域只在類中
stu1.x = "from stu1"
BeijingStudent.x = "from BeijingStudent"
print(stu1.x)  #from stu1

  擴充套件性
  將資料與專門操作該資料的功能整合到一起。
# 在沒有學習類這個概念時,資料與功能是分離的
def exc1(host,port,db,charset):
    conn=connect(host,port,db,charset)
    conn.execute(sql)
    return xxx

def exc2(host,port,db,charset,proc_name)
    conn=connect(host,port,db,charset)
    conn.call_proc(sql)
    return xxx

#每次呼叫都需要重複傳入一堆引數
exc1('127.0.0.1',3306,'db1','utf8','select * from tb1;')
exc2('127.0.0.1',3306,'db1','utf8','儲存過程的名字')

# 解決方法是,把這些變數都定義成全域性變數
HOST=‘127.0.0.1’
PORT=3306
DB=‘db1’
CHARSET=‘utf8’

def exc1(host,port,db,charset):
    conn=connect(host,port,db,charset)
    conn.execute(sql)
    return xxx


def exc2(host,port,db,charset,proc_name)
    conn=connect(host,port,db,charset)
    conn.call_proc(sql)
    return xxx

exc1(HOST,PORT,DB,CHARSET,'select * from tb1;')
exc2(HOST,PORT,DB,CHARSET,'儲存過程的名字')

# 我們必須找出一種能夠將資料與操作資料的方法組合到一起的解決方法,這就是我們說的類了
class MySQLHandler:
    def __init__(self,host,port,db,charset='utf8'):
        self.host=host
        self.port=port
        self.db=db
        self.charset=charset
        self.conn=connect(self.host,self.port,self.db,self.charset)
    def exc1(self,sql):
        return self.conn.execute(sql)

    def exc2(self,sql):
        return self.conn.call_proc(sql)


obj=MySQLHandler('127.0.0.1',3306,'db1')
obj.exc1('select * from tb1;')
obj.exc2('儲存過程的名字')