面向对象高级进阶

一.类中的装饰器的使用:property,classmethod,staticmethod,

property的使用:property 的作用是讲一个类的函数属性装饰成对象的一个数据属性,能够直接被对象.方法名 调用,不用去通过加()的方式调用。

当property去装饰一个类的函数方法时,与setattr,delattr 共用时,@name.setattr @name.delattr 前面的前缀必须相同

property的本质就实现了 get,set,del 三个方法

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:

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__) #完成了去重,得到去重后的值

 

posted @ 2019-04-21 15:18  心动丶男孩  阅读(133)  评论(0编辑  收藏  举报