search
HomeBackend DevelopmentPython TutorialWhat is the self parameter in Python?

What is the self parameter in Python?

May 08, 2023 pm 05:49 PM
pythonelf

Python 的

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!

Statement
This article is reproduced at:51CTO.COM. If there is any infringement, please contact admin@php.cn delete
Explain the performance differences in element-wise operations between lists and arrays.Explain the performance differences in element-wise operations between lists and arrays.May 06, 2025 am 12:15 AM

Arraysarebetterforelement-wiseoperationsduetofasteraccessandoptimizedimplementations.1)Arrayshavecontiguousmemoryfordirectaccess,enhancingperformance.2)Listsareflexiblebutslowerduetopotentialdynamicresizing.3)Forlargedatasets,arrays,especiallywithlib

How can you perform mathematical operations on entire NumPy arrays efficiently?How can you perform mathematical operations on entire NumPy arrays efficiently?May 06, 2025 am 12:15 AM

Mathematical operations of the entire array in NumPy can be efficiently implemented through vectorized operations. 1) Use simple operators such as addition (arr 2) to perform operations on arrays. 2) NumPy uses the underlying C language library, which improves the computing speed. 3) You can perform complex operations such as multiplication, division, and exponents. 4) Pay attention to broadcast operations to ensure that the array shape is compatible. 5) Using NumPy functions such as np.sum() can significantly improve performance.

How do you insert elements into a Python array?How do you insert elements into a Python array?May 06, 2025 am 12:14 AM

In Python, there are two main methods for inserting elements into a list: 1) Using the insert(index, value) method, you can insert elements at the specified index, but inserting at the beginning of a large list is inefficient; 2) Using the append(value) method, add elements at the end of the list, which is highly efficient. For large lists, it is recommended to use append() or consider using deque or NumPy arrays to optimize performance.

How can you make a Python script executable on both Unix and Windows?How can you make a Python script executable on both Unix and Windows?May 06, 2025 am 12:13 AM

TomakeaPythonscriptexecutableonbothUnixandWindows:1)Addashebangline(#!/usr/bin/envpython3)andusechmod xtomakeitexecutableonUnix.2)OnWindows,ensurePythonisinstalledandassociatedwith.pyfiles,oruseabatchfile(run.bat)torunthescript.

What should you check if you get a 'command not found' error when trying to run a script?What should you check if you get a 'command not found' error when trying to run a script?May 06, 2025 am 12:03 AM

When encountering a "commandnotfound" error, the following points should be checked: 1. Confirm that the script exists and the path is correct; 2. Check file permissions and use chmod to add execution permissions if necessary; 3. Make sure the script interpreter is installed and in PATH; 4. Verify that the shebang line at the beginning of the script is correct. Doing so can effectively solve the script operation problem and ensure the coding process is smooth.

Why are arrays generally more memory-efficient than lists for storing numerical data?Why are arrays generally more memory-efficient than lists for storing numerical data?May 05, 2025 am 12:15 AM

Arraysaregenerallymorememory-efficientthanlistsforstoringnumericaldataduetotheirfixed-sizenatureanddirectmemoryaccess.1)Arraysstoreelementsinacontiguousblock,reducingoverheadfrompointersormetadata.2)Lists,oftenimplementedasdynamicarraysorlinkedstruct

How can you convert a Python list to a Python array?How can you convert a Python list to a Python array?May 05, 2025 am 12:10 AM

ToconvertaPythonlisttoanarray,usethearraymodule:1)Importthearraymodule,2)Createalist,3)Usearray(typecode,list)toconvertit,specifyingthetypecodelike'i'forintegers.Thisconversionoptimizesmemoryusageforhomogeneousdata,enhancingperformanceinnumericalcomp

Can you store different data types in the same Python list? Give an example.Can you store different data types in the same Python list? Give an example.May 05, 2025 am 12:10 AM

Python lists can store different types of data. The example list contains integers, strings, floating point numbers, booleans, nested lists, and dictionaries. List flexibility is valuable in data processing and prototyping, but it needs to be used with caution to ensure the readability and maintainability of the code.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version

MantisBT

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.

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

PhpStorm Mac version

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool