面向對象編程學習筆記

面向對象的編程

面向過程的編程:
  • 核心:過程(過程指的是解決問題的步驟,機械式的思惟方式)
  • 優勢:將複雜的問題流程化,進而簡單化
  • 缺點:可擴展性差python

    面向對象編程
  • 核心:對象(對象就是特徵與技能的結合體)
  • 對象:python中一切是對象
  • 優勢:可擴展性強
  • 缺點:編程複雜度高
  • 應用場景:用戶需求常常變化,互聯網應用,遊戲,企業內部應用sql

  • 類:就是一 系列對象類似的特徵與技能的結合體(站在不一樣角度,獲得的分類是不一樣的)
  • 對象:特徵與技能結合體
  • 在現實世界中:必定先有對象,後有類
  • 在程序中:必定得先定義類,後調用類來產生對象
  • 查看名稱空間:
stu1 = LufftStudent()
print(stu1.__dict__)

類:編程

class LuffyStudent:
    school = 'luffycity' #數據屬性
    
    def learn(self):# 函數屬性
        print('is learing')
    
    def eat(self):
        print('is eating')
        
        
stu1 = LuffyStudent() #實例化對象


# # 查看類的名稱空間
# print(LuffyStudent.__dict__)
# print(LuffyStudent.__dict__['school'])
# print(LuffyStudent.__dict__['learn'])

# 查看類的屬性
#print(LuffyStudent.school) #LuffyStudent.__dict__['school']

# 增長類的屬性
LuffyStudent.county = 'China'

# 刪除
del LuffyStudent.county

# 改
LuffyStudent.school = 'Luffycity'
__init__方法
class LuffyStudent:
    school = 'luffycity' #數據屬性
    def __init__(self,name,sex,age):# __init__方法用來對象定製對象獨有的特徵
        self.Name = name
        self.Sex = sex
        self.Age = age

    def learn(self):# 函數屬性
        print('is learing')

    def eat(self):
        print('is eating')

# 後產生的對象
stu1 = LuffyStudent('wualin','man',29)#LuffyStudent.__init__(stu1,'wualin','man',20)

# 加上__init__方法後,實例化步驟
# 1. 先產生一個空對象stu1
# 2. 觸發LuffyStudent.__init__(stu1,'wualin','man',29)

#
# # 查
# print(stu1.Name)
# print(stu1.Sex)
# print(stu1.Age)
# # 改
# stu1.Name='520'
#
# # 刪除
# del stu1.Name
#
# # 增
# stu1.class_name = 'python開發'
屬性查找
  • 類中的數據屬性:是全部對象共有的函數

  • 類中的函數屬性:是綁定給對象,綁定到不一樣的對象是不一樣的綁定方法,對象調用綁定方式時,會把對象自己看成第一個傳入,傳個self
class LuffyStudent:
    school = 'luffycity' #數據屬性
    def __init__(self,name,sex,age):# __init__方法用來對象定製對象獨有的特徵
        self.Name = name
        self.Sex = sex
        self.Age = age

    def learn(self):# 函數屬性
        print('is learing')

    def eat(self):
        print('is eating')

# 後產生的對象
stu1 = LuffyStudent('wualin','man',29)
stu2 = LuffyStudent('張寶寶','man',19)

# 類的數據屬性
print(stu1.school)


# 類的函數屬性,類中函數屬性是給對象使用的,誰調用就綁定給它使用,自動將對象傳入第一個參數


stu1.learn()#learn(stu1)

#對象在訪問一個屬性的時候會先在對象裏面的名稱空間找,若是對象裏面沒有則去類裏面找。不會到全局變量裏面找
python中一切皆對象:
  • 對象之間的交互:
class Girlun:
    faction = 'Demasia'
    def __init__(self,name,life,attack):
        self.name = name
        self.life = life
        self.attack = attack
    def attack_1(self,enemy):
        enemy.life = enemy.life-self.attack
        print('%s攻擊了%s'%(self.name,enemy.name))


class Riwen:
    faction = 'Demasia'

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

    def attack_1(self, enemy):
        enemy.life = enemy.life - self.attack
        print('%s攻擊了%s' % (self.name, enemy.name))
g1 = Girlun('草叢倫',100,10)
r1 = Riwen('銳萌萌',80,20)
print(r1.life)
g1.attack_1(r1)
print(r1.life)

繼承與重用

  • 繼承指的是類與類之間的關係
  • 查看繼承自父類的哪些東西:
print(<類名>.__bases__)
  • 繼承示例:
class Hero:
    def __init__(self,name,life,attack):
        self.name = name
        self.life = life
        self.attack = attack
    def attack_1(self,enemy):
        print('%s攻擊了%s'%(self.name,enemy.name))

class Griren(Hero):
    pass

class Riven(Hero):
    pass

g1 = Griren('蓋倫',80,50)
r1 = Riven('銳雯',50,50)

g1.attack_1(r1)
派生
  • 當子類中有須要的屬性則不會去父類中查找
繼承的實現原理:
  • 原則:
    • 子類會先餘父類被檢查
    • 多個父類會根據他們在列表中的順序被檢查(從左到右)
    • 若是下一個類存在兩個合法的選擇,會選擇第一個父類
  • MRO查找方法
print(<類名>.__mro__
在子類中重用父類的方法或屬性
  • 方式一:指名道姓,類名+方法(不依賴繼承)
class Hero:
    def __init__(self,name,life,attack):
        self.name = name
        self.life = life
        self.attack = attack
    def attack_1(self,enemy):
        enemy.life -=self.attack

class Griren(Hero):
    def attack_1(self,enemy):
        Hero.attack_1(self,enemy) # 不依賴於繼承
        print('%s攻擊了%s'%(self.name,enemy.name))
class Riven(Hero):
    pass

g1 = Griren('蓋倫',80,50)
r1 = Riven('銳雯',100,50)
print(r1.life)
g1.attack_1(r1)
print(r1.life)
  • 方式二:super()
    • super()查找方法基於mro列表日後找
class Hero:
    def __init__(self,name,life,attack):
        self.name = name
        self.life = life
        self.attack = attack
    def attack_1(self,enemy):
        enemy.life -=self.attack

class Griren(Hero):

    def __init__(self,name,life,attack,weapon):
        super().__init__(name,life,attack)# 第一種寫法,依賴於繼承
    def attack_1(self,enemy):
        super(Griren,self).attack_1(enemy)# 第二種寫法,依賴於繼承
        print('%s攻擊了%s'%(self.name,enemy.name))
class Riven(Hero):
    pass

g1 = Griren('蓋倫',80,50,'大保健')
r1 = Riven('銳雯',100,50)
print(r1.life)
g1.attack_1(r1)
print(r1.life)
print(g1.__dict__)
組合
  • 將兩個類生成的實例對象組合在一塊兒
抽象類與歸一化
  • 經過抽象類使子類中的方法名統一塊兒來
  • 抽象類只能被繼承,不能實例化
import abc
class Animal(metaclass=abc.ABCMeta):# 經過抽象類使子類中的方法名統一塊兒來
    @abc.abstractmethod
    def run(self):
        pass

    @abc.abstractmethod
    def eat(self):
        pass

class People(Animal):

    def run(self):
        pass

    def eat(self):
        pass

class Pig(Animal):

    def run(self):
        pass

    def eat(self):
        pass

多態與多態性

  • 同一種事物的多種形態工具

    多態性:
  • 能夠在不考慮對象的類型的狀況下而直接使用對象
    • 如抽象類中只要是動物都有的屬性,無論屬於什麼分類,都有這一個方法,能夠直接使用
  • 多態性的好處:
  1. 增長類程序的靈活性
    • 以不變應萬變,不論對象變幻無窮,均可以經過統一接口調用
  2. 增長類程序可擴展性
    • 經過繼承父類建立類一個新類,使用者無需更改本身的代碼,仍是用一樣的方法去調用
  • python崇尚的是一種鴨子類型

封裝

如何實現屬性的隱藏
class A:
    __x = 1 #_A__x=1
    
    def __init__(self,name):
        self.__name=name
        
    def __foo(self):
        print('run foo')
  • 特色:
  1. 在類外部沒法直接使用
  2. 在類內部能夠直接使用
  3. python並不真正隱藏,只是在類定義是進行了變形操做
  4. 子類沒法覆蓋父類__開頭的屬
封裝的意義
  • 封裝數據屬性:明確區份內外,控制外部對隱藏的屬性的操做行爲code

  • 封裝方法:隔離複雜度對象

封裝與擴展性
property的使用

propert:特性繼承

class People:
    def __init__(self,name):
        self.__name = name
    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self,val):
        if not isinstance(val,str):
            print('val is not str')
            return
        self.__name = val
    @name.deleter
    def name(self):
        print('不容許刪除')

p = People('wualin')
print(p.name)
綁定方法與非綁定方法
  • 綁定方法:
    • 綁定給誰,就應該由誰來調用,誰來調用就把調用者看成第一個參數自動傳入
    • 綁定到對象的方法:在類內定義的沒有被任務裝飾器修飾的接口

    • 綁定到類的方法:在類內部定義的裝飾器classmethod修飾的方法遊戲

  • 非綁定方法:不會自動傳值,就是類中的普通工具,類和對象均可以使用
    • 非綁定方法:不與類或者對象綁定
class Foo:
    def __init__(self,name):
        self.name = name

    def tell(self):# 綁定到對象的函數
        print('name:%s'%self.name)

    @classmethod
    def func(cls): #cls=Foo 綁定到類的方法
        print(cls)

    @staticmethod
    def func1(x,y):#類中的普通函數
        print(x+y)

f = Foo('wualin')
Foo.func1(1,2)
f.func1(1,3)
  • 綁定方法與非綁定方法的實際應用場景

反射

  • 經過字符串映射到對象的屬性
hasattr(obj,'name')# 判斷對象有沒有'name'屬性 obj.__dict__['name']

getattr(obj,'name') # 拿到對象的屬性

setattr(obj,'name','wualin')#修改 obj.name = 'wualin'

delattr(obj,'age')# del obj.age
以上方法一樣適用於類
  • 反射的應用:
class Service:
    def run(self):
        while True:
            cmd = input('>>>:').strip()
            if hasattr(self,cmd):
                func = getattr(self,cmd)
                func()
    def get(self):
        print('get...')
        
    def put(self):
        print('put...')
obj = Service()
obj.run()
內置方法
  • isinstance(obj,cls) 檢查obj是不是類cls的對象
class Foo(object):
    psss
obj = Foo()
isinstance(obj,Foo)
  • issubclass(sub,super) 檢查sub類是不是super的派生類(子類)
class Foo():
    pass
class Bar(Foo):
    pass
issubclass(Bar,Foo)
  • item系列:
# item
class Foo():
    def __init__(self,name):
        self.name = name

    def __getitem__(self, item):#查看

        return self.__dict__.get(item)

    def __setitem__(self, key, value):#增長
        self.__dict__[key] = value

    def __delitem__(self, key):#刪除
        del self.__dict__[key]

obj = Foo('wualin')
#操做字典的方式去操做obj對象
#查看
print(obj['name']) #obj.name

#增長
obj['age'] = 20 #obj.age = 20
print(obj['age'])

#刪除
del obj['name'] #del obj.name
  • str
class Foo():
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __str__(self):

        return '<name:%s age:%s>'%(self.name,self.age)

f = Foo('wualin',20)
print(f)
  • del:在對象被刪除時先觸發__del__,可自定義回收系統資源
class Open():
    def __init__(self,filename):
        print('Open...')
        
    def __del__(self):
        print('del...')
f = Open('a.txt')
print('---main---')
  • call
class Foo:
    def __call___(self,*args,**kwargs)
        print(self)
        print(args)
        print(kwargs)
obj = ()
obj(1,2,3,a=1,b=2,c=3)#obj.__call__(obj,1,2,3,a=1,b=2,c=3)

元類介紹

  • exec命令的使用:
  1. 參數1:字符串形式的命令
  2. 參數2:全局做用域(字典形式),若是不指定默認使用globals()
  3. 參數3:局部做用域(字典形式),若是不指定默認使用locals()
  • 對象能夠怎麼使用?
    • 均可以被引用:x = obj
    • 均可以看成函數的參數傳入
    • 均可以看成函數的返回值
    • 均可以看成容器類
  • 產生類的類稱之爲元類,默認使用class定義的類,他們的元類是type
  • 定義類的三要素:
  1. 類名
  2. 類的基類
  3. 類的局部名稱空間:obj.__dict__()
  • 定義類的兩種方式:
    • 方式1:class

    • 方式2:type
    class_name = 'Chinese' #類名
    class_bases = (object,) #類的基類
    class_body = 
    '''
    country = 'china'
    def __init__(self,name,age):
      self.name = name
      self.age = age
    def talk(self)
      print('%s is talking'$self.name)
    '''
    class_dic = {}# 類的局部名稱空間
    exec(class_body,globals(),class_dic)
    Chinese1 = type(class_name,class_bases,clsaa_dic)
    自定義元類控制類的行爲
    class Mymeta(type):
      '''
      給傳入class_name添加首字母必須大寫,不然拋出異常,若是定義類的元類是Mymeta(metaclass=),就必須遵循自定義規則
      '''
      def __init__(self,class_name,class_bases,class_dic):
          if not class_name.istitle():
              raise TypeError('首字母大寫') #raise主動拋出錯誤
    class Chinese(object,metaclass=Mymeta):
      def __init__(self,name,age):
          self.name = name
          self.age = age
    
      def tall_info(self):
          print('Name: %s Age: %s'%(self.name,self.age))
自定義元類控制類的實例化行爲
class Mymeta(type):
    def __call__(self, *args, **kwargs):
        '''
        實例化類的步驟:
        1. 生成obj對象
        2. 初始化obj對象
        3. 返回obj
        :param args:
        :param kwargs:
        :return:
        '''
        obj = object.__new__(self)
        self.__init__(obj,*args,*kwargs)
        return obj

class Chinese(object,metaclass=Mymeta):
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def tall_info(self):
        print('Name: %s Age: %s'%(self.name,self.age))
obj = Chinese('WUALIN',20)
print(obj.__dict__)
自定義元類控制類的實例化行爲的應用
  • 單例模式:
class MySQL:
    '''
    假如一個類初始化屬性都是同樣的,能夠使用單例模式節省內存空間
    '''
    __instance = None
    def __init__(self):
        self.host = '127.0.0.1'
        self.port = 3306
    
    @classmethod
    def singleton(cls): #單例模式函數,生成實例化對象時調用該函數
        if not cls.__instance:
            obj=cls()
            cls.__instance=obj
        return cls.__instance
# 兩次實例化對象內存地址是同樣的   
obj1 = MySQL.singleton()
obj2 = MySQL.singleton()
  • 經過元類實現單例模式:
class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dic):
        if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
            raise TypeError('註釋不能爲空')

        super(Mymeta,self).__init__(class_name,class_bases,class_dic)

        self.__instance = None
    def __call__(self, *args, **kwargs):
        if not self.__instance:
            obj = object.__new__(self)
            self.__init__(obj)
            self.__instance = obj
        return self.__instance

class Mysql(object,metaclass=Mymeta):
    '''
    xxx
    '''
    def __init__(self):
        self.host = '127.0.0.1'
        self.port = 3306

obj1 = Mysql()
obj2 = Mysql()
print(obj1 is obj2)
面向對象的軟件開發
相關文章
相關標籤/搜索