面向對象高級進階

一.類中的裝飾器的使用:property,classmethod,staticmethod,python

property的使用:property 的做用是講一個類的函數屬性裝飾成對象的一個數據屬性,可以直接被對象.方法名 調用,不用去經過加()的方式調用。面試

當property去裝飾一個類的函數方法時,與setattr,delattr 共用時,@name.setattr @name.delattr 前面的前綴必須相同json

property的本質就實現了 get,set,del 三個方法dom

class Foo:
    @property
    def AAA(self):
        print('get的時候運行我啊')

    @AAA.setter
    def AAA(self,value):
        print('set的時候運行我啊')

    @AAA.deleter
    def AAA(self):
        print('delete的時候運行我啊')

#只有在屬性AAA定義property後才能定義AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA
class Goods:

    def __init__(self):
        # 原價
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    @property
    def price(self):
        # 實際價格 = 原價 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    @price.setter
    def price(self, value):
        self.original_price = value

    @price.deleter
    def price(self):
        del self.original_price


obj = Goods()
obj.price         # 獲取商品價格
obj.price = 200   # 修改商品原價
print(obj.price)
del obj.price     # 刪除商品原價
property的做用實例
#實現類型檢測功能

#第一關:
class People:
    def __init__(self,name):
        self.name=name

    @property
    def name(self):
        return self.name

# p1=People('alex') #property自動實現了set和get方法屬於數據描述符,比實例屬性優先級高,因此你這面寫會觸發property內置的set,拋出異常


#第二關:修訂版

class People:
    def __init__(self,name):
        self.name=name #實例化就觸發property

    @property
    def name(self):
        # return self.name #無限遞歸
        print('get------>')
        return self.DouNiWan

    @name.setter
    def name(self,value):
        print('set------>')
        self.DouNiWan=value

    @name.deleter
    def name(self):
        print('delete------>')
        del self.DouNiWan

p1=People('alex') #self.name實際是存放到self.DouNiWan裏
print(p1.name)
print(p1.name)
print(p1.name)
print(p1.__dict__)

p1.name='egon'
print(p1.__dict__)

del p1.name
print(p1.__dict__)


#第三關:加上類型檢查
class People:
    def __init__(self,name):
        self.name=name #實例化就觸發property

    @property #當property將一個類的函數屬性定義與__init__中的名字同樣時,
    # 因爲property的優先級更高會優先執行property,而property必須經過setter方法去設置對象的新的屬性
    def name(self):
        # return self.name #無限遞歸
        print('get------>')
        return self.DouNiWan

    @name.setter
    def name(self,value):
        print('set------>')
        if not isinstance(value,str):
            raise TypeError('必須是字符串類型')
        self.DouNiWan=value

    @name.deleter
    def name(self):
        print('delete------>')
        del self.DouNiWan

p1=People('alex') #self.name實際是存放到self.DouNiWan裏
p1.name=1

案例二
property的實例1

2.classmethod:ide

class Classmethod_Demo():
    role = 'dog'

    @classmethod #做用及時統一了對象和類調用方法的方式,都是經過同一種方式去調用
    def func(cls):
        print(cls.role)
    def func1(self):
        print(self.role)

Classmethod_Demo.func()
Classmethod_Demo.func1() #必須傳一個參數才能實現類調用去下的函數屬性。

3.staticmethod:函數

class Staticmethod_Demo():
    role = 'dog'

    @staticmethod #做用就是當成普通的函數方法使用,類與對象都不用傳參數
    def func():#注意不自動傳self值了
        print("當普通方法用")

Staticmethod_Demo.func()
s =Staticmethod_Demo()
s.func()
#1...__new__方法的使用:就是構造方法,建立一個對象
#單例模式:一個類從始至終只實例化一個對象,單例模式的模擬
"""
class A:
    __issingle = False
    def __init__(self,name,age):
        print('執行的init方法')
        self.name = name
        self.age = age
    def __new__(cls, *args, **kwargs):
        print('執行的new方法')
        if cls.__issingle:
            return cls.__issingle
        cls.__issingle = object.__new__(cls)
        return cls.__issingle
a1 = A('yuan',18)
a2 = A('rong',18)
a1.id = '001'
print(id(a1),id(a2)) #在內存中的id都是相同的,實際上操做的是同一個對象
print(a1.name,a2.name)
print(a1.age,a2.age)
print(a1.id,a2.id)# a2對象而言並無id屬性,用的就是a1.id,實際上就是操做同一個實例化對象
"""
內置方法__new__的解析
#.2.item系列的方法: 字典類型的數據就是經過item的內置方法去建立和操做的。
"""
class A:
    def __init__(self,name):
        self.name = name
    def __getitem__(self, item):
        print('執行的getitem方法')
        return self.__dict__[item]
    def __setitem__(self, key, value):
        print('執行的setitem方法')
        self.__dict__[key] = value
        return self.__dict__
    def __delitem__(self, key):
        print('執行的delitem方法')
        del self.__dict__[key]
    def __delattr__(self, item):
        print('執行的delattr方法')
        del self.__dict__[item]
        pass
a = A('yuan')
# print(a.name)
# print(a['name'])
# a.age = 18
a['age'] = 19  
print(a.age)
del a['age'] #若是執行del 語句,會執行__delitem__方法,
del a.age # 若是執行del 語句,會執行__delattr__方法,就是兩種刪除的方法不同執行調用類的方法就不同,
#若是即沒有delitem和delattr方法就會去執行父類中的方法,都沒有就執行object中的delattr方法
print(a.age)
"""
item系列的解析
#__str__:能夠控制對象的屬性詳細的說明的方法,當類中沒有__str__方法時候,會調用__repr__
"""
class A:
    def __str__(self):
        print('這是A類本身的__str__方法')
        return 'A' #能夠在這裏面定義本身想要定義返回的信息
a = A()
print(a)#當類中沒有定義本身的__str__方法時,會去object中找__str__方法,會返回這個對象的內存地址
#而當類中有本身定義的__str__方法時會優先執行執行的__str__方法,print一個對象的時候會自動執行該對象下的
#__str__方法,該對象的類中沒有,找父類,父類沒有,找object中。
print(str(a))
%s,str() 就是調用類下的__str__方法
"""
__str__方法的解析
# __repr__:將對象的原始數據格式打印到終端,當類中沒有__repr__時候,不能調用__str__方法。
#%r repr() 就是調用了類下的__repr__方法
"""
class A:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __repr__(self):
        print('這是本身的repr方法')
        return str(self.__dict__) #跟str的返回值同樣,必須返回一個字符串
a = A('yuan',18)
print('%r'% a)#至關於調用_repr__方法
print(repr(a))
"""
__repr__的解析
#__del__:析構函數
# 做用通常是在文件打開後作的收尾工做,與內置的垃圾回收裝置相關
"""
import time
class A:
    def __del__(self):
        print('執行本身的del方法')
a = A()  #若是一個程序代碼都執行完以後,會自動執行對象中的__del__方法,即沒有手動
# del 對象也會執行__del__裏面的代碼,與python中的垃圾回收裝備有關聯關係。
time.sleep(3) 
"""
析構函數__del__的解析
#__call__:當一個對象被調用的時候會自動執行該對象下的__call__方法
"""
class A:
    pass
    # def __call__(self, *args, **kwargs):
    #     print('執行本身的call方法')
a = A() #至關於執行了 a() ,就是自動執行該對象下的__call__方法
#若是沒有該對象下沒有__call__方法,及時提示報錯,只會從該對象的父類中查找是否有
#__call__方法,不會去object中找尋__call__方法,
a()
"""
__call__方法的解析
#__eq__:判斷兩個對象是否相等,默認的是比較兩個對象的內存地址,若是須要從新
#定製本身的判斷相等的方法,只須要在__eq__中定義本身的方法
"""
class A:
    def __init__(self,name):
        self.name = name

    def __eq__(self, other):
        if self.name == other.name:
            return True
a1 = A('yuan')
a2 = A('yuan')
print(a1 == a2) # 若是沒有定製本身的__eq__,就默認執行object中的__eq__,默認比較兩個對象的內存地址
"""
__eq__方法的解析
#__hash__:得到對象的hash值
"""
a = 10
a1 ='abc'
l = [1,2,3]
print(hash(a))
print(hash(a1))
print(hash(l)) #可變數據類型是不能夠被hash的
"""
hash()內置函數
#內置方法的實例,使用內置方法會使代碼更加的優美
#1 實例一  模擬一副撲克牌
"""
import random
import json
from collections import namedtuple
from random import shuffle
Card = namedtuple('Card',['rank','suits'])

class Poke:
    ranks = [str(rank) for rank in range(1,11)] + list('JQKA')
    suits = ['紅心','黑桃','方塊','梅花']
    def __init__(self):
        self.__cards = [Card(rank,suit) for rank in Poke.ranks for suit in Poke.suits]
    def __getitem__(self, item): #想要經過[]的形式去取值,就要設置本身的__len__方法,
        return self.__cards[item]
    def __len__(self):
        return len(self.__cards)
    def __setitem__(self, key, value):
        self.__cards[key] = value
    def __str__(self):#想要定義本身的__str__就必需要定義本身的__setitem__方法
        return json.dumps(self.__cards,ensure_ascii=False)#__str__可視化要進行json序列化一下

c = Poke()
print(c[0]) #取得是第一張牌
print(c[0][0])#取得是第一張牌的數字
print(c[0][1])#取得是第一張牌的花色
print(random.choice(c))
print(c)
shuffle(c)#完成洗牌操做
print(c)
print(c[:5])#直接去經過__getitem__方法去實現的,相似於用字典的關鍵字去取值同樣
"""
內置方法的結合使用:撲克牌的模擬
#2.實例一  一道面試題
#1.有100的對象,名字和性別相同,但年齡不一樣

class A:
    def __init__(self,name,sex,age):
        self.name = name
        self.sex = sex
        self.age = age
    def __eq__(self, other):#加了__eq__才能完成去重,內置判斷去重不是簡單的判斷hash,仍是與__eq__相關聯
        if self.name == other.name and self.sex == other.sex:
            return True
        return False
    def __hash__(self):
        return hash(self.name + self.sex)

a1 = A('yuan','male',18)
a2 = A('yuan','male',18)


print(set((a1,a2)))# 仍是沒有完成去重,加了__hash__和__eq__才能完成去重
"""
如何去實現去重的機制
a1 = A('yuan','male',18)
a2 = A('yuan','male',19)
print(a1)
print(a2)
print(a2.__dict__)

res =set((a2,a1))# 仍是沒有完成去重,加了__hash__和__eq__才能完成去重
print(list(res)[0].__dict__) #完成了去重,獲得去重後的值
相關文章
相關標籤/搜索