Переменная self в Python с примерами

Если вы работали с Python, то, возможно, сталкивались с переменной self. Ее можно встретить в определениях методов и при инициализации переменных. В этой статье мы познакомим вас с self поближе.

Содержание

Методы класса и экземпляра в Python

Возможно, изучая Python, вы уже встречали такие термины, как «экземпляры» и «классы». Переменные класса определяются внутри него и являются общими для всех экземпляров (объектов) этого класса. А переменные экземпляра принадлежат экземплярам класса. Для разных экземпляров переменные экземпляра различны. 

Аналогичным образом в Python существуют методы класса и методы экземпляра. Методы класса информируют о состоянии класса. Методы экземпляра предназначены для установки или получения информации об экземплярах или объектах.

 Если вы хотите определить метод экземпляра, то его главным параметром всегда должен быть self. Давайте рассмотрим пример: 

class myClass:
    def instance_method(self):
        return "Instance method is called", self

Метод instance_method является обычным методом экземпляра. Он принимает единственный параметр — self. Переменная self при вызове метода указывает на экземпляр класса myClass. Хотя здесь метод принимает только один параметр, он может принимать и больше. 

С помощью переменной self методы экземпляра могут легко получить доступ к различным атрибутам и другим методам одного и того же объекта. Переменная self также способна изменять состояние объекта, а с помощью атрибута self.__class__  методы экземпляра также могут получить доступ к классу. Таким образом, методы экземпляра также могут изменять состояние класса. 

Теперь посмотрим, что произойдет, если мы вызовем instance_method

>>> obj = myClass()
>>> obj.instance_method()
('Instance method is called', myClass instance at 1x09255d103) 

Это означает, что instance_method может получить доступ к экземпляру объекта (myClass instance) через параметр self. При этом при вызове метода происходит замена параметра self на объект экземпляра obj. Но если передать объект экземпляра вручную, то получится то же самое, что и раньше: 

>>> myClass.instance_method(obj)
('Instance method is called', myClass instance at 1x09255d103) 

Заметим, что self не является зарезервированным ключевым словом в Python. Имя «self» — соглашение.

Что такое self в Python? 

В отличие от переменной this  в C++,  self в Python не является зарезервированным ключевым словом. Эту переменную просто принято называть именно так. Она представляет собой экземпляр или объекты класса и связывает атрибуты класса с определенными аргументами. Использование переменной self в Python позволяет разграничить атрибуты (и методы) экземпляра и локальные переменные. 

Если вы не хотите, чтобы переменные вашего класса были общими для всех его экземпляров, вы можете объявить переменные внутри класса без self. Поясним это на примере: 

class Car: 
    def __init__(self, model): 
        self.model = model 
    def Car_info(self): 
        print("Model : ", self.model) 

Здесь мы объявили класс Car  с одной переменной экземпляра self.model = model. Значение переменной экземпляра будет уникальным для объектов экземпляра класса, которые могут быть объявлены. Однако если вы хотите, чтобы переменные были общими для всех экземпляров класса, то необходимо объявлять переменные экземпляра без self. В противном случае это будет неоднозначно, поскольку все автомобили будут иметь одну и ту же модель. 

Зачем нужна переменная self? 

Переменная self используется для представления экземпляра класса, что часто применяется в объектно-ориентированном программировании. Она работает как ссылка на объект. В Python параметр self используется для обращения к атрибутам и методам экземпляра класса.  

В отличие от других языков программирования, в Python не используется @-синтаксис для доступа к атрибутам экземпляра. Это единственная причина, по которой в Python необходимо использовать переменную self. Язык содержит методы для автоматической передачи экземпляра, но не для его автоматического получения. 

Почему self в Python определяется явно?

В «Дзене Python» говорится: «Явное лучше неявного».  Программисты, работающие с другими языками, часто спрашивают, почему при определении метода self каждый раз явно передается в качестве параметра. На это есть несколько причин. 

Во-первых, поскольку Python использует метод или атрибут экземпляра вместо локальной переменной, когда вы читаете self.name или self.age, это дает понять, что вы используете переменную экземпляра или метод, даже если вы не знаете определения класса. 

Во-вторых, если вы явно ссылаетесь или вызываете метод из конкретного класса в Python, вам не нужно использовать для этого специальный синтаксис.  

В-третьих, явное определение self помогает Python понять, куда присваивать — в переменную экземпляра или в локальную переменную. Проще говоря, локальные переменные и экземпляры существуют в двух разных пространствах имен, и нам необходимо сообщить Python, какое пространство имен следует использовать. 

Использование self в конструкторе класса Python

Переменная self в Python также может использоваться для доступа к полю переменной внутри определения класса. Давайте разберемся в этом на примере кода.

class Student:
    def __init__(self, Alex): 
        self.name = Alex    #name created in constructor 
    def get_student_name(self): 
        return self.name 

В приведенном примере переменная self относится к переменной age  класса Student.  Переменная age  является локальной для метода. Во время работы метода переменная age  существует внутри класса. 

Если внутри метода имеется переменная, то переменная self не будет работать. Если вы хотите определить глобальные поля, то необходимо определять переменные вне методов класса.   

Является ли self ключевым словом в Python? 

Программисты часто задаются вопросом, является ли self ключевым словом в Python.

В отличие от других языков программирования таких, как C++, где self считается ключевым словом, в Python это соглашение, которого обычно придерживаются программисты. По сути, это параметр в определении метода. Однако вместо self для первого параметра метода можно использовать любое другое имя, например another, или me,  или любое другое. Но рекомендуется использовать self, потому что это повышает читабельность кода. 

Для понимания рассмотрим пример: 

class myClass:  
    def show(another):  
        print("another is used in place of self") 

Можно заметить, что здесь вместо self использовано имя another. Теперь создадим объект этого класса и посмотрим на результат: 

object = myClass()
object.show()

Как видите, программа работает, даже если вместо переменной self использовать другое имя.

Почему self следует использовать в качестве первого параметра методов экземпляра?

Это можно понять на следующем примере. У нас есть класс Rectangle, в котором определен метод area для вычисления площади: 

class Rectangle (): 
    def __init__(self,x = 0,y = 0): 
        self.x = x 
        self.y = y 
    def area (self): 
        """Find area of rectangle""" 
        return (self.x * self.y) 

rec1 = Rectangle(6, 10) 
print ("Area is:", rec1.area()) 

# Вывод:
# Area is: 60  

В приведенном примере __init__()  определяет три параметра, но передается только два аргумента — 6 и 10. А вот area()  требует один параметр, но ни один аргумент не передается.  

Rectangle.area и rec1.area  в приведенном примере отличаются: 

>>> type(Rectangle.area ) 
<class 'function'> 
>>> type(rec1.area) 
<class 'method'> 

Здесь первая — это функция, а второй — метод. Уникальная особенность Python заключается в том, что сам объект передается в качестве первого аргумента соответствующей функции. 

В приведенном примере вызов метода rec1.area() эквивалентен Rectangle.area(rec1)

Как правило, при вызове метода с некоторыми аргументами вызывается соответствующая функция класса, помещая объект метода перед первым аргументом. 

Поэтому obj.method(args) становится Class.method(obj, args)

Именно по этой причине первым параметром функции в классе должен быть сам объект. Запись этого параметра как self — это всего лишь соглашение. Можно использовать и другие имена (например, this, that), но это нежелательно, так как ухудшает читаемость кода.

Должны ли мы передавать self в метод?

Что произойдет, если мы просто передадим self в определение метода? Рассмотрим класс myClass, который мы использовали ранее.  

В классе определен метод с именем something  с параметром another  и двумя аргументами: 

class myClass:  
    def something(another, argument1, argument2):  
        pass 

Теперь объявим экземпляр obj  класса myClass и вызовем метод something с помощью объекта экземпляра: 

obj = myClass() 
obj.something(argument1, argument2) 

Python выполняет внутреннюю работу над вызовом метода и преобразует его в нечто подобное: 

myClass.something(obj, argument1, argument2)  

Это показывает, что переменная another (используемая вместо self) ссылается на объект экземпляра класса. 

Обратите внимание, что ключевое слово pass , используемое в методе something, ничего не делает. Оно используется как заглушка в ситуациях, когда не нужно выполнять никаких операций, но синтаксис требует, чтобы был какой-то элемент программирования. 

Как мы можем пропустить self в Python? 

Рассмотрим ситуацию, когда метод экземпляра не должен иметь доступ к переменным экземпляра. В этом случае можно пропустить переменную self при определении методов. Для наглядного понимания этого факта приведем пример кода: 

class Vehicle:
    def Car():
        print("Rolls Royce 1948")

obj = Vehicle()
print("Complete")

# Вывод:
# Complete

Мы не объявили здесь переменную self, но ошибки в программе нет, и вывод получается нормальный. Но что произойдет, если мы вызовем метод Car()?

obj = Vehicle() 
obj.Car() 

Когда мы компилируем код после вызова метода Car(), он выдает ошибку следующего вида: 

Traceback (most recent call last): 
  File "string>", line 11, in module> 
TypeError: Car() takes 0 positional arguments but 1 was given 

В результате выдается ошибка, поскольку метод Car() принимает 0 позиционных аргументов, а мы передали ему 1 позиционный аргумент. Это связано с тем, что при создании экземпляра obj он автоматически передается в качестве первого аргумента в метод Car(), даже если мы не объявили переменную self

Но если попытаться обратиться к методу экземпляра Car()  с помощью ссылки на класс, то ошибок не возникнет и программа будет работать нормально: 

class Vehicle:
    def Car():
        print("Rolls Royce 1948")

obj = Vehicle()
Vehicle.Car()

# Вывод:
# Rolls Royce 1948

Разница между self и __init__  

self представляет собой экземпляр класса. С помощью self можно получить доступ ко всем атрибутам и методам класса Python. 

__init__ — это зарезервированный метод в классах Python. В объектно-ориентированных концепциях он известен как конструктор. Этот метод вызывается при создании объекта из класса и позволяет классу инициализировать атрибуты класса.

Использование self в классе для доступа к методам и атрибутам: 

class Rectangle: 
   def __init__(self, length, breadth, cost_per_unit =0): 
       self.length = length 
       self.breadth = breadth 
       self.cost_per_unit = cost_per_unit 
   def perimeter(self): 
       return 2 * (self.length + self.breadth) 
   def area(self): 
       return self.length * self.breadth 
   def calculate_cost(self): 
       area = self.area() 
       return area * self.cost_per_unit 
# length = 40 cm, breadth = 30 cm and 1 cm^2 = Rs 100 
r = Rectangle(40, 30, 100) 
print("Area of Rectangle:",r.area()) 
print("Cost of rectangular field is : Rs ",r.calculate_cost()) 

Вывод:  

Area of Rectangle: 1200 
Cost of rectangular field is : Rs  120000 

Мы создали объект класса Rectangle. При создании объекта Rectangle мы передали 3 аргумента — 40, 30, 100.  Все эти аргументы передаются в метод __init__ для инициализации объекта. 

Здесь self представляет экземпляр класса. Он связывает атрибуты с заданными аргументами. 

self представляет собой тот же объект или экземпляр класса. Как видите, внутри метода area self.length используется для получения значения атрибута length. Атрибут length привязывается к объекту (экземпляру класса) в момент создания объекта.

self представляет объект внутри класса. Он работает так же, как r в выражении r = Rectangle(40, 30, 100). Если посмотреть на определение метода def area(self):, то здесь в качестве параметра метода используется self, поскольку при вызове метода объект (экземпляр класса) автоматически передается в качестве первого аргумента вместе с другими аргументами метода. Если другие аргументы не указаны, то в метод передается только self. Именно по этой причине self используется для вызова метода внутри класса (self.area()). Для вызова метода вне определения класса(r.area()) мы использовали object (экземпляр класса).  

r — это экземпляр класса при вызове метода r.area(). Экземпляр r передается в качестве первого аргумента вместо self

Различные реализации self в Python

Теперь рассмотрим несколько различных реализаций переменной self

Аналогичные переменные для метода класса и статического метода 

Метод класса — это метод, который привязан к классу. Разберем метод класса на примере: 

class myClass:
    @classmethod
    def classmethod(cls):
        return "Class Method is called"

obj.classmethod()

Переменная self ведет себя аналогично и в методах класса, с той лишь разницей, что для методов класса в качестве имени переменной принято использовать cls, а не self

Методы класса принимают параметр cls вместо параметра self. Когда метод вызывается, он указывает на класс. Метод класса не может изменять состояние объекта, но может изменять состояние класса всех экземпляров класса. 

С другой стороны, статические методы являются самодостаточными функциями. Этот тип методов не принимает ни параметр self, ни параметр cls.

Рассмотрим пример статического метода: 

class myClass:
    @staticmethod
    def staticmethod():
        return "Static Method is called"

obj.staticmethod()

Поскольку статический метод не принимает никаких параметров, он не может изменять состояние объекта или даже класса. В основном они используются для обозначения пространств имен различных методов, и Python ограничивает их в данных, к которым они могут обращаться. 

Обратите внимание, что оба метода здесь помечены декораторами @classmethod  и  @staticmethod, отмечающими их как метод класса и статический метод соответственно. 

Переменная self привязывается к текущему экземпляру 

Переменная self позволяет получить доступ к свойствам текущего экземпляра. Поясним это на примере: 

class Person:
    def __init__(self, n):
        self.name = n

    def walk(self):
        print(f"{self.name} is walking")

obj1 = Person("Alex")
obj2 = Person("Charles")

obj1.walk()
obj2.walk()

# Вывод:
# Alex is walking
# Charles is walking

Здесь у нас есть класс Person  с двумя методами __init__ и walk, объявленными с параметром self. Мы создали два разных экземпляра класса — obj1  и obj2.  При вызыве первого экземпляра выводится «Alex», а при вызыве второго —  «Charles». 

Советы по работе с self в Python 

Поскольку мы подошли к концу статьи, позвольте мне дать вам несколько советов о том, когда следует и когда не следует использовать переменную self в Python. 

Используйте self:

  • При определении метода экземпляра, поскольку он автоматически передается в качестве первого параметра при вызове метода
  • Когда ссылаетесь на класс или атрибут экземпляра внутри метода экземпляра
  • Если хотите ссылаться на переменные и методы экземпляра из других методов экземпляра. 

Не используйте self: 

  • Если хотите вызвать метод экземпляра обычным способом
  • При обращении к атрибуту класса внутри определения класса, но вне метода экземпляра
  • Находясь внутри статического метода

Заключение

Напомним основные моменты, которые мы рассмотрели в этой статье:

  • Классы и экземпляры классов в Python
  • Переменная self и ее значение
  • Явность переменной self
  • self-конструктор класса Python
  • Передача self в качестве метода
  • Пропуск self в Python
  • Переменные, используемые для методов класса и статических методов
  • Привязка self к текущему экземпляру 
  • Когда использовать и когда не использовать self в Python. 

Если же вы хотите узнать больше о self в Python, можете сразу перейти к официальной документации.

Перевод статьи «The Self Variable in Python Explained with Python Examples».