I thought about why Python self is necessary with the feeling of a Python interpreter

Introduction

I read @ free_jinji2020's "I thought about why Python self is necessary as a beginner". I used another approach to imagine the internal structure and behavior of the Python interpreter, and actually verified the behavior with the Python interpreter, which deepened my understanding, so I will write down how to do it.

In addition, the operation check is done with Python3 series. Please note that the display result will be different in Python2 series.

Function definition: function object creation

When the Python interpreter reads a Python script and finds a " def definition ", it creates an" instance of the function class", makes it a "function object" that can call the process, and assigns it to the variable of the function name. The processing in the function is compiled into Bytecode and assigned to the function object. You can also disassemble the bytecode (https://docs.python.org/ja/3.5/library/dis.html).

>>> def hello():
...     print("Hello, world!")
...
>>> hello
<function hello at 0x6fffffd0dae8>
>>> type(hello)
<class'function'>
>>> hello()
Hello, world!
>>> hello.__code__.co_code.hex()
'740064018301010064005300'
>>> import dis
>>> dis.dis(hello)
  2           0 LOAD_GLOBAL              0 (print)
              2 LOAD_CONST               1 ('Hello, world!')
              4 CALL_FUNCTION            1
              6 POP_TOP
              8 LOAD_CONST               0 (None)
             10 RETURN_VALUE

Class definition: class object creation

When the Python interpreter finds a " class definition ", it instantiates a type class, makes it a "class object", and assigns it to a variable in the class name. A class object can create a ** namespace ** (** variable space **), define ** variables ** freely in the class object, and assign ** values ** and ** functions **. I will. Variables in the object can be seen with the vars function. You can also see the names in local scope with the dir function. I also have Various information.

>>> class Sample:
...     pass
...
>>> Sample.value = 123
>>> Sample.value * 3
369
>>> Sample.data = [1, 2, 3]
>>> vars(Sample)
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Sample' objects>, '__weakref__': <attribute '__weakref__' of 'Sample' objects>, '__doc__': None,
 'value': 123, 'data': [1, 2, 3]})
>>> dir(Sample)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> Sample.__name__
'Sample'

The function is not executed unless it is called, but the variable assignment (assignment to the class object) and function definition (assignment to the function object) written directly under the class definition are executed at the time of class definition.

>>> class Sample:
...     value = 123
...     print(value * 3)
...
369
>>> Sample.value
123

In-class function definition: function object assignment

If there is a def definition (function definition) in the class definition, the "function object" is assigned in the class object. It can be called with class name.function name ().

>>> class Sample:
...     def greet():
...         print("Hey, guys!")
...
>>> Sample
<class'__main__.Sample'>
>>> type(Sample)
<class'type'>
>>> Sample.greet
<function Sample.greet at 0x6fffffd0dd08>
>>> type(Sample.greet)
<class'function'>
>>> Sample.greet()
Hey, guys!

You can see that the greet function object (function greet) is assigned to the variable greet.

>>> vars(Sample)
mappingproxy({'__module__': '__main__', 'greet': <function Sample.greet at 0x6fffffd0dd08>, '__dict__': <attribute '__dict__' of 'Sample' objects>, '__weakref__': <attribute '__weakref__' of 'Sample' objects>, '__doc__': None})

Constructor: Instantiation

When creating a class object, the process called "constructor" is automatically set as __call__ method, and " You can now call the constructor with class name () ". Calling the constructor creates a "data area" called an "instance".

Instance: Data

Instances can also create namespaces (variable spaces), freely define variables and assign values. The initial instance is empty with no variables.

>>> data = Sample()
>>> vars(data)
{}
>>> data.name = "Taro"
>>> vars(data)
{'name': 'Taro'}

Let's define a "function" that displays the name assigned to the instance and display the name. You need an argument that tells which instance the name is.

>>> def introduce(data):
...     print("My name is", data.name)
...
>>> introduce(data)
My name is Taro

Assign a function to a class object

You can also call the ʻintroduce` function defined outside the class above by assigning it to a class object.

>>> introduce
<function introduce at 0x6fffffd0dc80>
>>> Sample.introduce = introduce
>>> Sample.introduce
<function introduce at 0x6fffffd0dc80>
>>> Sample.introduce(data)
My name is Taro

Method: method object

The "constructor" was automatically set when the class was created, but the "method" is automatically set when the instance is created. A "method" is an instance of the method class. There are various types of methods such as "instance method" and "class method". When you call a method, the function in the class object is called with the instance or class object as the first argument.

>>> Sample.introduce
<function introduce at 0x6fffffd0dc80>
>>> type(Sample.introduce)
<class'function'>
>>> data.introduce
<bound method introduce of <__main__.Sample object at 0x6fffffd16518>>
>>> type(data.introduce)
<class'method'>
>>> data.introduce()
My name is Taro

Instance method

I assigned the ʻintroduce` function defined outside the class to the class object, but it is easier to understand if the function definition is written inside the class.

>>> class Person:
...     def initialize(data, name):
...         data.name = name
...     def introduce(data):
...         print("My name is", data.name)
...
>>> taro = Person()
>>> vars(taro)
{}
>>> Person.initialize(taro, "Taro")
>>> vars(taro)
{'name': 'Taro'}
>>> Person.introduce(taro)
My name is Taro

You can also call in-class functions via instance methods. As I wrote earlier, the method calls the function in the class object with the instance itself as the first argument.

>>> hanako = Person()
>>> hanako.inittialize("Hanako")
>>> hanako.introduce()
My name is Hanako

Initialization method: __init__ method

After creating the instance, the name is set by calling the ʻinitialize method, but it would be convenient if the initial value could be specified in the argument of the constructor. That is the [initmethod](https://docs.python.org/ja/3.6/reference/datamodel.html#object.__init__). After the constructor instantiates, it calls theinit` method with the instance itself as the first argument. With the arguments passed to the constructor.

>>> class Person:
...     def __init__(self, name):
...         self.name = name
...     def introduce(self):
...         print("My name is", self.name)
...
>>> ichiro = Person("Ichiro")
>>> ichiro.introduce()
My name is Ichiro

Instance itself: self

In "PEP8: Python Code Style Guide", it says:

Always use self as the name of the first argument of the instance method. Always use cls as the name of the first argument of the class method.

It doesn't matter what the argument name is, but let's change the argument name data in the above code to self according to the style guide. That's the general way of writing.

Class method: @ classmethod

If you add a @ classmethod decorator when defining an in-class function, it will be replaced with a method that calls the first argument as a class object. You can define processing for each class that does not depend on the instance.

>>> class Sample:
...     @classmethod
...     def class_method(cls):
...         print("called:", cls)
...
>>> Sample.class_method
<bound method Sample.class_method of <class'__main__.Sample'>>
>>> Sample.class_method()
called: <class'__main__.Sample'>
>>> s = Sample()
>>> s.class_method
<bound method Sample.class_method of <class'__main__.Sample'>>
>>> s.class_method()
called: <class'__main__.Sample'>

Static method: @staticmethod

If you add a @staticmethod decorator when defining an in-class function, the function will be called directly without adding the first argument. It's the same as a normal function definition, but by putting it in the class namespace, you can define functions with the same name in various classes, so you don't have to worry about name conflicts.

>>> class Sample:
...     @staticmethod
...     def static_method():
...         print("Hello, world!")
...
>>> Sample.static_method
<function Sample.static_method at 0x6fffffd1e268>
>>> Sample.static_method()
Hello, world!
>>> s = Sample()
>>> s.static_method
<function Sample.static_method at 0x6fffffd1e268>
>>> s.static_method()
Hello, world!

at the end

Function objects are responsible for all processing in Python, and an argument is required to specify which data = instance = object to process, and the operation rule that the first argument name passed by the instance should be unified with self. Was found to be specified in PEP8.

I haven't followed the source code of the Python interpreter in depth, so I think there are some inaccuracies. I would appreciate it if you could give me comments such as suggestions. There were many things I could understand by thinking about the feelings of the Python interpreter. Why don't you think about the feelings of the Python interpreter?

Recommended Posts

I thought about why Python self is necessary with the feeling of a Python interpreter
Why is the first argument of [Python] Class self?
I took a closer look at why Python self is needed
[python] [meta] Is the type of python a type?
A memo that I touched the Datastore with python
A reminder about the implementation of recommendations in Python
[Python & SQLite] I analyzed the expected value of a race with horses with a win of 1x ②
About the ease of Python
About the features of Python
I replaced the Windows PowerShell cookbook with a python script.
I tried "gamma correction" of the image with Python + OpenCV
I thought about a Python beginner's course on blockchain games
Why can I use the module by importing with python?
I just changed the sample source of Python a little.
I wrote the basic grammar of Python with Jupyter Lab
Tank game made with python About the behavior of tanks
I evaluated the strategy of stock system trading with Python.
I tried a stochastic simulation of a bingo game with Python
I thought a little because the Trace Plot of the stan parameter is hard to see.
[Python] I want to make a 3D scatter plot of the epicenter with Cartopy + Matplotlib!
I wrote a doctest in "I tried to simulate the probability of a bingo game with Python"
I compared the speed of Hash with Topaz, Ruby and Python
[Python] What is a with statement?
I tried scraping the ranking of Qiita Advent Calendar with Python
Save the result of the life game as a gif with python
March 14th is Pi Day. The story of calculating pi with python
[python, ruby] fetch the contents of a web page with selenium-webdriver
[Python] What is @? (About the decorator)
[Introduction to StyleGAN] I played with "The Life of a Man" ♬
I want to output the beginning of the next month with Python
I made a fortune with Python.
I made a lot of files for RDP connection with Python
The story of making a standard driver for db with python.
A list of functions that I came across with 100 Numpy knocks and thought "This is convenient!"
I liked the tweet with python. ..
I wanted to solve the ABC164 A ~ D problem with Python
The idea of feeding the config file with a python file instead of yaml
The latest NGINX is an application server! ?? I measured the benchmark of NGINX Unit with PHP, Python, Go! !!
After researching the Python library, I understood a little about egg.info.
I tried to improve the efficiency of daily work with Python
I want to clear up the question of the "__init__" method and the "self" argument of a Python class.
I made a daemon with Python
About the basics list of Python basics
The story of making a module that skips mail with python
I did a lot of research on how Python is executed
A simple reason why the return value of round (2.675,2) is 2.67 in python (it should be 2.68 in reality ...)
Create a compatibility judgment program with the random module of python.
I'm tired of Python, so I analyzed the data with nehan (corona related, is that word now?)
[AtCoder explanation] Control the A, B, C problems of ABC182 with Python!
What is the XX file at the root of a popular Python project?
Calculate the shortest route of a graph with Dijkstra's algorithm and Python
Get the number of searches with a regular expression. SeleniumBasic VBA Python
[AtCoder explanation] Control the A, B, C problems of ABC186 with Python!
[Introduction to Python] How to sort the contents of a list efficiently with list sort
I tried to get the authentication code of Qiita API with Python.
[AtCoder explanation] Control the A, B, C problems of ABC185 with Python!
Calculate the probability of being a squid coin with Bayes' theorem [python]
Hit a method of a class instance with the Python Bottle Web API
Receive a list of the results of parallel processing in Python with starmap
[Python, ObsPy] I drew a beach ball on the map with Cartopy + ObsPy.
I made a GAN with Keras, so I made a video of the learning process.