A summary of the special methods of implementing custom classes in Python _python

Source: Internet
Author: User
Tags instance method in python

It's a special use in Python to see a variable or function name like __slots__ such as __xxx__.

__slots__ we already know how to use it, the __len__ () method is also known to allow class to function in the Len () function.

In addition, there are many special-purpose functions in Python's class that can help us customize our classes.

__str__

Let's first define a student class and print an instance:

Copy Code code as follows:

>>> class Student (object):
... def __init__ (self, name):
... self.name = name
...
>>> print Student (' Michael ')
<__main__. Student Object at 0x109afb190>

Print out a bunch of <__main__. Student object at 0x109afb190>, not good-looking.

How can you print it beautifully? Just define the __str__ () method and return to a nice string:

Copy Code code 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)

This kind of printed example, not only good-looking, but also easy to see the important data inside the instance.

But careful friends will find that the direct typing of variables without print, the printed example is still not good to see:

Copy Code code as follows:

>>> s = Student (' Michael ')
>>> s
<__main__. Student Object at 0x109afb310>

This is because the direct display of variable calls is not __str__ (), but __repr__ (), the difference being that __str__ () returns the string that the user sees, and __repr__ () returns the string that the program developer saw, that is, __repr__ () is a service for debugging.

The solution is to redefine a __repr__ (). But usually the __str__ () and __repr__ () code are the same, so there's a lazy way to do it:

Copy Code code 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 wants to be used for ... in loops, like list or tuple, you must implement a __iter__ () method that returns an iteration object, and then Python's for loop calls the next () of the Iteration object continuously. Method gets the next value of the loop until the loop is exited when a stopiteration error is encountered.

We take the Fibonacci sequence as an example, write a fib class that can be used for a For loop:

Copy Code code as follows:

Class Fib (object):
def __init__ (self):
SELF.A, self.b = 0, 1 # Initialize two counters a,b

def __iter__ (self):
Return self # The instance itself is an iterative object, so go back to your

Def next (self):
SELF.A, self.b = self.b, SELF.A + self.b # calculates the next value
If SELF.A > 100000: # Conditions for exiting loops
Raise Stopiteration ();
Return SELF.A # returns the next value

Now, try to apply the FIB instance to the For loop:

Copy Code code as follows:

>>> for N in Fib ():
... print n
...
1
1
2
3
5
...
46368
75025

__getitem__

Although the FIB instance can be used for a for loop, it looks a bit like the list, but it doesn't work as a list, for example, take the 5th element:

Copy Code code as follows:

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

To behave like a list, you need to implement the __getitem__ () method by following the subscript to remove the element:
Copy Code code as follows:

Class Fib (object):
def __getitem__ (self, N):
A, B = 1, 1
For x in range (n):
A, B = B, A + b
Return a

You can now access any one of the series by subscript:
Copy Code code as follows:

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

But the list has a magical slicing method:
Copy Code code as follows:

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

For FIB but the error. The reason is that __getitem__ () the parameters passed in may be an int, or a slice object slice, so make a judgment:
Copy Code code 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 a
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)
A, B = B, A + b
Return L

Now try the fib slices:
Copy Code code 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:
Copy Code code as follows:

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

There is no processing of negative numbers, so there is still a lot of work to do to implement a __getitem__ () correctly.

In addition, if you think of an object as an argument to dict,__getitem__ () it may also be an object that can be a key, such as Str.

corresponding to the __setitem__ () method, the object is treated as a list or dict to assign a value to the set. Finally, there is a __delitem__ () method for deleting an element.

In short, the above method, our own definition of the class performance and Python from the list, tuple, Dict no different, this is entirely due to the dynamic language of the "duck type", do not need to force an interface to inherit.

__getattr__

Normally, when we call a class's method or property, if it does not exist, an error is encountered. For example, define the student class:

Copy Code code as follows:

Class Student (object):

def __init__ (self):
Self.name = ' Michael '


The call to the Name property is fine, but there is a problem invoking the score property that does not exist:
Copy Code code 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 we have not found the attribute of score.

To avoid this error, in addition to adding a score attribute, Python has another mechanism, which is to write a __getattr__ () method that dynamically returns an attribute. Modified as follows:

Copy Code code as follows:

Class Student (object):

def __init__ (self):
Self.name = ' Michael '

def __getattr__ (self, attr):
If attr== ' score ':
Return 99


When an attribute is invoked that does not exist, such as the Score,python interpreter tries to invoke __getattr__ (self, ' score ') to try to get the property, so that we have a chance to return the score value:
Copy Code code as follows:

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

The return function is also perfectly acceptable:
Copy Code code as follows:

Class Student (object):

def __getattr__ (self, attr):
If attr== ' age ':
Return lambda:25


Just call the way to change:
Copy Code code as follows:

>>> S.age ()
25

Note that __getattr__ is invoked only if an attribute is not found, and an existing property, such as name, is not searched in __getattr__.

Also, note that any call like S.ABC returns NONE, because the default return of the __getattr__ we define is none. To have the class respond to only a specific number of attributes, we will throw the Attributeerror error by convention:

Copy Code code as follows:

Class Student (object):

def __getattr__ (self, attr):
If attr== ' age ':
Return lambda:25
Raise Attributeerror (' student\ ' object has no attribute \ '%s\ '% attr)


This actually allows all of the properties and method invocations of a class to be dynamically processed, without any special means required.

What is the real effect of this fully dynamic invocation of properties? The effect is that it can be invoked for a completely dynamic situation.

As an example:

Now many web sites are doing rest APIs, such as Sina Weibo, watercress, the URL of the call API is similar to:

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

If you want to write the SDK, the corresponding API for each URL to write a method, that is dead, and, once the API changes, the SDK will also change.

With fully dynamic __getattr__, we can write a chained call:

Copy Code code 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:
Copy Code code as follows:

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

In this way, no matter how the API changes, the SDK can be fully dynamic according to the URL implementation of the call, and not with the increase in the API to change!

There are also some rest APIs that place parameters in URLs, such as the GitHub API:

Copy Code code as follows:

Get/users/:user/repos

When called, you need to replace: User with the actual username. If we can write such a chained call:
Copy Code code as follows:

Chain (). Users (' Michael '). Repos

The API can be invoked very conveniently. Interested children's shoes can try to write them out.

__call__

An object instance can have its own properties and methods, and when we call an instance method, we use Instance.method () to invoke it. Can you call it directly on the instance itself? Similar to instance ()? In Python, the answer is yes.

Any class, you just need to define a __call__ () method to invoke the instance directly. Take a look at the example:

Copy Code code as follows:

Class Student (object):
def __init__ (self, name):
Self.name = Name

def __call__ (self):
Print (' My name is%s. '% self.name)


The method is invoked as follows:
Copy Code code as follows:

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

__CALL__ () can also define parameters. Making a direct call to an instance is like calling a function, so you can simply look at the object as a function and think of the function as an object, because there is no fundamental difference between the two.

If you look at the object as a function, then the function itself can be created dynamically at runtime, because instances of the class are created by the runtime, so we blur the bounds of the objects and functions.

So, how do you judge whether a variable is an object or a function? In fact, more often than not, we need to judge whether an object can be invoked, and the object that can be invoked is a callable object, such as a function and the class instance we defined above with __call () __:

Copy Code code as follows:

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

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

Summary

Python class allows you to define a number of custom methods that allow us to 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.