Python3---魔术方法,new方法和单例,定制属性访问

一.魔术方法

__名字__  这样的形式就是魔术方法

(一)举例:__add__

class Rectangle(object):
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def get_area(self):
        return self.length * self.width

    def __add__(self, other):  #__add__魔术方法,相加
        add_length = self.length + other.length
        add_width = self.width + other.width
        return add_length, add_width

rec1 = Rectangle(10,8)
rec2 = Rectangle(20,15)
print(rec1 + rec2)
运行结果:
(30, 23)

到底是怎么回事呢?

>>> a =1
>>> a = 1
>>> b =2
>>> a + b
3
>>> b.__add__(a)  #实际a + b 就等同于 b.__add__(a)
3
魔术方法之运算方法:
__add__(self,other) # x+y
__sub__(self,other) # x-y
__mul__(self,other) # x*y
__mod__(self,other) # x%y
__iadd__(self,other) # x+=y
__isub__(self,other) # x-=y
__radd__(self,other) # y+x
__rsub__(self,other) # y-x
__imul__(self,other) # x*=y
__imod__(self,other) # x%=y

(二)字符串引入 __str__ 和__repr__

在python中,str和repr方法在处理对象的时候,分别调用的是对象的
class Rectangle:

    def __init__(self,length,width):

        self.length = length            

        self.width  = width  

    def area(self):        

        areas = self.length * self.width        

        return areas

    def __str__(self): 
    
        return 'length is %s, width is %s '%(self.length, self.width)

    def __repr__(self):

        return 'area  is %s'%self.area()

a = Rectangle(3,4)
print(a) #实际默认调用__str__
print(str(a))
print(repr(a))

运行结果:

length is 3, width is 4 
length is 3, width is 4 
area  is 12

如果在类中没有定义 __str__和__repr__方法,则会调用object中的__str__方法:

class Rectangle:

    def __init__(self,length,width):

        self.length = length            

        self.width  = width  

    def area(self):        

        areas = self.length * self.width        

        return areas

    #def __str__(self): #向使用者提供尽可能简洁且有用的信息
     
        #return 'length is %s, width is %s '%(self.length, self.width)

    #def __repr__(self):#向开发者提供接近创建时的信息
    
        #return 'area  is %s'%self.area()

a = Rectangle(3,4)
print(a)

运行结果:

<__main__.Rectangle object at 0x0000000002F2D978> #在类中没有定义__str__和__repr__方法,默认调用类中的__str__方法
__str____repr__方法
print也是如此,调用str函数来处理输出的对象,如果对象没有定义 __str__方法,则调用repr处理

在 shell 模式下,展示对象 __repr__ 的返回值

对使用者使用友好的 __str__

对开发者调试友好的 __repr__

更多详情可以参考:https://blog.csdn.net/zss041962/article/details/78926718

(三)类的实例可以像函数一样被调用吗?

正常情况下,实例是不能像函数一样被调用的,要想实例能够被调用,就需要定义 __call__  方法

class Rectangle:


    def __init__(self,length,width):

        self.length = length            

        self.width  = width  


    def area(self):        

        areas = self.length * self.width
    def __call__(self,*args,**kwargs):
        print('类的实例像函数一样调用必须加__call__方法哦~')


#def myfunc():
#    pass
#myfunc() 函数调用,函数名+()
#rec1()类的实例不能直接这样,会报错,除非调用__call__方法

rec1 = Rectangle(10,20)
rec1()

运行结果:

类的实例像函数一样调用必须加__call__方法哦~

其他的一些魔术方法:

__class__ 查看类名
__base__ 查看继承的父类
__bases__ 查看继承的全部父类
__dict__ 查看全部属性,返回属性和属性值键值对形式
__doc__ 查看对象文档,即类中的注释(用引号注视的部分)
__dir__ 查看全部属性和方法

二.__new__方法:节省内存

引入:类每次实例化的时候都会创建一个新的对象,如果要求类只能被实例化一次该怎么做呢?

单例的设计模式:

class Earth:
    def __new__(cls):
        if not hasattr(cls, 'instance'):#cls代表类本身,hasattr判断类中有没有('instance')参数
            cls.instance = super().__new__(cls)  #如果没有就调用object中new方法
        return cls.instance
    def __init__(self): #self代表实例本身
        self.name = '单例'

e = Earth()
print(e, id(e))
a = Earth()
print(a, id(a))

运行结果:

<__main__.Earth object at 0x0000000003064588> 50742664
<__main__.Earth object at 0x0000000003064588> 50742664
在上面的例子中,我们可以看到两个实例的ID是相同的,意味着这两个其实引用的是同一个实例(只占一个内存),是一个实例的不同名字

初始化一个类的时候所做的操作:

a = Earth().__new__()#当我们初始化一个实例的时候,会在内存中开辟一个空间
Earth.__init__(a)

三.定制访问属性

作用方法返回
hasattr(re, 'length') 返回bool值
 getattr(re,  'length')返回属性值
 b. __getattribute__('length')返回全部属性值
setattr(b, 'length', 6) 
 b.__setattr__('length', 5) 
b.aaa = 1 
 setattr(b, 'bbb', 2) 
 b.__setattr__('ccc', 3) 
delattr(b, 'ccc') 
 b.__delattr__('bbb') 
 del b 

注:print(hasattr(实例rec1,属性'length'))等效于print(rec1.__hasattr__('name'))

class Animal(object):
    def __init__(self,name):
        self.name = name

    def eat(self):
        print('%s正在吃东西'%self.name)

    def breath(self):
        print('%s正在呼吸'%self.name)

##    def __getattribute__(self,item):
##        return '不给你看'#修改了__getattribute__这个方法的返回值

##    def __getattr__(self,item):#如果不写这个方法,当查找一个不存在的属性的时候,会报错
##        return '没有这个值'
    
spider = Animal('蜘蛛')
print(hasattr(spider,'speak'))#返回bool值,判断实例里面有没有某个属性

'''spider.name默认调用__getattribute__这个方法,如果__getattribute__这个方法没有找到我们要查找的属性,就会调用__getattr__方法'''
print(getattr(spider,'name'))#返回属性值,和spider.name一致
print(spider.name)#实际和 print(spider.getattribute__('name'))一致
setattr(spider,'legs',8)#添加属性,修改属性,和spider.legs = 8一致
print(spider.legs)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值