Let’s start with what we already know: self - the first parameter in the method - refers to the class instance:
class MyClass: ┌─────────────────┐ ▼ │ def do_stuff(self, some_arg): │ print(some_arg)▲│ ││ ││ ││ ││ instance = MyClass() ││ instance.do_stuff("whatever") │ │ │ └───────────────────────────────┘
Also, this argument doesn't actually have to be called self - it's just a convention. For example, you can use it as is common in other languages.
The above code may be natural and obvious because you have been using it, but we only gave .do_stuff() one argument (some_arg), but the method declares two (self and, some_arg) , it doesn’t seem to make sense. The arrow in the snippet shows that self is translated into an instance, but how is it actually passed?
instance = MyClass() MyClass.do_stuff(instance, "whatever")
What Python does internally is convert instance.do_stuff("whatever") to MyClass.do_stuff(instance, "whatever"). We could call it "Python magic" here, but if we want to really understand what's going on behind the scenes, we need to understand what Python methods are and how they relate to functions.
Class Attributes/Methods
In Python, there is no such thing as a "method" object - in fact methods are just regular functions. The difference between functions and methods is that methods are defined in the namespace of a class, making them properties of that class.
These attributes are stored in the class dictionary __dict__ and we can access them directly or using the vars built-in function:
MyClass.__dict__["do_stuff"] # <function MyClass.do_stuff at 0x7f132b73d550> vars(MyClass)["do_stuff"] # <function MyClass.do_stuff at 0x7f132b73d550>
The most common way to access them is the "class method ” Way:
print(MyClass.do_stuff) # <function MyClass.do_stuff at 0x7f132b73d550>
Here we access the function using the class attribute and as expected print do_stuff is a function of MyClass. However, we can also access it using instance properties:
print(instance.do_stuff) # <bound method MyClass.do_stuff of <__main__.MyClass object at 0x7ff80c78de50>
But in this case, we get a "bound method" instead of the original function. What Python does for us here is that it binds class attributes to instances, creating what are called "binding methods". This "bound method" is a wrapper around the underlying function, which already inserts the instance as the first argument (self).
Thus, methods are ordinary functions with a class instance (self) appended to their other parameters.
To understand how this happens, we need to look at the descriptor protocol.
Descriptor Protocol
Descriptors are the mechanism behind methods, they are objects (classes) that define __get__(), __set__(), or __delete__() methods. To understand how self works, let's just consider __get__(), which has a signature:
descr.__get__(self, instance, type=None) -> value
But what does the __get__() method actually do? It allows us to customize property lookup in a class - or in other words - customize what happens when class properties are accessed using dot notation. This is very useful considering that methods are really just properties of the class. This means we can use the __get__ method to create a "bound method" of a class.
To make it easier to understand, let's demonstrate this by implementing a "method" using a descriptor. First, we create a pure Python implementation of a function object:
import types class Function: def __get__(self, instance, objtype=None): if instance is None: return self return types.MethodType(self, instance) def __call__(self): return
The Function class above implements __get__ , which makes it a descriptor. This special method receives the class instance in the instance parameter - if this parameter is None, we know that the __get__ method was called directly from a class (e.g. MyClass.do_stuff), so we just return self. However, if it is called from a class instance, such as instance.do_stuff, then we return types.MethodType, which is a way of manually creating a "bound method".
In addition, we also provide the __call__ special method. __init__ is called when a class is called to initialize an instance (e.g. instance = MyClass()), while __call__ is called when an instance is called (e.g. instance()). We need to use this because self in types.MethodType(self, instance) must be callable.
Now that we have our own function implementation, we can use it to bind methods to the class:
class MyClass: do_stuff = Function() print(MyClass.__dict__["do_stuff"])# __get__ not invoked # <__main__.Function object at 0x7f229b046e50> print(MyClass.do_stuff)# __get__ invoked, but "instance" is None, "self" is returned print(MyClass.do_stuff.__get__(None, MyClass)) # <__main__.Function object at 0x7f229b046e50> instance = MyClass() print(instance.do_stuff)#__get__ invoked and "instance" is not None, "MethodType" is returned print(instance.do_stuff.__get__(instance, MyClass)) # <bound method ? of <__main__.MyClass object at 0x7fd526a33d30>
By giving MyClass an attribute do_stuff of type Function, we Roughly emulates what Python does when defining methods in a class's namespace.
To sum up, when accessing attributes such as instance.do_stuff, do_stuff is searched in the attribute dictionary (__dict__) of the instance. If do_stuff defines a __get__ method, do_stuff.__get__ is called, ultimately calling:
# For class invocation: print(MyClass.__dict__['do_stuff'].__get__(None, MyClass)) # <__main__.Function object at 0x7f229b046e50> # For instance invocation: print(MyClass.__dict__['do_stuff'].__get__(instance, MyClass)) # Alternatively: print(type(instance).__dict__['do_stuff'].__get__(instance, type(instance))) # <bound method ? of <__main__.MyClass object at 0x7fd526a33d30>
As we know now - a bound method will be returned - a callable wrapped around the original function Wrapper whose parameters are preceded by self!
If you want to explore this further, static and class methods can be implemented similarly (https://docs.python.org/3.7/howto/descriptor.html#static-methods-and-class-methods)
Why is self in the method definition?
We now know how it works, but there is a more philosophical question - "Why does it have to appear in the method definition?"
The explicit self method parameter is controversial design choice, but it's one that favors simplicity.
Python self-embodies the "worse is better" design philosophy - described here . The priority of this design concept is "simplicity", which is defined as:
The design must be simple, including implementation and interfaces. It's more important that the implementation is simple than the interface...
This is exactly the case with self - a simple implementation at the expense of the interface, where the method signature doesn't match its invocation.
There are of course more reasons why we should write self explicitly, or why it must be preserved, some of which are described in a blog post by Guido van Rossum (http://neopythonic.blogspot.com/ 2008/10/why-explicit-self-has-to-stay.html), the article responded to a request for its removal.
Python abstracts away a lot of complexity, but in my opinion digging into the low-level details and complexity is extremely valuable for better understanding of how the language works, when things break and advanced troubleshooting/debugging When not enough, it can come in handy.
Also, understanding descriptors can actually be quite practical since they have some use cases. While most of the time you really only need @property descriptors, there are some cases where custom descriptors make sense, such as those in SLQAlchemy or e.g. custom validators.
The above is the detailed content of What is the self parameter in Python?. For more information, please follow other related articles on the PHP Chinese website!

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于Seaborn的相关问题,包括了数据可视化处理的散点图、折线图、条形图等等内容,下面一起来看一下,希望对大家有帮助。

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于进程池与进程锁的相关问题,包括进程池的创建模块,进程池函数等等内容,下面一起来看一下,希望对大家有帮助。

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于简历筛选的相关问题,包括了定义 ReadDoc 类用以读取 word 文件以及定义 search_word 函数用以筛选的相关内容,下面一起来看一下,希望对大家有帮助。

VS Code的确是一款非常热门、有强大用户基础的一款开发工具。本文给大家介绍一下10款高效、好用的插件,能够让原本单薄的VS Code如虎添翼,开发效率顿时提升到一个新的阶段。

pythn的中文意思是巨蟒、蟒蛇。1989年圣诞节期间,Guido van Rossum在家闲的没事干,为了跟朋友庆祝圣诞节,决定发明一种全新的脚本语言。他很喜欢一个肥皂剧叫Monty Python,所以便把这门语言叫做python。

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于数据类型之字符串、数字的相关问题,下面一起来看一下,希望对大家有帮助。

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于numpy模块的相关问题,Numpy是Numerical Python extensions的缩写,字面意思是Python数值计算扩展,下面一起来看一下,希望对大家有帮助。


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Dreamweaver CS6
Visual web development tools

SecLists
SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

MantisBT
Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

ZendStudio 13.5.1 Mac
Powerful PHP integrated development environment
