Deep understanding of how the various methods in Python work

Source: Internet
Author: User
How the method works in Python

A method is a function that exists as a class property and you can declare and access a function in the following way:

>>> class Pizza (object): ...   def __init__ (self, size): ...     self.size = Size   ... def get_size (self): ...     return self.size...>>> Pizza.get_size
 
  

Python is telling you that property _get_size is an unbound method of class pizza. What does that mean? Soon we'll know the answer:

>>> pizza.get_size () Traceback (most recent call last): File "
 
  
   
  ", line 1, in 
  
   
    
   Typeerror:unbound method Get_size () must is called with Pizza instance as first argument (got nothing instead)
  
 
   
  

We cannot call this because it is not bound to any instance of the pizza class, it requires an instance to be passed in as the first argument (Python2 must be an instance of the class, anything in Python3), try:

>>> pizza.get_size (Pizza (42))

Great, now use an instance as its first argument to call, the whole world is quiet, if I say this call method is not the most convenient, you will think so; Yes, now every time we call this method we have to refer to this class, if we do not know which class is our object, In the long run, this approach is unworkable.

So what does Python do for us, it binds all methods from the class _pizza and any one instance of the class. It also means that the property get_size is now the binding method of an instance object of pizza, the first parameter of this method is the instance itself.

>>> Pizza (get_size
 
  <__main__.pizza object="" at="" 0x7f3138827910="">
  >>>> Pizza).
 get_size ()
  

As we expected, it is no longer necessary to provide any parameters to _get_size, because it is already bound, and its self parameter is automatically set to the pizza instance, and the following code is the best proof:

>>> m = Pizza (.get_size>>> m () 42

What's more, you don't have to use a reference to hold the pizza object because the method is already bound to the object, so this method is sufficient for itself.

Perhaps, if you want to know which object the binding is bound to, the following means are available:

>>> m = Pizza (.get_size>>>) m.__self__<__main__. Pizza object at 0x7f3138827910>>>> # could guess, look at this:...>>> m = = M.__self__.get_sizetru E

Obviously, the object still has a reference to it, and you can still get it back if you want.

In Python3, a function attached to a class is no longer considered an unbound method, but rather as a simple function, and if necessary it binds to an object, and the principle remains consistent with the Python2, but the module is more concise:

>>> class Pizza (object): ...   def __init__ (self, size): ...     self.size = Size   ... def get_size (self): ...     return self.size...>>> Pizza.get_size
 
  

Static methods

Static methods are a special kind of method, and sometimes you may need to write a method that belongs to this class, but the code does not use the instance object itself at all, for example:

Class Pizza (object):  @staticmethod  def mix_ingredients (x, y):    return x + y   def Cook (self):    return Self.mix_ingredients (Self.cheese, Self.vegetables)

In this example, the _mix_ingredients can be run as a non-static method, but it provides the self parameter, which is not used in the method at all. The @staticmethod decorator here can bring us some benefits:

Python no longer needs to initialize a binding method for an Pizza object instance, the binding method is also an object, but creating them requires cost, and static methods can avoid these.

>>> Pizza (). Cook is Pizza () .cookfalse>>> Pizza (). Mix_ingredients is pizza.mix_ingredientstrue> >> Pizza (). Mix_ingredients is Pizza (). mix_ingredientstrue

More readable code, see @staticmethod We know that this method does not need to depend on the state of the object itself.
Can be overridden in subclasses, if the mix_ingredients is used as the top-level function of the module, then the subclass inheriting from pizza cannot change the mix_ingredients of pizza if it is not covered by cook.

Class method

That being said, what is a class method? A class method is not bound to an object, but is bound to a method on a class.

>>> class Pizza (object): ...   Radius =   ...   @classmethod ... def Get_radius (CLS): ...     return Cls.radius >>> >>> pizza.get_radius
 
  
  
   
  >>>> Pizza (). get_ Radius
  
   
    
   
   >>>> Pizza.get_radius is Pizza () .get_radiustrue>>> Pizza.get_radius ()
 
  

Regardless of the way you access this method, it is always bound to the class, and its first argument is the class itself (remember: The class is also an object).

When do you use this method? Class methods are typically useful in the following two scenarios:

Factory method: It is used to create an instance of a class, such as some preprocessing. If we use @staticmethod instead, we have to hardcode the pizza class name in the function, which makes it impossible for any class inheriting pizza to use this factory method for itself.

Class Pizza (object):  def __init__ (self, ingredients):    self.ingredients = Ingredients   @classmethod  Def from_fridge (CLS, fridge):    return CLS (Fridge.get_cheese () + fridge.get_vegetables ())

Call Static class: If you split a static method into multiple static methods, you will have to hardcode the class name unless you use a class method. Declaring a method in this way, the pizza class name will never be directly referenced, inherited, and method overrides work perfectly.


Class Pizza (object):  def __init__ (self, radius, height):    self.radius = radius    self.height = height   @ Staticmethod  def compute_area (RADIUS):     return Math.PI * (RADIUS * * 2)   @classmethod  def compute_ Volume (CLS, Height, radius):     return Height * cls.compute_area (RADIUS)   def get_volume (self):    return Self.compute_volume (Self.height, Self.radius)

Abstract methods

An abstract method is a method defined in a base class that does not provide any implementation, similar to a method in the Java Interface (Interface).

The simplest way to implement abstract methods in Python is to:

Class Pizza (object):  def Get_radius (self):    raise Notimplementederror

Any class that inherits from _pizza must override the implementation method Get_radius, or an exception will be thrown.

The implementation of this abstract method has its drawbacks, if you write a class to inherit pizza, but forget to implement Get_radius, the exception will only be thrown out when you actually use it.

>>> Pizza () <__main__. Pizza object at 0x7fb747353d90>>>> Pizza (). Get_radius () Traceback (most recent call last): File "
 
  
    ", line 1, in 
  
   
    
    File"
   
    
     
    , Line 3, in Get_radiusnotimplementederror
   
    
  
   
 
  

There is also a way to trigger an error earlier, using the ABC module provided by Python, after which the object is initialized to throw an exception:

Import ABC class Basepizza (object):  __metaclass__ = abc. Abcmeta   @abc. Abstractmethod  def Get_radius (self): "" "     Method, should do something." "

With ABC, when you try to initialize Basepizza or any subclass, you get a typeerror immediately, without having to wait until the Get_radius is actually called to find the exception.

>>> Basepizza () Traceback (most recent): File "
 
  
   
  ", line 1, in 
  
   
    
   Typeerror:can ' T instantiate abstract class Basepizza with abstract methods Get_radius
  
   
 
  

Mixed static methods, class methods, abstract methods

When you start building classes and inheritance structures, it's time to mix up these adorners, so here are some tips.

Remember, declaring an abstract method does not fix the prototype of the method, which means that although you have to implement it, I can do it with any parameter list:

Import ABC class Basepizza (object):  __metaclass__ = abc. Abcmeta   @abc. Abstractmethod  def get_ingredients (self): "" "     Returns the ingredient list." "Class Calzone ( Basepizza):  def get_ingredients (self, with_egg=false):    egg = egg () If With_egg else None    return Self.ingredients + Egg

This is allowed because the calzone satisfies the interface requirements defined by the Basepizza object. We can also use a class method or a static method to implement:

Import ABC class Basepizza (object):  __metaclass__ = abc. Abcmeta   @abc. Abstractmethod  def get_ingredients (self): "" "     Returns the ingredient list." "" Class Dietpizza (Basepizza):  @staticmethod  def get_ingredients ():    return None

This is also true because it follows the contract set by the abstract class Basepizza. In fact, the Get_ingredients method does not need to know what the return result is, the result is the implementation details, not the contract condition.

Therefore, you cannot force the implementation of an abstract method to be a regular method, a class method, or a static method, and there is nothing to argue about. Starting with Python3 (not in Python2 as you would expect, see issue5867), it is possible to use @staticmethod and @classmethod adorners above the Abstractmethod method.

Import ABC class Basepizza (object):  __metaclass__ = abc. Abcmeta   ingredient = [' cheese ']   @classmethod  @abc. Abstractmethod  def get_ingredients (CLS): "     " "Returns the ingredient list.     " "" " Return cls.ingredients

Don't get me wrong, if you think it will force subclasses to implement Get_ingredients as a class method, then you're wrong, it just means that the get_ingredients you implement is a class method in Basepizza.

Can the code be implemented in an abstract way? Yes, Python, in contrast to the methods in the Java interface, you can write the implementation code in an abstract method to invoke it through Super (). (Note: In Java8, the interface also provides the default method, allowing the implementation of the Write method in the interface)

Import ABC class Basepizza (object):  __metaclass__ = abc. Abcmeta   default_ingredients = [' cheese ']   @classmethod  @abc. Abstractmethod  def get_ingredients (CLS ): "" "     Returns the ingredient list.     " " Return Cls.default_ingredients class Dietpizza (Basepizza):  def get_ingredients (self):    return [' egg '] + super ( Dietpizza, self). Get_ingredients ()

In this example, each pizza you build is inherited Basepizza, and you have to override the Get_ingredients method, but you can use the default mechanism to get the ingredient list through Super ().

  • 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.