常规:
__del__
魔术方法:
对象即将被释放的时候,会调用这个方法。注意如果这个对象产生了循环引用,并且实现了__del__方法,那么这个对象将得不到释放,从而产生内存泄漏。因此慎用这个方法。
__new__
魔术方法:
这个方法用来创建对象。如果想在创建对象的时候做些事情,那么可以重写这个方法。
__class__
魔术属性:
用来返回这个对象所属的类。如果一个类调用这个属性,那么得到的是这个类的元类。
__iter__
魔术方法:
返回一个迭代器。
__next__
魔术方法:
迭代器在被遍历的时候会每遍历一次调用这个方法(在Python3中,在Python2中使用的是next方法)
__str__
魔术方法:
- 在打印某个对象的时候,会调用这个对象的
__str__
方法,打印这个方法的返回值。
class Person(object):
def __init__(self,name):
self.name = name
p1 = Person('zhouxin')
print(p1)
# 打印出来的结果:
# <__main__.Person object at 0x008AD170>
而重写了__str__方法,那么打印出来的就是__str__的返回值:
class Person(object):
def __init__(self,name):
self.name = name
def __str__(self):
return 'Person<%s>' % self.name
p1 = Person('zhouxin')
print(p1)
# 打印出来的结果:
# Person<zhouxin>
- 如果在使用
str(obj)
这个函数的时候,也会调用__str__
方法。
__repr__
魔术方法:
__repr__
魔术方法是用来表述某个对象在内存中的展示形式- 如果在终端直接输入一个对象,然后按回车,那么将会执行这个对象的
__repr__
方法。 - 如果你将几个对象扔到一个容器中(比如:列表),那么你在打印这个容器的时候,会依次调用这个容器中的元素的
__repr__
方法。如果没有实现这个__repr__
方法,那么得到的将是一个类名+地址
的形式,这种形式的是不好理解的。
class Person(object):
def __init__(self,name):
self.name = name
def __repr__(self):
return "Person(%s)" % self.name
p1 = Person('zhouxin1')
p2 = Person('zhouxin2')
a = [p1,p2]
print(a)
# 打印的结果:
[Person(zhouxin1), Person(zhouxin2)]
__dict__
魔术属性:
- 用来获取用户自定义的属性,以及这个属性对应的值。返回的是一个字典。
- 和
dir
函数做一个区分。dir
函数返回的是这个对象上拥有的所有属性,包括Python
内置的属性和用户自己添加的,并且只是获取属性名字,不会获取这个属性对应的值。
比较:
__cmp__
魔术方法:
__cmp__(self,other)
这个方法在Python2
中可以正常使用。如果self
是大于other
的,那么应该返回正数,如果self
等于other
,那么应该返回0,如果self
小于other
,那么应该返回负数。
这个方法只能在Python2
中起作用,在Python3
中不再有用了。
class Person(object):
def __init__(self,name,age,height):
self.name = name
self.age = age
self.height = height
def __cmp__(self, other):
if self.age == other.age:
if self.height == self.height:
return 0
else:
return 1 if self.height > other.height else -1
return 1 if self.age > other.age else -1
__eq__(self,other)
:
比较两个对象是否相等,如果相等,那么返回True
,否则返回Flase
class Person(object):
def __init__(self,name,age,height):
self.name = name
self.age = age
self.height = height
def __eq__(self, other):
# self == other
if self.age == other.age:
if self.height == other.height:
return True
else:
return True if self.height == other.height else False
__ne__(self,other)
:
如果两个对象不想等,那么返回True,否则返回Flase
class Person(object):
def __init__(self,name,age,height):
self.name = name
self.age = age
self.height = height
def __ne__(self, other):
# self != other
return False if self.age == other.age and self.height == other.height else True
__lt__(self,other)
:
class Person(object):
def __init__(self,name,age,height):
self.name = name
self.age = age
self.height = height
def __lt__(self, other):
# self < other
if self.age == other.age:
return True if self.height < other.height else False
return self.age < other.age
如果self小于other,那么应该返回True,否则返回False
__gt__(self,other)
:
如果self是大于other,那么应该返回True,否则返回Flase
class Person(object):
def __init__(self,name,age,height):
self.name = name
self.age = age
self.height = height
def __gt__(self, other):
# self > other
if self.age == other.age:
return True if self.height > other.height else False
return self.age > other.age
__ge__(self,other)
:
如果self>=other,那么应该返回True,否则返回Flase
__le__(self,other)
:
如果self<=other,那么应该返回True,否则返回Flase
__ge__
和__le__
注意点:
- 这两个方法在Python2中写不写都无所谓。因为她会分开来判断。比如<=,那么首先会判断是否<,然后在判断是否等于。
- 在Python3中,必须要实现这两个方法中的一个。当然最好两个都实现。
运算符:
一元运算符魔术方法:
__pos__(self)
魔术方法:在对象前面使用+
的时候会调用。__neg__(self)
魔术方法:在对象前面使用-
的时候会调用。__abs__(self)
魔术方法:在给对象执行abs(obj)
的时候会调用。__invert__(self)
魔术方法:在对象前面使用~
的时候会调用。- 如果在这些魔术方法中,所有的更改都是在
self
对象上,那么将会更改这个对象本身。如果是新建一个对象,再更改这个对象的值,那么更改的是这个对象的副本。
class Coornidate(object):
def __init__(self,x,y):
self.x = x
self.y = y
def _pos__(self):
return self
def __neg__(self):
new_coornidate = Coornidate(-self.x,-self.y)
return new_coornidate
def __abs__(self):
new_coornidate = Coornidate(abs(self.x),abs(self.y))
return new_coornidate
def __invert__(self):
new_coornidate = Coornidate(255-self.x,255-self.y)
return new_coornidate
def __str__(self):
return "(%s,%s)" % (self.x,self.y)
c1 = Coornidate(-1,2)
c2 = +c1
c3 = -c1
c4 = abs(c1)
c5 = ~c1
print(c5)
二元运算符魔术方法:
__add__(self,other)
:两个对象相加的时候会调用。__sub__(self,other)
:两个对象相减的时候会调用。__mul__(self,other)
:两个对象相乘的时候会调用。__div__(self,other)
:只有在Python2
中才有用,两个对象相除的时候会调用。__truediv__(self,other)
:两个对象真正相除的时候会调用。如果在Python2
中,必须从Python3
中导入division
这个特性。也就是from __future__ import division
。__mod__(self,other)
:两个对象取模操作的时候会调用。
class Coornidate(object):
def __init__(self,x,y):
self.x = x
self.y = y
def __add__(self, other):
new_coornidate = Coornidate(self.x+other.x,self.y+other.y)
return new_coornidate
def __sub__(self, other):
new_coornidate = Coornidate(self.x-other.x,self.y-other.y)
return new_coornidate
def __mul__(self, other):
new_coornidate = Coornidate(self.x*other.x,self.y*other.y)
return new_coornidate
def __floordiv__(self, other):
new_coornidate = Coornidate(self.x//other.x,self.y//other.y)
return new_coornidate
def __div__(self, other):
new_coornidate = Coornidate(self.x/other.x,self.y/other.y)
return new_coornidate
def __truediv__(self, other):
new_coornidate = Coornidate(self.x/other.x,self.y/other.y)
return new_coornidate
def __mod__(self, other):
new_coornidate = Coornidate(self.x%other.x,self.y%other.y)
return new_coornidate
def __str__(self):
return "(%s,%s)" % (self.x,self.y)
c1 = Coornidate(4,6)
c2 = Coornidate(3,4)
c3 = c1+c2
c4 = c1 - c2
c5 = c1*c2
c6 = c1/c2
c7 = c1%c2
print(c7)
属性访问控制:
__getattr__
魔术方法:
在访问一个对象的某个属性的时候,如果这个属性不存在,那么就会执行这个方法。
class Person(object):
def __init__(self,name):
self.name = name
def __getattr__(self, item):
if item == 'age':
return 18
else:
return None
p1 = Person('zhouxin')
print(p1.name)
print(p1.age)
__setattr__
魔术方法:
给一个对象设置属性的时候,就会执行这个魔术方法。要注意的是,使用self.__dict__[key]=value
的形式,避免使用self.xxx=xxx
产生死循环的递归。
class Person(object):
def __init__(self,name):
self.name = name
self.is_adult = False
def __setattr__(self, key, value):
if key == 'age':
self.__dict__[key] = value
if value >= 18:
self.__dict__['is_adult'] = True
else:
self.__dict__['is_adult'] = False
else:
self.__dict__[key] = value
__getattribute__
魔术方法:
在访问一个对象的属性的时候,都会执行这个魔术方法。要注意的是,使用super(类名,self).__getattribute__(item)
来避免产生死循环的递归。
class Person(object):
def __init__(self,name):
self.name = name
def __getattribute__(self, item):
print(item)
return super(Person, self).__getattribute__(item)
__getattr__
与__getattribute__
区别:
__getattr__
只有属性不存在的时候才会调用。__getattribute__
不管属性存不存在都会调用。
创建属于自己的序列
__len__()
魔术方法:
在使用len(obj)
的时候,会调用这个魔术方法。
__getitem__(self,key)
魔术方法:
使用下标或者切片操作获取值的时候会调用这个魔术方法。
示例:
my_list = ZLList()
temp = my_list[0:2]
__setitem__(self,key)
魔术方法:
使用下标或者切片操作设置值的时候会调用这个魔术方法。
示例:
my_list = ZLList()
my_list[0:2] = ['a','b']
__delitem__(self,key)
魔术方法:
使用del
关键字执行下标或者切片操作删除值的时候会调用这个魔术方法。
示例:
my_list = ZLList()
del my_list[0]
__iter__()
魔术方法:
使用for
循环遍历这个序列的时候会调用这个方法。
示例:
示例:
my_list = ZLList()
for x in my_list:
print(x)
__reversed__
魔术方法:
在使用reversed(obj)
函数的时候,会执行这个魔术方法。
class ZLList(object):
def __init__(self,values=None):
if values is None:
self.values = []
else:
self.values = values
def __iter__(self):
return iter(self.values)
def __len__(self):
return len(self.values)
def __getitem__(self, item):
return self.values[item]
def __setitem__(self, key, value):
self.values[key] = value
def __delitem__(self, key):
del self.values[key]
def __reversed__(self):
return reversed(self.values)
def append(self,value):
self.values.append(value)
def remove(self,value):
return self.values.remove(value)
def head(self):
return self.values[0]
def tail(self):
return self.values[-1]
def take(self,n):
return self.values[:n]
可变容器可以对容器中的元素进行更改,比如删除一个元素,添加一个容器。而不可变容器不能做这些操作。因此如果想定义一个不可变容器,那么不应该实现__setitem__
、__delitem__
方法。
魔术方法(可调用的对象)
__call__
魔术方法:
如果想让一个对象,能够想函数那样被调用,例如:index_view()
,那么应该实现__call__
方法。
class Coornidate(object):
def __init__(self,x,y):
self.x = x
self.y = y
def __call__(self,x,y):
self.x,self.y = x,y
def __str__(self):
return '(%s,%s)' % (self.x,self.y)
c1 = Coornidate(1,2)
print(callable(c1))
c1(2,3)
print(c1)
魔术方法(会话管理)
__enter__
魔术方法:
使用with
语句的时候,会调用这个魔术方法,这个方法的返回值可以作为as xx
的值。
示例:
with open('xxx.txt','r') as fp:
print(fp.read())
__exit__(self,exc_type,exc_val,exc_tb)
魔术方法:
- 执行完这个
with
语句中的代码块或者是这个代码块中的代码发生了异常,就会执行这个方法。可以在这个方法中做一些清理工作。比如关闭文件等。 - 如果在
with
语句中发生了异常,那么exc_type
和exc_val
将会存储这个异常的信息,如果没有任何异常,那么他们的值为None
。 - 如果在
with
语句中发生了异常,那么会执行__exit__
方法,但是如果你不想让这个异常抛出with
代码块,那么你可以返回True
,就不会把异常抛出到外面了。
自定义文件打开器
class FileOpener(object):
def __init__(self,*args,**kwargs):
self.args = args
self.kwargs = kwargs
def __enter__(self):
self.fp = open(*self.args,**self.kwargs)
return self.fp
def __exit__(self, exc_type, exc_val, exc_tb):
self.fp.close()
print(exc_type)
return False
with FileOpener('test.txt','r') as fp:
a = 1
b = 0
# c = a/b
print(fp.read())
对象持久化
有时候一个对象,想要保存在硬盘中。这时候就需要使用到对象持久化的技术了。在Python
中,如果要将一个对象存储到硬盘中,需要使用pickle
模块,其中dump
方法可以将一个对象存到硬盘中,load
方法可以从硬盘中加载一个对象。以下举几个例子来介绍下序列化的大体步骤:
- 写入对象到磁盘中:
import pickle
data = {'foo': [1, 2, 3],
'bar': ('Hello', 'world!'),
'baz': True}
jar = open('data.pkl', 'wb')
pickle.dump(data, jar) # 写入数据到文件中
jar.close()
- 从硬盘中加载对象:
import pickle
pkl_file = open('data.pkl', 'rb') # connect to the pickled data
data = pickle.load(pkl_file) # load it into a variable
print data
pkl_file.close()
Python内置的数据结构是直接可以被序列化的:
字典、元组、列表、集合、字符串、整形、浮点型、布尔类型。
如果自己定义的对象想要能够被序列化,那么必须实现以下两个魔术方法:
__getstate__
:当这个对象被序列化的时候,会调用这个方法,然后将这个方法的返回值存储到硬盘中。这个方法的返回值必须是可序列化的。__setstate__
:当从硬盘中加载一个对象的时候,会调用这个方法,并且将加载到的数据作为参数传递给这个方法。拿到这个数据后,就可以做自己的事情了,比如将之前的数据重新保存到这个对象上。
import pickle
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def __getstate__(self):
return {"name":self.name,'age':self.age}
def __setstate__(self, state):
self.name = state['name']
self.age = state['age']
def __str__(self):
return "<name:%s,age:%d>" % (self.name,self.age)
def dump_obj():
p1 = Person('zhiliao',18)
with open('person.pkl','wb') as fp:
pickle.dump(p1,fp)
def load_obj():
with open('person.pkl','rb') as fp:
p1 = pickle.load(fp)
print(p1)