SoFunction
Updated on 2024-10-29

Explaining Python's common magic methods in detail

I. python magic methods

Python's magic methods are called automatically under certain circumstances, and their method names are usually wrapped in double underscores; the constructor and destructor functions we learned about earlier are magic methods

II. Operator Overloading

Python also has operator overloading, in fact, all the operators are used in the corresponding magic method to deal with the object, the magic method corresponding to the operator is as follows

在这里插入图片描述

Let's take a simple example

class A:
    def __init__(self,x):
         = x
    def __add__(self,other):
        return int()+int()
a = A(3.3)
b = A(5.2)
print(a+b)

Similarly, inverse overloading and incremental copying are less useful and will not be explained again.

在这里插入图片描述
在这里插入图片描述

III. Magic Methods of Printing Operations

__str__(self): The return value is of type str, which is automatically called when we need to output an object as a string (when calling print), for example

class A:
    def __str__(self):
        return 'I'm so handsome'

a = A()
print(a)# I'm so handsome.

__repr__(self): The return value is of type str, which is automatically called when we type the name of the object directly in the shell and press enter, and he also has the same function as the__str__same functionality, but if both you rewrite, when using print, the__str__of high priority.__repr__It's for the machine.__str__It's for people. Give me an example.

>>> class A:
    def __str__(self):
        return 'I'm so handsome'
    def __repr__(self):
        return 'I'm the world's most handsome'

>>> a = A()
>>> a
I'm the most handsome man in the world.
>>> print(a)
I'm so handsome.

IV. Magic Methods of Attribute Manipulation

  • __getattr__(self, name): defines the behavior when the user tries to get a non-existing attribute, where name is the name of the attribute, which is a string, as follows
  • __getattribute__(self, name): Defines the behavior when an attribute of this class is accessed, the method returns the value of the attribute by default
  • __setattr__(self, name, value): defines the behavior when an attribute is set, value is the value given to the attribute
  • __delattr__(self, name): define the behavior when an attribute is deleted

Example:

class A:
    def __init__(self):
         = "Pyhon"
    def __getattr__(self,name):
        print(name+"This property does not exist.")
    def __getattribute__(self,name):
        print("I visited."+name+"This property.")
        return super().__getattribute__(name)
    def __setattr__(self,name,value):
        print("will attribute"+name+"Set to"+value)
        super().__setattr__(name,value)
    def __delattr__(self,name):
        print("will attribute"+name+"Deleted.");
        super().__delattr__(name)
    def fun(self):
        pass
a = A()

 = "Teacher."
del 
()
# output:
# Set the attribute id to Pyhon
# I accessed the name attribute
# The name attribute doesn't exist
# Set the attribute name to teacher
# Removed the attribute name
# I accessed the property fun

The result shows that when we access a property, we first call the__getattribute__, if the property does not exist, then call the__getattr__

When using these methods, it is important to note thatDon't fall into infinite recursionIt is also easy to make this mistake with operator overloading, as in the following example

class A:
    def __init__(self):
         = "Pyhon"
    def __setattr__(self,name,value):
        print("will attribute"+name+"Set to"+value)
        if(name == "id"):
             = value

a = A()

Execution of this program will fall into infinite recursion, due to the fact that the__setattr__directly to the self object's attributes, which in turn calls the__setattr__Methods.

thus in__setattr__We usually use the parent class's__setattr__method to assign a value to the property of the self object, which does not fall into infinite recursion, and the same is true for several other methods and operator overloads, the above program is revised as follows

class A:
    def __init__(self):
         = "Pyhon"
    def __setattr__(self,name,value):
        print("will attribute"+name+"Set to"+value)
        if(name == "id"):
            super().__setattr__(name,value)

a = A()
# output
# Set the attribute id to Pyhon

V. Descriptors

  • __get__(self, instance, owner): This method is called when accessing an instance of the class through another instance object, and returns a reference to the instance object. Where instance is access to the object of the instance object reference, the same below, owner is access to the object of the class object
  • __set__(self, instance, value): This method is called when assigning a value to an instance object of this class through another instance object. Where value is the value assigned to the object.
  • __delete__(self, instance): This method is called when deleting an instance object of the class through another instance object.
class Fit:
    def __init__(self):
         = 180
         = 80
    def __get__(self,instance,owner):
        print("get:",instance,owner)
        return [,]
    def __set__(self,instance,value):
        print("set:",instance,value)
         = value
         = value/2
    def __delete__(self,instance):
        del 
        del 
        print("delete:",instance)

class Test:
    fit = Fit()
        
t = Test()
print ()
 = 190
del 
# output:
# get: <__main__.Test object at 0x0000023EFFA738C8> <class '__main__.Test'>
# [180, 80]
# set: <__main__.Test object at 0x0000023EFFA738C8> 190
# delete: <__main__.Test object at 0x0000023EFFA738C8>

Usually, the above several magic methods, when we need to define a property, and want to be able to directly on the property to carry out the corresponding operation, rather than through the way to call the method to operate, we can define a property of the class, the implementation of the above several magic methods, the need to use the property as its instance object, so that it is completed, for example, the above Fit, in fact, is the body type class, and the Test has a body type property called fit. And Test has a body property called fit, we define in Fit some operations to be performed when operating on the instance object of Fit.

VI. Customized sequences

  • __len__(self): Define the behavior of an instance object of this class when it is called by len()
  • __getitem__(self, key): Defines the behavior of getting the specified element of an instance object of this class, i.e., the behavior when self[key] is executed
  • __setitem__(self, key, value): Defines the behavior of setting the specified element in an instance object of this class, equivalent to self[key] = value
  • __delitem__(self, key): defines the news that deletes the specified element of an instance object of the class, which is equivalent to del self[key].
class CountList:
    def __init__(self,*args):
         = [x for x in args]# This is a list derivation, using the elements in args as elements of values
         = {}.fromkeys(range(len()),0)

    def __len__(self):
        return len()

    def __getitem__(self,key):
        [key] += 1;
        return [key]

c = CountList(1,3,5,7,9,11)
print(c[1])
print(c[1]+c[2])
print()
# output:
# 3
# 8
# {0: 0, 1: 2, 2: 1, 3: 0, 4: 0, 5: 0}

The count in this class is the number of times the corresponding element has been accessed, and the other two are similar, so I won't give any more examples.

VII. Iterators

Iterators, that is, containers that provide iteration methods, and the so-called iteration methods are the following two__iter__cap (a poem)__next__
Iterable, that is, providing the__iter__method containers, the strings, lists, tuples, dictionaries, and collections we talked about earlier are all iterable, but they are not iterators and can be used with Python's built-in functioniter(iterable)to get their corresponding iterator, which uses thenext(iterator)can get the next element, and these two methods actually call the iterator's__iter__cap (a poem)__next__

  • __iter__(self): Define the behavior when acquiring iterators
  • __next__(self): Define the behavior when getting the next element corresponding to an iterator
class Fb:
    def __init__(self,n = 20):
         = 0
         = 1
         = n
    def __iter__(self):
        return self
    def __next__(self):
        t = 
         = 
         = t + 
        if( <= ):
            return 
        else:
            raise StopIteration

f = Fb()
for i in f:
    print(i,end=' ')
# output:1 1 2 3 5 8 13 

where raise returns an exception, the program above is equivalent to the following

class Fb:
    def __init__(self,n = 20):
         = 0
         = 1
         = n
    def __iter__(self):
        return self
    def __next__(self):
        t = 
         = 
         = t + 
        if( <= ):
            return 
        else:
            raise StopIteration

f = Fb()
it = iter(f)
while True:
    try:
        i = next(it)
        print(i, end=' ')
    except StopIteration:
        break;

In this way, we are very clear about the principle of Python's for loop, the first iter to get the iterator object, and then keep calling next to get the next element to assign to the value of i, until it encounters the StopIteration exception

to this article on the details of Python commonly used magic method of the article is introduced to this, more related python magic method content please search for my previous articles or continue to browse the following related articles I hope you will support me in the future more!