Summary of special methods for implementing custom classes in python

Source: Internet
Author: User
This article mainly introduces the summary of special methods for implementing custom classes in python, this article describes special methods such as _ str _, _ iter _, _ getitem _, _ getattr _, and _ call, for more information, see variables or function names like _ slots _ xxx _. These variables are useful in Python.

_ Slots _ we already know how to use the _ len _ () method. We also know that we want to allow the class to act on the len () function.

In addition, there are many such special functions in the Python class that can help us customize the class.

_ Str __

First, we define a Student class and print an instance:

The Code is as follows:


>>> Class Student (object ):
... Def _ init _ (self, name ):
... Self. name = name
...
>>> Print Student ('Michael ')
<__Main _. Student object at 0x0000afb190>


Print out a bunch of <__main _. Student object at 0x20.afb190>.

How can I print well? You only need to define the _ str _ () method and return a nice string:

The Code is as follows:


>>> Class Student (object ):
... Def _ init _ (self, name ):
... Self. name = name
... Def _ str _ (self ):
... Return 'student object (name: % s) '% self. name
...
>>> Print Student ('Michael ')
Student object (name: Michael)


The printed instances are not only nice-looking, but also easy to see the important data in the instance.

However, careful friends will find that directly typing variables does not require print, and the printed instances are still hard to understand:

The Code is as follows:


>>> S = Student ('Michael ')
>>> S
<__Main _. Student object at 0x0000afb310>


This is because the direct display of variables calls not _ str _ (), but _ repr _ (). The difference between the two is _ str __() returns the string that the user sees, and _ repr _ () returns the string that the developer sees, that is, __repr _ () is used for debugging.

The solution is to define another _ repr __(). But the _ str _ () and _ repr _ () code are usually the same, so there is a lazy way to write:

The Code is as follows:


Class Student (object ):
Def _ init _ (self, name ):
Self. name = name
Def _ str _ (self ):
Return 'student object (name = % s) '% self. name
_ Repr _ = _ str __

_ Iter __

If a class is used... in loop. Like list or tuple, A _ iter _ () method must be implemented. This method returns an iteration object. Then, the for loop of Python constantly calls the next () method of the iteration object to get the next value of the loop until the loop is exited when the StopIteration error occurs.

Let's take the Fibonacci series as an example. Writing a Fib class can act on the for Loop:

The Code is as follows:


Class Fib (object ):
Def _ init _ (self ):
Self. a, self. B = 0, 1 # initialize two counters a and B

Def _ iter _ (self ):
Return self # The instance itself is an iteration object, so it returns itself

Def next (self ):
Self. a, self. B = self. B, self. a + self. B # Calculate the next value
If self. a> 100000: # condition for exiting the loop
Raise StopIteration ();
Return self. a # return the next value

Now, try to apply the Fib instance to the for Loop:

The Code is as follows:


>>> For n in Fib ():
... Print n
...
1
1
2
3
5
...
46368
75025

_ Getitem __

Although the Fib instance can act on a for loop, it looks a little like a list, but it still cannot be used as a list, for example, taking 5th elements:

The Code is as follows:


>>> Fib () [5]
Traceback (most recent call last ):
File" ", Line 1, in
TypeError: 'fib 'object does not support indexing


To retrieve elements by subscript like list, the _ getitem _ () method must be implemented:

The Code is as follows:


Class Fib (object ):
Def _ getitem _ (self, n ):
A, B = 1, 1
For x in range (n ):
A, B = B, a + B
Return


Now, you can access any of the series by Subscript:

The Code is as follows:


>>> F = Fib ()
>>> F [0]
1
>>> F [1]
1
>>> F [2]
2
>>> F [3]
3
>>> F [10]
89
>>> F [1, 100]
573147844013817084101


However, list has a magic slicing method:

The Code is as follows:


>>> Range (100) []
[5, 6, 7, 8, 9]


An error is reported for Fib. The reason is that the input parameter _ getitem _ () may be an int or slice object. Therefore, we need to make a judgment:

The Code is as follows:


Class Fib (object ):
Def _ getitem _ (self, n ):
If isinstance (n, int ):
A, B = 1, 1
For x in range (n ):
A, B = B, a + B
Return
If isinstance (n, slice ):
Start = n. start
Stop = n. stop
A, B = 1, 1
L = []
For x in range (stop ):
If x> = start:
L. append ()
A, B = B, a + B
Return L


Now try the Fib slice:

The Code is as follows:


>>> F = Fib ()
>>> F [0: 5]
[1, 1, 2, 3, 5]
>>> F [: 10]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]


However, the step parameter is not processed:

The Code is as follows:


>>> F [: 10: 2]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]


The negative number is not processed. Therefore, there is still much work to do to implement a correct _ getitem.

In addition, if the object is treated as a dict, __getitem _ () parameter, it may also be an object that can be used as a key, such as str.

Corresponding to the _ setitem _ () method, the object is treated as list or dict to assign values to the set. Finally, there is a _ delitem _ () method to delete an element.

In short, through the above method, the class we define is similar to the list, tuple, and dict that comes with Python. This is entirely due to the "duck type" of the Dynamic Language ", you do not need to forcibly inherit an interface.

_ Getattr __

Under normal circumstances, if the method or attribute of the class does not exist, an error is returned. For example, define the Student class:

The Code is as follows:


Class Student (object ):

Def _ init _ (self ):
Self. name = 'Michael'


You can call the name attribute. However, if you call a score attribute that does not exist, the following error occurs:

The Code is as follows:


>>> S = Student ()
>>> Print s. name
Michael
>>> Print s. score
Traceback (most recent call last ):
...
AttributeError: 'student 'object has no attribute 'score'


The error message clearly tells us that the score attribute is not found.

To avoid this error, in addition to adding a score attribute, Python also has another mechanism, that is, to write a _ getattr _ () method and return a dynamic attribute. Modify as follows:

The Code is as follows:


Class Student (object ):

Def _ init _ (self ):
Self. name = 'Michael'

Def _ getattr _ (self, attr ):
If attr = 'score ':
Return 99


When a nonexistent attribute is called, for example, score, the Python interpreter tries to call _ getattr _ (self, 'score ') to obtain the attribute. In this way, we have the opportunity to return the score value:

The Code is as follows:


>>> S = Student ()
>>> S. name
'Michael'
>>> S. score
99


The return function is also completely possible:

The Code is as follows:


Class Student (object ):

Def _ getattr _ (self, attr ):
If attr = 'age ':
Return lambda: 25


The call method must be changed:

The Code is as follows:


>>> S. age ()
25


Note: Only when the attribute is not found can _ getattr __be called. Existing attributes, such as name, will not be searched in _ getattr.

In addition, it is noted that any call such as s. abc will return None, because the default return value of _ getattr _ is None. To make the class only respond to specific attributes, we need to throw the AttributeError error as agreed:

The Code is as follows:


Class Student (object ):

Def _ getattr _ (self, attr ):
If attr = 'age ':
Return lambda: 25
Raise AttributeError ('\' Student \ 'object has no attribute \ '% s \ ''% attr)


In fact, all attributes and method calls of a class can be dynamically processed without any special means.

What is the actual function of this completely dynamic call feature? The function is to call the service in a completely dynamic situation.

For example:

At present, many websites are engaged in restful APIs, such as Sina Weibo and Douban. The URLs used to call APIs are similar:

Http://api.server/user/friends
Http://api.server/user/timeline/list

If you want to write an SDK and write a method to the API corresponding to each URL, you will be exhausted. In addition, once the API is changed, the SDK should also be changed.

Using fully dynamic _ getattr __, we can write a chain call:

The Code is as follows:


Class Chain (object ):

Def _ init _ (self, path = ''):
Self. _ path = path

Def _ getattr _ (self, path ):
Return Chain ('% s/% s' % (self. _ path, path ))

Def _ str _ (self ):
Return self. _ path


Try:

The Code is as follows:


>>> Chain (). status. user. timeline. list
'/Status/user/timeline/list'


In this way, no matter how the API changes, the SDK can implement completely dynamic calling Based on the URL, and it does not change with the increase of the API!

Some REST APIs put parameters in URLs, such as the GitHub API:

The Code is as follows:


GET/users/: user/repos


During the call, replace the user with the actual user name. If we can write such a chain call:

The Code is as follows:


Chain (). users ('Michael '). repos


You can easily call the API. If you are interested, try writing it out.

_ Call __

An object instance can have its own attributes and Methods. When we call an instance method, we use instance. method () to call it. Can it be called directly on the instance itself? Like instance ()? In Python, the answer is yes.

For any class, you only need to define a _ call _ () method to call the instance directly. See the example:

The Code is as follows:


Class Student (object ):
Def _ init _ (self, name ):
Self. name = name

Def _ call _ (self ):
Print ('My name is % s. '% self. name)


The call method is as follows:

The Code is as follows:


>>> S = Student ('Michael ')
>>> S ()
My name is Michael.


_ Call _ () can also define parameters. It is better to call an instance directly than to call a function. Therefore, you can regard an object as a function and a function as an object, because there is no fundamental difference between the two.

If you regard an object as a function, the function itself can also be dynamically created during the runtime, because the class instances are created during the runtime, we blur the boundaries between objects and functions.

So how can we determine whether a variable is an object or a function? In fact, more often, we need to determine whether an object can be called. The called object is a Callable object, such as a function and the _ call () defined above () _ class instance:

The Code is as follows:


>>> Callable (Student ())
True
>>> Callable (max)
True
>>> Callable ([1, 2, 3])
False
>>> Callable (None)
False
>>> Callable ('string ')
False


Through the callable () function, we can determine whether an object is a "callable" object.

Summary

Python class allows you to define many custom methods, so that we can easily generate specific classes.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.