一.魔术方法
__名字__ 这样的形式就是魔术方法
(一)举例:__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
魔术方法之运算方法:
# 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__
更多详情可以参考:
(三)类的实例可以像函数一样被调用吗?
正常情况下,实例是不能像函数一样被调用的,要想实例能够被调用,就需要定义 __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)