1. 程式人生 > 實用技巧 >8.面向物件

8.面向物件

目錄

一、類的屬性問題

新增物件屬性

可以在類中,在__init__方法中使用self.屬性名 = 值,在內外使用物件名.屬性名 = 值

新增類的靜態屬性

內中但是不再__init__方法中,屬性名=值,在類外,類名.屬性名 = 值。

物件找類屬性的順序

先在本類中找,找不到再去父類中找

二、類與類之間的關係

2.1 依賴關係

一個類的物件可以作為另一個類中方法的引數,在該方法中可以呼叫該物件擁有的方法。

class A:
    def __init__(self):
        pass
    def funca(self):
        print('你好')
class B:
    def __init__(self):
        pass
    def funcb(self, obj):
        obj.funca()

a = A()
b = B()
b.funcb(a)		# 你好

2.2 關聯,聚合,組合

組合:將一個類的物件封裝到另一個類的物件的屬性中,就叫組合。

另一個類的物件可以呼叫這個類物件的屬性個方法。

三、繼承與多型

繼承的優點:

  • 增加了類的耦合性
  • 減少了重複程式碼
  • 使得程式碼更加規範化,合理化

3.1 繼承的分類

單繼承和多繼承:

# 多繼承
class A(object):
    def func(self):
        print("A")

class B(A):
    def func(self):
        super().func()
        print('B')
    
class C(A):
    def func(self):
        super().func()
        print('C')

class D(B,C):
    def func(self):
        super().func()
        print('D')

D().func()
# 找的順序是DCBA,執行順序為ABCD

3.2 多型

父類對於子類的約束,只要有這種類,子類必須實現和父類中同名的方法

實現多型的方法,抽象類。子類繼承一個抽象類並重寫抽象類中的方法。

# 父類對於子類的約束,只要有這種類,子類必須實現和pay同名的方法
# class Payment():
#     def pay(self, money):   # money引數在子類中也是必須的
#         raise NotImplementedError('請在子類中重寫pay方法')
# 實現抽象類的類一種方法,約束性強,但是依賴abc模組
from abc import ABCMeta, abstractclassmethod
class Payment(metaclass=ABCMeta):
    @abstractclassmethod
    def pay(self, money):   # money引數在子類中也是必須的
        raise NotImplementedError('請在子類中重寫pay方法')

3.3 例項化

例項化物件時必須執行__init__方法,類中沒有,從父類找,父類沒有,從object類中找。

例項化所經歷的步驟

  1. 類名() 之後的第一個事兒 :開闢一塊兒記憶體空間
  2. 呼叫 __init__ 把空間的記憶體地址作為self引數傳遞到函式內部
  3. 所有的這一個物件需要使用的屬性都需要和self關聯起來
  4. 執行完init中的邏輯之後,self變數會自動的被返回到呼叫處(發生例項化的地方)

四、反射

用字串資料型別的名字,來操作這個名字對應的函式\例項變數\繫結方法\各種方法

使用反射場景

  1. 反射物件的 例項變數

  2. 反射類的 靜態變數/繫結方法/其他方法

  3. 模組中的 所有變數

    被匯入的模組

    	當前執行的py檔案
    

4.1 反射物件的 例項變數

# 物件名.屬性名  --> getattr(物件名, '屬性名') 

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

    def func(self):
        print('getattr')
an = Person('an',11)
ret = getattr(an,'name')
print(ret)

ret = getattr(an, 'func')  # 返回funcdi地址
print(getattr(a, 'func')())   # 反射物件的繫結方法
print(ret)

4.2 反射模組中的所有變數

# 反射模組中的所有變數
import a
print(getattr(a, 'sww'))
print(getattr(a, 'lst'))

# print(getattr(a,'Alipay'))
# print(getattr(sys.modules['a'],'Alipay'))

# wahaha = 'hahaha'
# print(getattr(sys.modules['__main__'],'wahaha'))

4.3.1 反射本模組中內容

import sys
dog = 'aqwefr'
print(getattr(sys.modules['__main__'],'dog'))

# 反射的另一個方法,hasattr返回bool
if hasattr(a, 'name'):
  	getattr(a, 'name')
callable(a.name) # 判斷是否可呼叫,返回bool

五、內建的魔術方法

_new_

_call_ 物件呼叫這個類中的__call__方法

_len_ len(物件)需要實現類中的__len__方法

_eq_

_str_

_repr_

六、裝飾器函式

@classmethod 傳入cls表示當前類

class Goods:
    __discount = 0.8
    def __inti__(self):
        self.__price = 5
        self.price = self.__discount*self.__price
    # 把一個物件繫結的方法修改成類繫結的方法
    # 在方法中可以應用類中的靜態變數,不用例項化物件
    @classmethod
    def change_discount(cls,new_discount):
        cls.__discount = new_discount

Goods.change_discount(0.6)
import time
class Date:
    def __init__(self,year, month, day):
        self.year = year
        self.month = month
        self.day = day
    @classmethod
    def today(cls):
        struct_t = time.localtime()
        date = cls(struct_t.tm_year, struct_t.tm_mon, struct_t.tm_mday)
        return date

date = Date.today()
print(date.year)
print(date.month)
print(date.day)

@staticmethod 靜態方法

class User:
    # 類外函式放到類內,不用self引數,也不用例項化
    @staticmethod
    def login():
        pass

User.login()