I've always been confused about the use of static, class, and abstract methods in Python. Recently saw a technical article on this aspect of interpretation is very good, in this translation, deepen the impression, also for the needy students to provide a convenience.
How the method works in Python:
A method is a function that is stored as a property of a class. You can declare and access a function like this:
class Pizza (object):
... def __init__ (self,size):
... Self.size = Size
... def get_size (self):
... return self.size
...
>>> pizza.get_size
<unbound Method pizza.get_size>
Python tells us here that the get_size property of thePizza class is not bound when accessed. What does that mean? We'll know right away as soon as we continue to invoke it:
>>> pizza.get_size ()
Traceback (most recent):
File "<stdin>", line 1, in <module>
instance as first
Argument (got nothing instead)
We cannot call it because it is not bound to any instance of Pizza . The method needs an instance as its first argument (in Python 2 It must be an instance of the class, in Python 3 it can be any instance), let's try it:
>>> pizza.get_size (Pizza (42))
42
It's working! When we call this method, we take an instance as its first parameter, so that everything is OK. But you will agree with my point of view: This is not a convenient way to invoke a method. We refer to the class every time we want to invoke the method. If we do not know which class makes our object, in a long period of time this way is not feasible.
As a result, Python has done all the methods of binding the Pizza class to any instance of the class. This means that the get_size property of an instance of the Pizza class is a binding method: the first parameter of the method is the instance itself:
>>> Pizza (get_size).
<bound method Pizza.get_size of <__main__. Pizza Object at 0x00000000025b3e48>>
>>> Pizza. Get_size ()
42
Unsurprisingly, we no longer need to provide any parameters for get_size because it is bound, and its self parameter is automatically set to our pizza instance. Here's a better proof:
>>> m = Pizza. get_size
>>> m ()
42
In fact, you don't even have to maintain a reference to your Pizza object. Its method is bound to an object, so the method is sufficient for itself.
But what if you want to know exactly which object this binding method is bound to? Here's a little trick:
>>> m = Pizza. get_size
>>> m.__self__
<__main__. Pizza Object at 0x0000000002a95cf8>
>>>
>>> m = = M.__self__.get_size
True
Obviously, we still have a reference to the object that can be found if necessary.
In Python 3, a method attached to a class is no longer considered a binding method, only as a simple function. If necessary, they are bound to an object. The principle remains the same, but the model is simplified.
class Pizza (object):
... def __init__ (self,size):
... Self.size = Size
... def get_size (self):
... return self.size
...
>>> pizza.get_size
<function pizza.get_size at 0x0000000002907268>
static method:
A static method is a special case of a method. Sometimes you need to write code that belongs to a class, but never use the object itself. For example:
class Pizza (object):
... @staticmethod
... def mix_ingredients (x, y):
... return X+y
... def Cook (self):
... return self.mix_ingredient (self.cheese,self.vegetables)
...
In this case, you can also work with mix_ingredients as a non-static function, but you must provide a self parameter (which is not used). Here, the adorner @staticmethod provides us with a few things:
- Python does not instantiate the binding function of the Pizza object we instantiate. Binding functions are also objects, and it is expensive to create them. Use static functions to avoid these:
>>> Pizza (). Cook is Pizza (). Cook
False
>>> Pizza (). Mix_ingredients is pizza.mix_ingredients
True
>>> Pizza (). Mix_ingredients is Pizza (). mix_ingredients
True
- Simplifies the readability of the code: seeing @staticmethod, we know that the method does not depend on the state of the object itself;
- It allows us to overload the mix_ingredients method in subclasses. If you use a mix_ingredients function defined at the top of our module, the class inheriting from Pizza cannot change the way we used to mix Pizza without overloading Cook itself. the ingredients.
class Method:
Having said so much, then what is a class method? A class method is a method that is not bound to an object but is bound to a class. (Note that I have the red section below, which is not the same as the original text, I run in Python 2.7.9 and Python 3.4.3 is false)
class Pizza (object):
... RADIUS = 42
... @classmethod
... def Get_radius (CLS):
... return Cls.radius
...
>>> Pizza.get_radius
<bound method Type.get_radius of <class '__main__. Pizza ' >>
>>> Pizza (). Get_radius
<bound method Type.get_radius of <class '__main__. Pizza ' >>
>>> Pizza.get_radius is Pizza (). Get_radius
False
>>> Pizza.get_radius ()
42
No matter how you access this method, it is always bound to the class it is attached to, and its first argument is the class itself (remember that the class is also the object).
So, when does this type of method happen? The class method is commonly used in two types of methods:
- The factory method, which is used to create an instance of a class for some preprocessing. If we use @staticmethod instead, we will have to hard-code the name of the Pizza class into our function. This makes it impossible for classes that inherit from Pizza to use our factory for their own use.
class Pizza (object):
... def __init__ (self, ingredients):
... Self.ingredients = Ingredients
...
... @classmethod
... def From_fridge (CLS, fridge):
... return CLS (Fridge.get_cheese () + fridge.get_vegetables ())
...
- Static methods Call static methods: If you split a static method into several static methods, you should not use the class method with hard coding. Using this method to assert our approach,Pizza names are never referenced and inherited and the method overloads work well.
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 Method:
The abstract method is defined in a base class, but may not provide any implementations. In Java, this method is described as an interface.
The simplest way to write an abstract method in Python is as follows:
class Pizza (object):
def Get_radius (self):
Raise Notimplementederror
Any other class that inherits from Pizza should implement and overload the Get_radius method. Otherwise an exception will be thrown.
There is a drawback to this particular way of implementing the extraction method. If you write a class that inherits from Pizza and forgets to implement Get_radius , the error is only thrown when you intend to try this method.
>>> Pizza ()
<__main__. Pizza Object at 0x0000000002b9c208>
>>> Pizza (). Get_radius ()
Traceback (most recent):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in Get_radius
Notimplementederror
There is a way to trigger this earlier, and when the object is instantiated, use the ABC module provided by Python.
>>>
class Basepizza (object):
... __metaclass__ = abc. Abcmeta
...
... @abc. Abstractmethod
... def Get_radius (self):
... """ Method that should do something. "" "
...
Using ABC and its special class, you will get a type error whenever you try to instantiate Basepizza or any class that inherits from it.
>>> Basepizza ()
Traceback (most recent):
File "<stdin>", line 1, in <module>
class Basepizza with abstract methods get_
Radius
mixed static, class, and abstract methods:
When building classes and inheriting, you need to mix these styles to decorate the time will come, here are some tips on it.
Remember that declaring a method is abstract and does not freeze the prototype of the method. This means that it has to be implemented, but 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):
if Else None
return self.ingredients + egg
This is effective because calzone satisfies the interface requirements that we define in the Basepizza object. This means that we can also implement it as a class or as a static method. For example:
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, in line with our contract with the Basepizza class. In fact, the get_ingredients method does not need to know that the object that returns the result is actually an implementation detail, not a standard that allows us to perform the contract.
Therefore, you cannot force the implementation of your abstract method to be an ordinary or a class or static method. Starting with Python 3 (which does not work in Python 2, refer to issue5867), it can now be used at the top of the @abstractmethod @staticmethod and @ Classmethod Decorative characters.
Import ABC
class Basepizza (object):
__metaclass__ = abc. Abcmeta
ingredient = [' cheese ']
@classmethod
@abc. Abstractmethod
def get_ingredients (CLS):
"" "Returns the ingredient list." ""
return cls.ingredients
Do not misread: if you think this will force your subclass to implement get_ingredients as a function of a class, then it is wrong. This simply means that the get_ingredients you implement in the Basepizza class is a class method.
Implementation in an abstract method? Yes, in Python, in contrast to the Java interface, you can encode in an abstract method and call it using super () :
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 case, every pizza you build that inherits from Basepizza has to reload the get_ingredients method, but you can use the default mechanism by using super () to get a list of ingredients.
Original address: Https://julien.danjou.info/blog/2013/guide-python-static-class-abstract-methods
Authoritative guidance on how to use static, class, and abstract methods in Python