Details of the difference between s and s and s and s in Python

  • 2020-04-02 13:51:34
  • OfStack

S the method of s/s?

Those of you who have written object-oriented code in Python may be familiar with the s/s method, which is usually used to initialize an instance of a class. Such as:


# -*- coding: utf-8 -*-

class Person(object):
  """Silly Person"""

  def __init__(self, name, age):
    self.name = name
    self.age = age

  def __str__(self):
    return '<Person: %s(%s)>' % (self.name, self.age)

if __name__ == '__main__':
  piglei = Person('piglei', 24)
  print piglei

This is the most common use of arbitration. But s not actually the first method to be called when instantiating a class. When instantiating a class with an expression like Persion(name, age), the first method to be called is actually the s method.

S the method of s/s s/s?

The s/s accepted by the s/s method are the same as with the s/s method, but with the s/s method called after the class instance is created.


# -*- coding: utf-8 -*-

class Person(object):
  """Silly Person"""

  def __new__(cls, name, age):
    print '__new__ called.'
    return super(Person, cls).__new__(cls, name, age)

  def __init__(self, name, age):
    print '__init__ called.'
    self.name = name
    self.age = age

  def __str__(self):
    return '<Person: %s(%s)>' % (self.name, self.age)

if __name__ == '__main__':
  piglei = Person('piglei', 24)
  print piglei

Execution results:


piglei@macbook-pro:blog$ python new_and_init.py
__new__ called.
__init__ called.
<Person: piglei(24)>

By running this code, we can see that the call to the method is prior to arbitration. When you instantiate a class, the execution logic goes like this:

1. P = Person (name, age)

2. First execute the s/s method of the Person class with the name and age arguments, this s/s method returns an instance of the Person class (usually using super(Persion, CLS). S/s. ...). The way)

3. Then use this instance to call the class's s s method with the instance of s s

So, The major difference between arbitration and arbitration is:

1. S/s is usually used to initialize a new instance and to control the initialization process, such as adding some properties and doing some additional operations, after the class instance has been created. It is an instance-level method.
2. S/s is usually used to control the process of generating a new instance. It is a method at the class level.

But with all that said, what's the most common use of arbitration, and when shall we have to arbitration?

The role of __new__

According to Python's official documentation, the s/s method provides you with a way to customize the instantiation of immutable classes (such as int, STR, tuple) while you inherit them. Then there is the implementation of a custom metaclass.

First, let's take a look at the first function. We can use int as an example:

If we needed an integer type that was always positive, by integrating int, we might write something like this.


class PositiveInteger(int):
  def __init__(self, value):
    super(PositiveInteger, self).__init__(self, abs(value))

i = PositiveInteger(-3)
print i

But when we run it, it's not what we thought it would be, we still get minus 3. This is because for an immutable object like int, we can only customize by reloading its s/s method.

This is the modified code:


class PositiveInteger(int):
  def __new__(cls, value):
    return super(PositiveInteger, cls).__new__(cls, abs(value))

i = PositiveInteger(-3)
print i

By reloading the method with the new one, we have achieved the desired functionality.

Another function is to customize the metaclass. In fact, the first time I came to touch with with s/s is to customize the metaclass, but due to the space, we will talk about the relationship between s/s and s/s in python next time.

Use s/s to implement the singleton

In fact, once we understand the s/s method, we can use it to do other interesting things, such as implementing singletons in design patterns.

Since the process generated after each class instantiation is controlled by arbitration with successive classes, we can simply implement the singleton pattern by reloading the method with successive classes.


class Singleton(object):
  def __new__(cls):
    #  The point is that every time we instantiate, we're only going to return this one instance object 
    if not hasattr(cls, 'instance'):
      cls.instance = super(Singleton, cls).__new__(cls)
    return cls.instance

obj1 = Singleton()
obj2 = Singleton()

obj1.attr1 = 'value1'
print obj1.attr1, obj2.attr1
print obj1 is obj2

Output results:

Value1 value1
True,

You can see that obj1 and obj2 are the same instance.


Related articles: