Если вы работали с Python, то, возможно, сталкивались с переменной self
. Ее можно встретить в определениях методов и при инициализации переменных. В этой статье мы познакомим вас с self
поближе.
Друзья, подписывайтесь на наш телеграм канал Pythonist. Там еще больше туториалов, задач и книг по 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» — соглашение.
В отличие от переменной 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
используется для представления экземпляра класса, что часто применяется в объектно-ориентированном программировании. Она работает как ссылка на объект. В Python параметр self
используется для обращения к атрибутам и методам экземпляра класса.
В отличие от других языков программирования, в Python не используется @
-синтаксис для доступа к атрибутам экземпляра. Это единственная причина, по которой в Python необходимо использовать переменную self
. Язык содержит методы для автоматической передачи экземпляра, но не для его автоматического получения.
В «Дзене Python» говорится: «Явное лучше неявного». Программисты, работающие с другими языками, часто спрашивают, почему при определении метода self
каждый раз явно передается в качестве параметра. На это есть несколько причин.
Во-первых, поскольку Python использует метод или атрибут экземпляра вместо локальной переменной, когда вы читаете self.name
или self.age
, это дает понять, что вы используете переменную экземпляра или метод, даже если вы не знаете определения класса.
Во-вторых, если вы явно ссылаетесь или вызываете метод из конкретного класса в Python, вам не нужно использовать для этого специальный синтаксис.
В-третьих, явное определение self
помогает Python понять, куда присваивать — в переменную экземпляра или в локальную переменную. Проще говоря, локальные переменные и экземпляры существуют в двух разных пространствах имен, и нам необходимо сообщить 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.
В отличие от других языков программирования таких, как 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
использовать другое имя.
Это можно понять на следующем примере. У нас есть класс 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
в определение метода? Рассмотрим класс 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
при определении методов. Для наглядного понимания этого факта приведем пример кода:
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
представляет собой экземпляр класса. С помощью 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
.
Метод класса — это метод, который привязан к классу. Разберем метод класса на примере:
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
позволяет получить доступ к свойствам текущего экземпляра. Поясним это на примере:
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
и ее значениеself
self
-конструктор класса Pythonself
в качестве методаself
в Pythonself
к текущему экземпляру self
в Python. Если же вы хотите узнать больше о self
в Python, можете сразу перейти к официальной документации.
Перевод статьи «The Self Variable in Python Explained with Python Examples».
Управление памятью - важный, но часто упускаемый из виду аспект программирования. При неправильном подходе оно…
Как возникает круговой импорт? Эта ошибка импорта обычно возникает, когда два или более модуля, зависящих…
Вы когда-нибудь оказывались в ситуации, когда скрипт на Python выполняется очень долго и вы задаетесь…
В этом руководстве мы разберем все, что нужно знать о символах перехода на новую строку…
Блок if __name__ == "__main__" в Python позволяет определить код, который будет выполняться только при…
Давайте разберем, как настроить модульные тесты для экземпляров классов. Мы напишем тесты для проверки функциональности…