January 10, 2025

Sorting out Python's magic method system

Python magic methods refer to methods that allow adding "magic" functions to custom classes. In the official Python documentation, the introduction or description of these methods is not only scattered in content, but also relatively loose in organization. This article systematically sorts out the magical methods of Python. For beginners or Python experts, it will be more or less helpful.

Not much to say, go directly to the topic!

Python Magic Guide Directory

Introduction

Build and initialize

Use operators in custom classes

Comparison of magic methods

Magic method number

Describe the custom class

Control property access

Make a custom sequence

reflection

Callable object

Context manager

Build descriptor object

Introduction

What is a magic method? They are oriented to everything in Python, and are some special methods that allow adding "magic" functions to their definitions. They always use double underscores (such as __init__ or __lt__), but their documentation does not show them well. All these magic methods appear in the official Python documentation, but the content is relatively scattered and the organization structure is also loose. You will also find it difficult to find an example (although they are well designed and described in detail in the language reference, they will be accompanied by boring grammatical descriptions, etc.).

In order to make up for these shortcomings in the official Python documentation, the author has compiled this article about magic method, which is intended to be used as a tutorial, review or reference document.

Build and initialize

I believe everyone is familiar with this most basic magic method __init__. It allows you to customize the initialization behavior of an object. When I call x=SomeClass(), __init__ is not the first to be called. In fact, there is a method called __new__. In fact, it creates an instance, and it passes any parameters to the initializer to achieve the purpose of creation. At the end of the object's life cycle, __del__ is called. Let's take a closer look at these 3 magic methods:

__new__(cls,[…)

__New__ is the first method called when an object is instantiated. Pass any other parameters in the class to __init__. __new__ is rarely used, and it does have its purpose, especially when a subclass inherits an immutable type (a tuple or a string).

__init__(self,[…)

Initialization of the class. After the object is created, the python interpreter calls the __init__() method by default. No matter what the main constructor calls, it will be passed. __init__ is almost universally used in Python class definitions.

__del__(self)

If __new__ and __init__ constitute the object's constructor, __del__ is the destructor. When deleting an object, the python interpreter will also call the __del__() method by default. In Python, it is rare for developers to destroy objects directly (if necessary, they should be destroyed using the del keyword). Python's memory management mechanism can do this job well. In other words, whether it is manually called del or automatically recycled by python will trigger the __del__ method to execute.

The following is an example of __init__ and __del__:

fromos.pathimportjoinclassFileObject:'''Packaging of file objects to ensure that files are deleted when they are closed'''def__init__(self,filepath='~',filename='sample.txt'):#Press filepath, open in read-write mode The file named filename self.file=open(join(filepath,filename),'r+')def__del__(self):self.file.close()delself.file

Use operators in custom classes

Comparison of magic methods:

Python has a lot of magic methods, designed to use operators to achieve intuitive comparisons between objects, rather than awkward method calls. They also provide a way to override the default Python behavior for object comparison. The following is a list of these methods and what they do:

__cmp__(self,other)

__cmp__ is the most basic one of the magic methods. In fact, it implements all comparison operator behaviors (other, returns a positive integer. It is usually the best definition, and you don’t need to define them all at once, but when you need to use similar criteria for all comparisons, __cmp__ would be a good way to help you save repetition and improve clarity.

__eq__(self,other)

Defines the equality operator, the behavior of ==.

__ne__(self,other)

Defines the inequality operator, the behavior of !=.

__lt__(self,other)

Defines the less than operator,

__gt__(self,other)

Defines the greater than operator, the behavior of >.

__le__(self,other)

Defines the less than or equal operator,

__ge__(self,other)

Defines the greater than or equal to operator, the behavior of >=.

As an example, imagine class definitions for words. We may want to compare words according to the internal default comparison behavior for strings, which is lexicographical order (by letters), and also hope to be able to base them on some other criteria, such as length or number of syllables. In this example, we sort by word length, and the implementation is given below:

classWord(str):'''Word class, the comparison definition is based on the word length'''def__new__(cls,word):#Note, we used __new__, this is because str is an immutable type, #So we It must be initialized earlier (at the time of creation) if "inword:print" contains spaces in the word, truncated to the first part "word=word[:word.index('')]#All before the first space It's a character now returnstr.__new__(cls,word)def__gt__(self,other):returnlen(self)>len(other)def__lt__(self,other):returnlen(self)=len(other)def__le__(self,other) :returnlen(self)

Magic method number:

Just as you can create your own class instance by overloading comparison operators, you can also overload numeric operators.

Unary operator:

Unary operations and functions have only one operand, such as negative numbers, absolute values, etc.

__pos__(self)

Realize the behavior of unary positive numbers (eg: +some_object)

__neg__(self)

Realize the behavior of negative numbers (e.g. -some_object)

__abs__(self)

Implement the behavior of the built-in abs() function

__invert__(self)

Realize the negation behavior with the ~ operator.

Regular arithmetic operators:

Now we cover the basic binary operators: +, -, * and so on. Most of them are self-explanatory.

__add__(self,other)

Implement addition

__sub__(self,other)

Implement subtraction

__mul__(self,other)

Implement multiplication

__floordiv__(self,other)

To achieve floor division, use the // operator

__div__(self,other)

Implement traditional division, use the / operator

__truediv__(self,other)

Realize true division. Note that it will only work when you import division from __future__

__mod__(self,other)

To achieve modulo, use the% operator

__divmod__(self,other)

Implement the behavior of the built-in function divmod()

__pow__(self,other)

To achieve the power, use the ** operator

__lshift__(self,other)

To achieve the left bit shift, use

__rshift__(self,other)

To achieve right bitwise displacement, use the >> operator

__and__(self,other)

To achieve bitwise AND, use the & operator

__or__(self,other)

To achieve bitwise OR, use the | operator

__xor__(self,other)

To achieve bitwise XOR, use the ^ operator

Reflection arithmetic operators:

First give an example: some_object + other. This is a "regular" addition. The reflection is actually the same thing, except that the operand changes and changes the position: other + some_object. In most cases, the results of reflection arithmetic operations are equivalent to regular arithmetic operations, so you can call __add__ as soon as __radd__ is overloaded. Simply happy:

__radd__(self,other)

Realize reflection addition

__rsub__(self,other)

Implement reflection subtraction

__rmul__(self,other)

Implement reflection multiplication

__rfloordiv__(self,other)

To achieve the reflective floor division, use the // operator

__rdiv__(self,other)

To achieve traditional division, use the / operator

__rturediv__(self,other)

Realize real division, note that it will only work when you import division from __future__

__rmod__(self,other)

Realize reflection modulus, use% operator

__rdivmod__(self,other)

Realize the long division behavior of the built-in function divmod(), which is called when divmod(other,self) is called

__rpow__(self,other)

Realize reflection power, use ** operator

__rlshift__(self,other)

To achieve the left bit shift of reflection, use

__rrshift__(self,other)

To achieve the right bitwise displacement of reflection, use the >> operator

__rand__(self,other)

To realize the bitwise AND of reflection, use the & operator

__ror__(self,other)

To realize the bitwise OR of reflection, use the | operator

__rxor__(self,other)

To realize the bitwise XOR of reflection, use the ^ operator

Incremental assignment:

Python also has a variety of magic methods that allow users to customize incremental assignment behavior.

None of these methods will return a value, because assignment does not have any return value in Python. Instead, they just change the state of the class. The list is as follows:

__rxor__(self,other)

Implement addition and assignment

__isub__(self,other)

Implement subtraction and assignment

__imul__(self,other)

Implement multiplication and assignment

__ifloordiv__(self,other)

To achieve the floor division and assignment, use the //= operator

__idiv__(self,other)

To achieve traditional division and assignment, use the /= operator

__iturediv__(self,other)

Realize real division and assignment. Note that it will only work when you import division from __future__

__imod__(self,other)

Realize modulus and assignment, use %= operator

__ipow__(self,other)

To achieve power and assignment, use the **= operator

__ilshift__(self,other)

To realize the left bitwise displacement and assignment, use

__irshift__(self,other)

Realize right bitwise displacement and assignment, use >>= operator

__iand__(self,other)

Realize bitwise AND and assignment, use &= operator

__ior__(self,other)

To achieve bitwise OR and assignment, use the |= operator

__ixor__(self,other)

To achieve bitwise XOR and assignment, use the ^= operator

The magic method of type conversion:

Python also has a set of magic methods designed to implement the behavior of built-in type conversion functions, such as float().

__int__(self)

Type conversion to int

__long__(self)

Realize type conversion to long

__float__(self)

Realize type conversion to float

__complex__(self)

Realize type conversion to plural

__oct__(self)

Realize type conversion to octal

__hex__(self)

Realize type conversion to hexadecimal

__index__(self)

Implement a type conversion when the object is sliced ​​to int. If you customize a numeric type, considering that it may be sliced, you should overload __index__.

__trunc__(self)

Called when math.trunc(self) is called. __trunc__ should return an integer truncation, (usually long).

__coerce__(self,other)

This method is used to implement mixed mode arithmetic. If type conversion is not possible, __coerce__ should return None. Otherwise, it should return a pair containing self and other (2-tuple), adjusted to have the same type.

Describe the custom class

It is usually useful to use a string to describe a class. Python provides some methods that allow you to customize built-in functions in your own class to return a description of your class behavior.

__str__(self)

When an instance of the class you define calls str(), it is used to define behavior

__repr__(self)

When an instance of the class you define calls repr(), it is used to define behavior for it. The main difference between str() and repr() is its reading object. The output produced by repr() is mainly computer-readable (in many cases, this may even be some valid Python code), while str() is meant to be human-readable.

__unicode__(self)

When an instance of the class you define calls unicode(), it is used to define its behavior. unicode() is like str(), except that it returns a unicode string. alert! If the user calls str() with an instance of your class, and you only define __unicode__(), it will not work. Just in case, you should always define __str__(), even if the user does not use unicode.

__hash__(self)

When an instance of the class you define calls hash(), it is used to define behavior for it. It must return an integer, and its result is used as a shortcut key comparison in the dictionary.

__nonzero__(self)

When an instance of the class you define calls bool(), it is used to define behavior. Return True or False, depending on whether you consider an instance to be True or False.

We have done the boring part of the magic method quite beautifully (no examples), so far we have discussed some basic magic methods, it is time for us to move to advanced topics.

Control property access

Python achieves a lot of encapsulation through magic methods, not through explicit methods or field modifiers. E.g:

__getattr__(self,name)

You can define the behavior of the user when trying to access a class attribute that does not exist (whether it exists or has not been established). This is useful for catching and redirecting common spelling mistakes, giving warnings about the use of attributes (you can still calculate and return that attribute as long as you want), or throwing an AttributeError exception. This method is only suitable for accessing a non-existent property, so this is not a true encapsulation solution.

__setattr__(self,name,value)

Unlike __getattr__, __setattr__ is an encapsulated solution. It allows you to behave when assigning a value to an attribute, regardless of whether the attribute exists or not. This means that you can customize rules for any change in attribute values. However, what you need to care about is that you have to use __setattr__ carefully, which will be given as an example in a later list.

__delattr__

This is equivalent to __setattr__, but as deleting class attributes instead of setting them. It requires the same precautions, like __setattr__, to prevent infinite recursion (when calling del self.name in __delattr__ will cause infinite recursion).

__getattribute__(self,name)

__getattribute__ is a good fit for its companions __setattr__ and __delattr__. But I do not recommend you to use it.

__getattribute__ can only be used in new-style classes (in the latest version of Python, all classes are new-style classes. In older versions, you can create a new-style class by inheriting the object class. It allows you to set rules. It does not matter whether the value of a class attribute is accessible at that time.) It will suffer from some infinite recursion problems because of errors in its companions (at this time, you can prevent it by calling the __getattribute__ method of the base class occur). When __getattribute__ is implemented and only this method is called, if __getattribute__ is explicitly called or an AttributeError exception is thrown, it also mainly avoids dependence on __getattr__. This method can be used, but I don't recommend it because it has a small use case (although it is relatively rare, but we need special behavior to get a value instead of assigning it) and it is really difficult to achieve zero bugs.

You can easily cause a problem when you customize any class attribute access method. Refer to this example:

def__setattr__(self,name,value):self.name=value#When assigning a value to a class attribute every time, __setattr__() is called, which forms recursion#because its real meaning is self.__setattr__('name ',value)#So this method keeps calling itself, it becomes a recursion that cannot be exited and finally causes crashdef__setattr__(self,name,value):self.__dict__[name]=value#to name assignment in the dictionary# Customize behavior here

The following is a practical example of special attribute access methods (note that we use super because not all classes have __dict__ class attributes):

classAccessCounter:'''A class contains a value and implements an access counter. When the value changes every time, the counter+1'''def__init__(self,val):super(AccessCounter,self).__setattr__('counter',0)super(AccessCounter,self).__setattr__('value',val) )def__setattr__(self,name,value):ifname=='value':super(AccessCounter,self).__setattr__('counter',self.counter+1)#Makethisunconditional.#If you want to prevent other attributes from being created, throw AttributeError(name) exception super(AccessCounter,self).__setattr__(name,value)def__delattr__(self,name)ifname=='value':super(AccessCounter,self).__setattr__('counter',self.counter+1) )super(AccessCounter,self).__delattr__(name)

Make a custom sequence

There are many ways to make your classes behave like built-in sequences (dictionaries, tuples, lists, strings, etc.). These are my favorite magic methods so far, because unreasonable control of them gives you a magical way to make your class instance and the entire global function array work beautifully.

__len__(self)

Returns the length of the container. Some protocols support both mutable and immutable containers

__getitem__(self,key)

To define the behavior when an item is accessed, use self[key] notation. This is also part of the mutable and immutable container protocol. This can also throw an appropriate exception: TypeError when the key is of the wrong type, or there is no value corresponding to the key.

__setitem__(self,key,value)

To define the behavior when an item is assigned, use self[key]=value notation. This is also part of the mutable and immutable container protocol. Once again, you should throw KeyError and TypeError exceptions where appropriate.

__delitem__(self,key)

Define the behavior when an item is deleted (for example, del self[key]). This is only part of the variable container protocol. After an invalid key is used, you must throw an appropriate exception.

__iter__(self)

Should return an iterator to the container. The iterator will return a number of contents, most of which are represented by the built-in function iter(). When a container uses a loop of the form for x in container:. The iterator itself is its object, and a __iter__ method must be defined to return itself.

__reversed__(self)

Define the behavior when the built-in function reversed() is called. Should return a list of reverse versions.

__contains__(self,item)

__contains__ is the membership, which defines the behavior when testing with in and not in. Then you may ask why this is not a part of the protocol of a sequence? This is because when __contains__ is not defined, Python will traverse the sequence and return True if it encounters the item it is looking for.

__concat__(self,other)

Finally, you can define the connection between your sequence and another sequence through __concat__. A newly constructed sequence should be returned from self and other. When calling 2 sequences __concat__ involves the operator +

In our example, let's take a look at the construction of some basic functionalities implemented by a list. May remind you of other languages ​​you use (such as Haskell).

classFunctionalList:'''The class covers some additional functional magic of a list, like head, tail, init, last, drop, andtake'''def__init__(self,values=None):ifvaluesisNone:self.values=[ ]else:self.values=valuesdef__len__(self):returnlen(self.values)def__getitem__(self,key):#If key is an illegal type and value, then listvaluse will throw an exception returnself.values[key]def__setitem__(self ,key,value):self.values[key]=valuedef__delitem__(self,key):delself.values[key]def__iter__(self):returniter(self.values)def__reversed__(self):returnreversed(self.values)defappend( self,value):self.values.append(value)defhead(self):#Get the first element returnself.values[0]deftail(self):#Get all other elements after the first element return.values [1:]definit(self):#Get the sequence except the last element return.values[:-1]deflast(last):#Get the last element return.values[-1]defdrop(self,n):# Get the sequence except the first n elements returnself.values[n:]deftake(self,n):#Get the first n elements return.values[:n]

reflection

You can also define magic methods to control how to reflect the behavior of the built-in functions isinstance() and issubclass(). These magic methods are:

__instancecheck__(self,instance)

Check whether an instance is an instance of the class you define (for example, isinstance(instance, class))

__subclasscheck__(self,subclass)

Check whether a class is a subclass of the class you define (for example, issubclass(subclass, class))

Callable object

This is a special magic method in Python that allows your class instances to behave like functions. So you can "call" them, pass them as parameters to functions, etc. This is another powerful and convenient feature that makes Python programming more lovely.

__call__(self,[args…])

Allow class instances to be called like functions. Essentially, this means that x() is equivalent to x.__call__(). Note that the number of parameters required by __call__ is variable, which means that you can define __call__ for any function as many as you like.

__call__ may be extremely useful for instances that frequently change state. "Calling" an instance is an intuitive and elegant way to change the state of an object. The following example is a class that represents the position of an entity on a plane:

classEntity:'''Describe the class of the entity, update the position of the entity when it is called'''def__init__(self,size,x,y):self.x,self.y=x,yself.size=sizedef__call__(self, x,y):'''Change the position of the entity'''self.x,self.y=x,y#omit...

Context manager

Context management allows you to set and clean up objects, and use the with statement to perform encapsulated operations. The behavior of the context operation depends on 2 magic methods:

__enter__(self)

Define what the context management should do at the beginning of the block when the block is created with with statement.

__exit__(self,exception_type,exception_value,traceback)

Define what the context management should do after the block is executed (or terminated).

You can also use these methods to create context management that encapsulates other objects. Look at the following example:

classCloser: ``'Use with to declare a context management and use a close method to automatically close an object''' def__init__(self,obj):self.obj=objdef__enter__(self):returnself.obj#Binding target def__exit__(self,exception_type ,exception_val,trace):try:self.obj.close()exceptAttributeError:#obj does not have closeprint'Notclosable.'returnTrue#Successfully handle the exception

The following is an example of the practical application of Closer, a demonstration using an FTP connection (a closeable socket):

>>>frommagicmethodsimportCloser>>>fromftplibimport:;;>>>withCloser(FTP('ftp.somsite.com'))asconn:...conn.dir()...#Omitted output >>>conn.dir ()#A very long AttributeError message, a connection used cannot be closed>>>withCloser(int(5))asi:...i+=1...Notcloseable.>>>i6

Build descriptor object

Descriptors can change other objects, and can also be access to any of the getting, setting, or deleting of the class.

As a descriptor, a class must implement at least one of __get__, __set__, and __delete__. Let's quickly take a look at these magic methods:

__get__(self,instance,owner)

Define the behavior when the value of the descriptor is retrieved. Instance is an instance of the owner object, and owner is all classes.

__set__(self,instance,value)

Define the behavior when the value of the descriptor is changed. instance is an instance of the owner object, value is the value of the set descriptor

__delete__(self,instance)

Define the behavior when the value of the descriptor is deleted. instance is an instance of the owner object.

Now, there is an example of a useful descriptor application: unit conversion strategy

classMeter(object):'''M Descriptor''' def__init__(self,value=0.0):self.value=float(value)def__get__(self,instance,owner):returnself.valuedef__set__(self,instance,value) :self.value=float(value)classFoot(object):``'Foot descriptor'''def__get__(self,instance,owner):returninstance.meter*3.2808def__set__(self,instance,value):instance.meter= float(value)/3.2808classDistance(object):''' represents the class of distance, which controls two descriptors: feet and meters'''meter=Meter()foot=Foot()

to sum up

The goal of this guide is for anyone to understand it, regardless of whether the reader has Python or object-oriented programming experience. If you are about to learn Python, then you have gained valuable knowledge of writing feature-rich, elegant, and easy-to-use classes. If you are an intermediate Python programmer, you may have picked up some concepts, strategies, and some good methods to reduce the amount of code you write. If you are a Python expert, you may have reviewed some knowledge points that you may have forgotten, or you have some new discoveries. Regardless of your experience level, I hope you will gain something in this journey of Python magic methods!

Tablet PC Pad


A tablet computer is an electronic device that integrates mobile commerce, mobile communication and mobile entertainment, with a touch recognition LCD screen, handwriting recognition and wireless network communication functions. At present, the tablet computer has become the most popular electronic product.

1.In appearance, the tablet computer looks like a large-screen mobile phone, or more like a separate LCD screen.

2.In terms of hardware configuration, a tablet computer has all the hardware devices of a traditional computer, and has its own unique operating system, compatible with a variety of applications, and has a complete set of computer functions.

3.Tablet PC is a kind of miniaturized computer. Compared with traditional desktop computers, tablet computers are mobile and flexible. Compared with notebook computers, tablet computers are more compact and more portable.

4.Tablet PC is a digital notebook with digital ink function. In daily use, you can use the tablet computer like an ordinary notebook, take notes anytime and anywhere, and leave your own notes in electronic texts and documents.


Tablet Pc Pad,Mobile Tablet,Scratch Pad Tablet Pc,Tablet Pc,Tablets & Presentation Equipment,Educational Tablet

Jingjiang Gisen Technology Co.,Ltd , https://www.jsgisengroup.com