Wechat search followed the "Water Drop and Silver Bullet" public account to get high-quality technical dry goods in the first place. With 7 years of experience in back-end research and development, he explained the technology clearly in a simple way.
In the previous article Advanced Python-How to use magic methods correctly? In (above) , we mainly introduced the magic methods of construction and initialization, class representation, access control, and their usage scenarios.
In this article, we continue to introduce the remaining magic methods, mainly including: comparison operations, container operations, callable objects, serialization.
Comparison operation
The magic methods of comparison operations mainly include the following:
__cmp__
__eq__
__ne__
__lt__
__gt__
__cmp__
We can tell from the name of this method is the role of magic, when we need to compare two objects, we can define __cmp__
to implement comparison operations.
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
From the example, we can see the specific logic of comparing two objects:
- If the
__cmp__
return integer greater than 0 (typically 1) described self> other - If
__cmp__
returns an integer greater than 0 (typically -1), indicating self <other - If
__cmp__
returns 0 if self == other
Of course, this comparison method has certain limitations. If I have N attributes, when the comparison is greater, we want to use attribute A to compare. When comparing Who hours, we want to compare the properties B, at this time __cmp__
can not be well realized this logic, so it applies only to common comparison logic.
How to implement complex comparison logic?
That's where __eq__
, __ne__
, __lt__
, __gt__
these magic methods, we look at the following example.
# coding: utf8
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):
"""对象 < 判断 根据len(name)"""
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__
__eq__
In the last article we have introduced it with the __hash__
method can determine whether two objects are equal.
But in this case, when determining whether two objects are equal, in fact, we are comparing uid
this property.
__ne__
Similarly, when two objects are not equal it is necessary to determine, calls the __ne__
method, in this case, we are according uid
to the judgment.
__lt__
When determining whether an object is less than another object, it calls __lt__
the method, in this example, we according to name
the comparison of the length to do.
__gt__
Similarly, when determining whether the object is greater than a another object, it calls __gt__
the method, in this case, according we salary
attribute judgment.
In Python3, it
__cmp__
was cancelled because of the functional duplication between it and other magic methods.
Container operations
Next we look at the magic methods of the container class, including:
__setitem__
__getitem__
__delitem__
__len__
__iter__
__contains__
__reversed__
Is it familiar? We have used these methods more or less in development.
Before introducing the magic method of containers, let us first think about what are the container types in Python?
Yes, the common container types in Python are:
- dictionary
- Tuple
- List
- String
These are all container types. Why do you say that?
Because they are all "iterable". Iterable because they all implement the container protocol, which is the magic method we will introduce below.
Let's look at the following example.
# coding: utf8
class MyList(object):
"""自己实现一个list"""
def __init__(self, values=None):
# 初始化自定义list
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):
# 自定义list的元素个数
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):
# 元素是否在自定义list中
return key in self.values
def __reversed__(self):
# 反转
return list(reversed(self.values))
# 初始化自定义list
my_list = MyList([1, 2, 3, 4, 5])
print my_list[0] # __getitem__
my_list[1] = 20 # __setitem__
print 1 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__
In this example, we have implemented a MyList class ourselves. In this class, we define many magic methods of the container class. As a result, our MyList class can operate as common list
as, by way of slicing add, get, delete, iterate the elements.
__setitem__
When we perform my_list[1] = 20
, it will call the __setitem__
method, which is mainly used to add elements to the container.
__getitem__
When we perform my_list[0]
, it will call the __getitem__
method, which is mainly used to read elements from the container.
__delitem__
When we perform del my_list[0]
, it will call the __delitem__
method, which is mainly used to remove elements from the container.
__len__
When we perform len(my_list)
, it will call the __len__
method, which is mainly used for the number of elements in the container to read.
__iter__
We need to focus on this method, why can we implement it [i for i in my_list]
? It's because we defined it __iter__
.
The return value of this method can have two types:
- Return
iter(obj)
: representative usesobj
object iteration protocol generallyobj
is a container object built - Returns
self
: iterative represent logic implemented by the present class, this time to rewritenext
method, iterative implementation of custom logic
In this example, the __iter__
returns self
, so we need to define next
methods to achieve their own iteration of the details.
next
The method uses an index variable used to record the position of the current iteration, every time this method is called, will return an element, when all the elements are iteration is complete, the method returns StopIteration
an exception, then for
stops iteration.
In Python3, the next method is no longer used, instead
__next__
.
__contains__
Can also be seen from the name, this method is executed 1 in my_list
when the trigger used to determine whether an element is present in the container.
__reversed__
This method is executed reversed(my_list)
when the trigger for reversing element container, concrete inverted logic we can also achieve their own.
Callable object
Learn the container class magic method, we then look at the magic method callable object, this magic is only one way: __call__
.
Let's look at the following example.
# coding: utf8
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) # 调用instance() 触发__call__
print c.x, c.y # 100 200
A closer look at this example, we first initialize an Circle
instance c
, then it calls the __init__
method, this is well understood.
However, we for instance c
has made a call c(100, 200)
, note that at this time c
is an instance of an object, when we execute this, in fact it is called __call__
. In this way, we can execute the instance as a method.
If it is not easy to understand, you can read this example several times to understand it.
That is, an example in Python, but also can be invoked by defining __call__
the method, you can pass parameters to implement your own custom logic.
This magic method is usually used in scenarios where a class implements a decorator, metaclass, etc. When you encounter this magic method, you can understand the principle.
Serialization
We know that Python provides a serial number module pickle
. When we use this module to serialize an instance, we can also implement our own logic through magic methods. These magic methods include:
__getstate__
__setstate__
Let's look at the following example.
# coding: utf8
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__
In this example, we first the initial Person
objects, including three attributes: name
, age
, birthday
.
When we call pickle.dumps(person)
, the __getstate__
method will be called, where we ignore the Person
object's age
attributes, then person
when serialization, it will only save the other two properties.
__setstate__
Similarly, when we call pickle.loads(pickled_person)
upon, __setstate__
it will be called to the Senate which is the __getstate__
result returned.
In the __setstate__
method, we have made from the ginseng being serialized dict
, and then from the dict
extracted attribute corresponding, to achieve the effect of anti-sequence.
Other magic methods
Well, the above introduced are the more magic methods we usually encounter.
There are many remaining magic methods, mainly including numerical processing, arithmetic operations, reflection arithmetic operations, incremental assignment, type conversion, reflection, etc. Since we rarely see them in development, we will not introduce them here. Yes, when we encounter it, we can directly consult the document to understand.
to sum up
In this article, we mainly introduced magic methods such as comparison operations, container classes, callable objects, and serialization.
Among them, the magic method of comparison operation can be used to customize the comparison logic of the instance. Container type magic method, can help us to achieve a custom container class, then we can operate list
, dict
as easily to acquire container elements, iterative data and so on. Callable object magic methods, you can call an instance as a method. The magic method of serialization can modify the serialization and deserialization logic of an instance.
Python’s magic methods are just like its name. If used properly, our classes will become easier to use as if they have been added magic. We can use these magic methods to help us achieve some complex functions, such as decorators, metaclasses, and so on.
Wechat search followed the "Water Drop and Silver Bullet" public account to get high-quality technical dry goods in the first place. With 7 years of experience in back-end research and development, he explained the technology clearly in a simple way.