python contains魔法方法_Python技术进阶——魔法方法(二)

在上一篇文章Python技术进阶——魔法方法(一)中,主要介绍了构造与初始化、类的表示、访问控制这几大类魔法方法,同时阐述了各自的使用场景。

本篇文章继续介绍剩下的魔法方法,主要包括:比较操作、容器类操作、可调用对象、Picking序列化。

比较操作

cmp

在比较2个对象时,我们可以定义cmp方法,来达到比较的操作。

class Person(object):

def __init__(self, uid):

self.uid = uid

def __cmp__(self, other):

if self.uid == other.uid:

return 0

if self.uid > other.uid:

return 1

return -1

p1 = Person(1)

p2 = Person(2)

print p1 > p2 # False

print p1 < p2 # True

print p1 == p2 # False

self > other,则返回大于0的整数,一般为1

self < other,返回小于0的整数,一般为-1

self == other,返回0

当然,这种比较有局限性,如果我有N个属性,比较最大时,我想用第一个属性比较,比较最小时,我想用第二个属性比较,此时cmp就不合适了,它只能用于通用的比较逻辑。如何进行不同的比较逻辑,我们可以使用如下方式:

class Person(object):

def __init__(self, uid, name, salary):

self.uid = uid

self.name = name

self.salary = salary

def __eq__(self, other):

"""对象==判断"""

return self.uid == other.uid

def __ne__(self, other):

"""对象!=判断"""

return self.uid != other.uid

def __lt__(self, other):

"""对象

return len(self.name) < len(other.name)

def __gt__(self, other):

"""对象>判断,根据alary"""

return self.salary > other.salary

p1 = Person(1, 'zhangsan', 1000)

p2 = Person(1, 'lisi', 2000)

p3 = Person(1, 'wangwu', 3000)

print p1 == p1 # uid是否相同

print p1 != p2 # uid是否不同

print p2 < p3 # name长度比较

print p3 > p2 # salary大小

eq

在判断两个对象是否相等==时,此方法被调用。同时在上一篇文章中也介绍到,如果需要在set、dict中实现去重,可配合hash方法使用。

ne

在判断两个对象是否不相等!=时,此方法被调用。

lt

在判断一个对象是否小于

gt

在判断一个对象是否大于>另一个对象时,此方法被调用。

在Python3中,cmp被取消了,因为和其他魔法方法有功能上的重复。

容器类操作

首先说明一下Python中内建的容器类型都有哪些?

字典、元组、列表、字符串都是容器类型,之所以是容器类型,是因为它们实现了一些协议。

这就是我们下面要讲到的容器类魔法方法:

class WrapperList(object):

def __init__(self, values=None):

self.values = values or []

def __setitem__(self, key, value):

self.values[key] = value

def __getitem__(self, key):

return self.values[key]

def __delitem__(self, key):

del self.values[key]

def __len__(self):

return len(self.values)

def __iter__(self):

return self

def next(self):

"""如果__iter__返回self,则必须实现此方法"""

if self._index >= len(self.values):

raise StopIteration()

value = self.values[self._index]

self._index += 1

return value

def __contains__(self, key):

return key in self.values

def __reversed__(self):

return list(reversed(self.values))

my_list = WrapperList([1, 2, 3, 4, 5])

print my_list[0] # __getitem__

my_list[1] = 20 # __setitem__

print 1 in my_list # __contains__

print 100 in my_list # __contains__

print len(my_list) # __len__

print [i for i in my_list] # __iter__

del my_list[0] # __del__

reversed_list = reversed(my_list) # __reversed__

print [i for i in reversed_list] # __iter__

setitem

此方法在执行obj[key] = value时触发执行,用于修改容器的某个元素。

getitem

执行obj[key]触发执行,用于获取容器的某个元素。

delitem

执行del obj[key]时触发执行,用于删除容器的某个元素。

len

执行len(obj)时触发执行,用于获取容器内的元素个数。

iter

执行for x in obj时触发执行,用于迭代容器内的元素。

注意,一般此方法会有两种方式返回:

返回iter(obj):代表使用obj对象的迭代协议,一般obj是内置的容器对象

返回self:代表迭代的逻辑由本类来实现,要重写next方法,实现自定义的迭代逻辑

在Python3中,不在使用next方法,而替换成next方法了。

contains

执行x in obj时触发执行,用于判断某个元素是否存在于容器中。

reversed

执行reversed(obj)时触发执行,用于反转容器的元素,具体的反转逻辑可自己实现。

可调用对象

call

我们知道类中的方法是可调用的,其实实例也是可以被调用的,我们只需要实现call:

class Circle(object):

def __init__(self, x, y):

self.x = x

self.y = y

def __call__(self, x, y):

self.x = x

self.y = y

c = Circle(10, 20) # __init__

print c.x, c.y # 10 20

c(100, 200) # 调用实例(),触发__call__

print c.x, c.y # 100 200

首先实例化这个类,触发init,然后通过实例调用触发call ,修改了实例变量。

此方法常见用于用类实现一个装饰器、元类等场景中。

Pickling序列化

在我们使用pickle模块对数据进行序列化和反序列化时,我们可以通过定义相关的魔术方法,自定义序列化和反序列化逻辑:

class Person(object):

def __init__(self, name, age, birthday):

self.name = name

self.age = age

self.birthday = birthday

def __getstate__(self):

"""pick.dumps,忽略了age属性"""

return {

'name': self.name,

'birthday': self.birthday

}

def __setstate__(self, state):

"""pick.loads,忽略了age属性"""

self.name = state['name']

self.birthday = state['birthday']

person = Person('zhangsan', 20, date(2017, 2, 23))

pickled_person = pickle.dumps(person) # __getstate__

p = pickle.loads(pickled_person) # __setstate__

print p.name, p.birthday

print p.age # AttributeError: 'Person' object has no attribute 'age'

getstate

当调用pickle.dumps时,此方法被调用,可以需要被序列化的数据,例如上面这个例子忽略了age属性,那么在序列化后只会对其他两个属性进行保存。

setstate

同样,当调用pickle.loads时,此方法被调用,传入一个参数,此参数就是getstate返回的结果。setstate根据这个参数重新初始化实例属性,已达到反序列化数据的目的。

其他魔法方法

主要的几大类魔法方法就是上述这些,剩下的当然还有很多,只不过我们在开发中很少会用到,这里就不再过多介绍了,需要的时候再查文档即可。剩下的魔法方法主要有这几类,了解一下就好:

数值处理

一元操作符和函数:仅仅有一个操作位的一元操作符和函数

os(self):正号

eg(self):负号

bs(self):实现内置abs()函数的行为

nvert(self) :~符号

算数操作

dd(self, other):加法

ub(self, other):减法

ul(self, other):乘法

loordiv(self, other):地板除法,使用//操作符

iv(self, other):传统除法,使用/操作符

ruediv(self, other):真正除法。注意,只有当from uture import division时才会有效

od(self, other):求模,使用%操作符

ivmod(self, other):实现内建函数divmod()的行为

ow(self, other):乘方,使用**操作符

shift(self, other):左按位位移,使用<

shift(self, other):右按位位移,使用>>操作符

nd(self, other):按位与,使用&操作符

r(self, other):按位或,使用|操作符

or(self, other):按位异或,使用^操作符

反射算术操作

add(self, other):反射加法

sub(self, other):反射减法

mul(self, other):反射乘法

floordiv(self, other):反射地板除,用//操作符

div(self, other):传统除法,用/操作符

turediv(self, other):真实除法,注意,只有当from uture import division时才会有效

mod(self, other):反射求模,用%操作符

divmod(self,other):实现内置函数divmod()的长除行为,当调用divmod(other,self)时被调用

pow(self, other):反射乘方,用**操作符

lshift(self, other):反射的左按位位移,使用<

rshift(self, other):反射的右按位位移,使用>>操作符

and(self, other):反射的按位与,使用&操作符

or(self, other):反射的按位或,使用|操作符

xor(self, other):反射的按位异或,使用^操作符

增量赋值

add(self, other):加法和赋值

sub(self, other):减法和赋值

mul(self, other):乘法和赋值

floordiv(self, other):地板除和赋值,用//=操作符

div(self, other):传统除法和赋值,用/=操作符

turediv(self, other):真实除法和赋值,注意,只有当from uture import division时才会有效

mod(self, other):求模和赋值,用%=操作符

pow(self, other):乘方和赋值,用**=操作符

lshift(self, other):左按位位移和赋值,使用<<=操作符

rshift(self, other):右按位位移和赋值,使用>>=操作符

and(self, other):按位与和赋值,使用&=操作符

or(self, other):按位或和赋值,使用|=操作符

xor(self, other):按位异或和赋值,使用^=操作符

类型转换

nt(self):实现到整型的类型转换

ong(self):长整形

loat(self):浮点型

omplex(self):复数型

ct(self):8进制型

ex(self):16进制型

ndex(self):实现一个当对象被切片到int的类型转换。若自定义了一个数值类型,考虑到它可能被切片,要重载ndex

runc(self):当math.trunc(self)被调用时调用。返回一个整型的截断

oerce(self,other):实现混合模式的算术。如果类型转换不可能则返回None。否则,它应当返回一对相同类型的元祖

反射

nstancecheck(self, instance):检查一个实例是否是你定义类中的一个实例

ubclasscheck(self, subclass):检查一个类是否是你定义类的子类

如果此文章能给您带来小小的工作效率提升,不妨小额赞助我一下,以鼓励我写出更好的文章!

你可能感兴趣的:(python,contains魔法方法)