Python advanced-how to use magic methods correctly? (under)

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 uidthis property.

__ne__

Similarly, when two objects are not equal it is necessary to determine, calls the __ne__method, in this case, we are according uidto the judgment.

__lt__

When determining whether an object is less than another object, it calls __lt__the method, in this example, we according to namethe 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 salaryattribute 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 listas, 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 uses objobject iteration protocol generally objis a container object built
  • Returns self: iterative represent logic implemented by the present class, this time to rewrite nextmethod, iterative implementation of custom logic

In this example, the __iter__returns self, so we need to define nextmethods to achieve their own iteration of the details.

nextThe 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 StopIterationan exception, then forstops 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_listwhen 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 Circleinstance c, then it calls the __init__method, this is well understood.

However, we for instance chas made a call c(100, 200), note that at this time cis 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 Personobjects, including three attributes: name, age, birthday.

When we call pickle.dumps(person), the __getstate__method will be called, where we ignore the Personobject's ageattributes, then personwhen 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 dictextracted 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, dictas 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.

Guess you like

Origin blog.csdn.net/ynxts/article/details/112342840
Recommended