Python面向对象高级、魔法方法与协议

(一)面向对象高级

常用的内置函数

上一篇文章讲到了类的定义和基本使用,可以通过点操作符去访问属性和方法,但是如果属性不存在会怎么办呢?同时不希望因为属性不存在而报错又该怎么处理呢?下面介绍几个能够帮助我们解决问题的关键词:

##has   判断属性存不存在
##get   获取属性
##set   设置属性
##attr  属性


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

zs = Person('张三',20)

print(hasattr(zs,'sex'))
print(getattr(zs,'name'))

在这里插入图片描述
通过运行可以看到,使用hasattr()判断属性是否存在时,结果返回的是布尔值(True or False)。而getattr()和我们在交互模式中使用zs.name获取的结果也是一样的,这是因为实际上我们在使用zs.name时,底层方法就是在使用getattr(),只不过我们平时是使用后者,而系统帮我们自动调用getattr()。接下来是setattr()

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

zs = Person('张三',20)

setattr(zs,'name','李四')

在这里插入图片描述

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

zs = Person('张三',20)

setattr(zs,'sex','男')

在这里插入图片描述
从这里对比可以看出,setattr()方法对于属性是否存在,运行结果是有区别的,如果属性已经存在,则会替换原来属性的内容,如果属性不存在,则会设置添加新的属性。这里的添加是对实例对象的单独添加,与初始时设置无关。比如在设置一个实力对象小蔡,则不会有sex这个属性。当不存在属性且不想要报错时,可以使用if语句。

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

zs = Person('张三',20)

if hasattr(zs,'sex'):
    print(getattr(zs,'sex'))
else:
    setattr(zs,'sex','男')

在这里插入图片描述
这里关于setattr()没有写print是根据功能来判断的,gerattr()是我们需要获取到内容,所以需要print来返回给我们,而setattr()只是添加进新的属性,并不需要返回值,需要值的话只需要对其进行操作就可以了。
最后再补充三个关键词:delattr() #删除属性 type() 查看数据类型并返回类型
isinstance(数据,(类型1,类型2,类型3)) 判断数据是否属于某个类型

(二)魔法方法

①Python中很多内置方法都是两个下划线在两边,中间是单词名字,并且这样的方法名字有一定的特殊的含义,把这种方法都称之为魔法方法。
我们知道实例对象都不是互通的,都有自己独立的空间,如果我想要让实例对象完全互通,可以使用new方法来完成单例模式(单个实例)。

class Person():
    pass
    
a = Person()
b = Person()

在这里插入图片描述
这里我们定义两个实例对象,通过id()方法可以看出这两个实例对象是各自独立的。这个时候如果我们给a赋值,那么b是不会有相同的值的。如果我们想要a和b同步接收数据,这时就要用到单例模式。

class Person():
    def __new__(cls):  #cls类本身,通过具体的类生成属于这个类的实例对象
        if not hasattr(cls,'_instance'): 
            cls._instance = super().__new__(cls)   #super调用父类函数
        return cls._instance


a = Person()
b = Person()

在这里插入图片描述
这段代码通过if判断是否有_instance这个属性,如果没有执行下一行的代码,通过调用父类函数生成一个实例对象,通过return返回给实例对象进行下一次循环,第二次循环已经有了实例对象,则if语句不会执行,还是返回之前的实例对象,如此反复。所以都是同一个实例对象,无论对哪个操作,都会同步实现。

②现在有一个列表实例对象和Person实例对象
在这里插入图片描述
可以看到这两个实例对象的访问结果是不一样的,这是因为它们所使用的底层魔法方法是不一样的。我们可以通过修改底层代码来打印我们想要的内容。

class Person():
    def __str__(self):   # 修改访问实例对象时返回的结果
        return '这是str打印的对象'
    def __repr__(self):
        return'这是repr打印的对象'
a = Person()
b = Person()

在这里插入图片描述
可以看到a和print(a)渲染的方式不一样,打印的结果也是不一样的。

③实例对象正常情况下是不能被调用的,如果想要实例对象像函数一样被调用可以用

    def __call__(self):      #让实例对象可以和函数一样被调用
        print('这是Person实例对象调用的结果')

(三)协议

(1)序列协议

把类变成列表或元组这种序列类型,通过下标去获取值。

class IndexTuple:
    def __init__(self,*args):    #如果不确定有多少个数据,定义一个不定长*args
        self.values = args       #arg本身就是元组
        self.index = tuple(enumerate(self.values))   #获取到每一个元素的下标

    def __len__(self):
        return len(self.values)    #通过len方法获取当前类有多少个元素

    def __getitem__(self,key):      #通过下标获取值
        return self.index[key]

    def __repr__(self):
        return str(self.values)


a = IndexTuple(1,2,3,'a','b',True)

在这里插入图片描述
Python中有很多协议,只要遵守这些协议,即可以说是对应的类型,比如上面定义了序列协议,那么这个类就是序列类型。

(2)迭代器协议

我们所知道的for循环就是遵循迭代器协议。iter 可迭代对象 next 迭代器

class number:
    def __init__(self,end=10):    #定义初始化条件
        self.start = 0
        self.end = end

    def __iter__(self):          
        return self

    def __next__(self):
        res = self.start
        self.start+=1             #和rage的步长类似,每次累加为1
        if self.start > self.end:
            raise StopIteration   #抛出异常,for循环会自东处理
        return res

for i in number(10):
    print(i)

在这里插入图片描述
所以我们所使用的类似for循环的方法都不是凭空产生的,都是Python前辈已经写好了这些功能,让我们使用起来更便捷。

(3)上下文协议

开始和结束时会自动调用对应的方法。

import time              #时间模块
class Runtime:           #运行时长
    def __enter__(self): #开始运行要做的事情
        self.start_time = time.time()
        return self.start_time

    def __exit__(self,exc_type,exc_val,exc_tb): #结束的时候要做的事情(self后面三个分别对应报错的类型,报错的内容,报错的信息)
        self.end_time = time.time()
        print('程序运行时间为',self.end_time-self.start_time)


with Runtime():
    for i in range(1000000):
        pass

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值