Python魔术方法
__
开头,__
结尾的方法就是魔术方法.
- 1.
__str__
格式化输出对象
__repr__
表示对象本身
class A:
def __str__(self):
return 'This is A'
# 表示对象本身
def __repr__(self):
return "I'm a A"
a = A()
print(a) # This is A
a # I'm a A
- 2.
__init__
和__new__
__init__
初始化实例,无返回值
__new__
创建一个实例,并返回类的实例.
__new__
是一个特殊的类方法,不需要使用@classmethod来装饰.
使用__new__
单例模式
# 借助__new__方法实现单例模式
class Singleton:
instance = None
def __new__(cls, *args, **kwargs):
# 判断实例对象是否已经存在
if cls.instance is None:
# 说明实例对象不存在.需要创建
cls.instance = super().__new__(Singleton, *args, **kwargs)
return cls.instance
s = Singleton()
s2 = Singleton()
s is s2
out: True
display(id(s), id(s2))
out: 78960288 78960288
- 3.数学运算、比较运算
运算符重载
+:
__add__(value)
-:__sub__(value) substract
*:__mul__(value) mulply
/:__truediv__(value) (Python 3.x), __div__(value) (Python 2.x) divide
//:__floordiv__(value)
%:__mod__(value)
&:__and__(value)
|:__or__(value)
# 自定义字典的加法
class Dict(dict):
# 实现加法
def __add__(self, other):
# 判断other是否是字典.
if isinstance(other, dict):
new_dict = {}
new_dict.update(self)
new_dict.update(other)
return new_dict
else:
raise TypeError('not a dict')
d1 = {1: 11, 2: 22}
d2 = {1: 111, 2: 222, 3:333}
dd1 = Dict(d1)
dd1 + d2
out:{1: 111, 2: 222, 3: 333}
# 定义一个类,长方形 , 让长方形类的实例对象可以实现减法操作.
class Rectangle:
def __init__(self, height, width):
self.height = height
self.width = width
# 实现减法
def __sub__(self, other):
if isinstance(other, Rectangle):
return Rectangle(abs(self.height - other.height), abs(self.width - other.width))
else:
raise TypeError('not a rectangle')
def __repr__(self):
return f'<Rectangle ({self.height}, {self.width})>'
r1 = Rectangle(1,2)
r2 = Rectangle(1,1)
r1 - r2
out:<Rectangle (0, 1)>
比较运算符的重载
==: __eq__(value)
!=: __ne__(value)
>: __gt__(value)
>=: __ge__(value)
<: __lt__(value)
<=: __le__(value)
# 定一个类实现数学上的无穷大
class Inf:
def __eq__(self, other):
return False
def __ne__(self, other):
return True
def __gt__(self, other):
return True
def __ge__(self, other):
return False
def __lt__(self, other):
return False
def __le__(self, other):
return False
inf = Inf()
inf > 20 ** 10000
out:True
# 练习: 写个长方体, 让长方体的实例对象之间可以比体积大小.
# 优化版本
class Cuboid:
def __init__(self, lenght, width, height):
self.lenght = lenght
self.width = width
self.height = height
@property
def V(self):
return self.lenght * self.width * self.height
def __gt__(self, other):
if isinstance(other, Cuboid):
return self.V > other.V
else:
raise TypeError('not a cuboid')
def __repr__(self):
return f'<Cuboid ({self.lenght}, {self.width}, {self.height}>'
c1 = Cuboid(2,3,4)
c2 = Cuboid(1,1,1)
c1 > c2
out:True
sorted([c1,c2]) # 对体积进行排序
out:[<Cuboid (1, 1, 1>, <Cuboid (2, 3, 4>]
- 4.容器方法
__len__ -> len
__iter__ -> for
__contains__ -> in
__getitem__
对 string, bytes, list, tuple, dict 有效
__setitem__
对 list, dict 有效
__missing__
对 dict 有效, 字典的预留接口, dict 本身并没有实现
l = [1,2,3]
len(l)
out:3
l.__len__()
out:3
l[0]
out: 1
l.__getitem__(0)
out: 1
l[0] = 8
l
out:[8, 2, 3]
l.__setitem__(0,10)
l
out: [10, 2, 3]
d1 = {1: 111, 2: 222, 3: 333}
d1[0]
out:---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-77-f64ff61913e8> in <module>()
----> 1 d1[0]
KeyError: 0
# 让字典的key找不到的时候,不要报错.返回空列表
class Dict(dict):
def __missing__(self, key):
return []
ddd = Dict(d1)
ddd[0]
out: []
- 5.上下文管理 with:
__enter__
进入 with 代码块前的准备操作
__exit__
退出时的善后操作
文件对象、线程锁、socket 对象 等 都可以使用 with 操作
with 不管with语句块中是否出现异常,资源依然可以被正常的释放.
exceptions = []
class A:
def __enter__(self):
print('enter....')
print(self)
return self
def __exit__(self, Error, error, Exception):
print(Error, error, Exception)
exceptions.append(Error)
exceptions.append(error)
exceptions.append(Exception)
print('exiting....')
with A() as a:
print(a)
print('------------------')
raise TypeError()
out:enter....
<__main__.A object at 0x0000000004E44940>
<__main__.A object at 0x0000000004E44940>
------------------
<class 'TypeError'> <traceback object at 0x0000000004DD9848>
exiting....
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-111-421bdf2504b3> in <module>()
2 print(a)
3 print('------------------')
----> 4 raise TypeError()
5
TypeError:
exceptions
out:[TypeError, TypeError(), <traceback at 0x4dd9848>]
Error, error, trace = exceptions
import traceback
traceback.print_exception(Error, error, trace) # 打印出异常
out:Traceback (most recent call last):
File "<ipython-input-111-421bdf2504b3>", line 4, in <module>
raise TypeError()
TypeError
python的内省
setattr() # 设置属性
__setattr__()
getattr() # 获取属性__getattribute__
hasattr() # 判断是否有某个属性
class A:
def __init__(self, x, y):
self.x = x
self.y = y
a = A(1,2)
setattr(a, 'z', 3)
a.z
out: 3
a.__setattr__('z', 9)
a.z
out: 9
getattr(a, 'x')
out: 1
a.__getattribute__('x')
out: 1
# __getattr__当__getattribute__找不到属性的时候,会执行__getattr__
# 默认获取不到会报错
getattr(a, 'a', 0)
out: 0
hasattr(a, 'a')
out: False
'a' in a.__dict__
out: False # 没有a.__hasattr__('a')
# 常用于属性监听
class User:
'''TestClass'''
z = [7,8,9]
def __init__(self):
self.money = 10000
self.y = 'abc'
def __setattr__(self, name, value):
if name == 'money' and value < 0:
raise ValueError('money < 0')
print('set %s to %s' % (name, value))
object.__setattr__(self, name, value)
def __getattribute__(self, name):
print('get %s' % name)
return object.__getattribute__(self, name)
def __getattr__(self, name):
print('not has %s' % name)
return -1
def foo(self, x, y):
return x ** y
# 对比
a = User()
# print(User.__dict__)
# print(a.__dict__)
out: set money to 10000
set y to abc
a.money -= 11000 # = a.money = a.money - 11000
out: get money
---------------------------------------------------------------------------
ValueError
---> 11 raise ValueError('money < 0')
12 print('set %s to %s' % (name, value))
13 object.__setattr__(self, name, value)
ValueError: money < 0
- 8.槽:
__slots__
固定类所具有的属性
实例不会分配__dict__
实例无法动态添加属性
优化内存分配, 大概能节约40%的内存.
class B:
__slots__ = ['x', 'y']
b = B()
b.x = 10
b.x
out: 10
b.z = 10
out: ---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-147-47de4eac37de> in <module>()
----> 1 b.z = 10
AttributeError: 'B' object has no attribute 'z'
b.__dict__ # 报错没有__dict__
out:---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-148-395029f23f31> in <module>()
----> 1 b.__dict__
AttributeError: 'B' object has no attribute '__dict__'
网友评论