Метод объекта/экземпляра класса в Python
Методы — это функции, вызываемые с использованием точечной нотации. Если обратится к методу (функции, определенной в пространстве имен класса) через экземпляр, то получим специальный объект: объект привязанного метода (также называемого методом экземпляра). При вызове он добавляет аргумент self в список аргументов.
Обычно метод вызывается сразу после его привязки:
class MyClass: """Простой пример класса""" i = 12345 def f(self): return 'hello world' x = MyClass() x.f() # 'hello world'
В примере с классом MyClass метод экземпляра класса x.f() возвращает строку «hello world». Нет необходимости вызывать метод сразу, x.f — это объект метода класса и его можно сохранить и вызвать позже. В примере ниже — бесконечный цикл, который будет продолжать печатать «hello world».
xf = x.f while True: print(xf())
Что именно происходит при вызове метода? Заметили, что x.f() был вызван без аргумента? Хотя в определение функции f() был указан один аргумент self . Python всегда вызывает исключение, когда функция, требующая аргумента, вызывается без него, даже если аргумент фактически не используется…
Особенность методов заключается в том, что объект экземпляра передается в качестве первого аргумента self функции. В примере вызов x.f() в точности эквивалентен вызову MyClass.f(x) . В общем случае вызов метода со списком из n аргументов эквивалентен вызову соответствующей функции со списком аргументов, который создается путем вставки объекта экземпляра метода перед первым аргументом.
При ссылке на атрибут экземпляра, не являющийся атрибутом данных, выполняется поиск экземпляра класса. Если имя обозначает допустимый атрибут класса, который является объектом функции, объект метода создается путем упаковки указателей объекта экземпляра и объекта функции, только что найденных вместе в абстрактном объекте: это объект метода. Когда объект метода вызывается со списком аргументов, новый список аргументов создается из экземпляра класса и списка аргументов этого класса, а объект функции вызывается с этим новым списком аргументов.
Первый аргумент метода называется self . Это не более чем соглашение: имя self не имеет абсолютно никакого особого значения для Python. Обратите внимание, что не следуя соглашению, ваш код может быть менее читаемым для других программистов Python и также может быть написана некая программа для просмотра классов, которая будет основываться на этом соглашении.
Любой функциональный объект, являющийся атрибутом класса, определяет метод для экземпляров этого класса. Нет необходимости в том, чтобы определение функции было текстуально заключено в определение класса: присвоение объекта функции локальной переменной в классе также нормально.
# Функция, определенная вне класса def f1(self, x, y): return min(x, x+y) class C: f = f1 def g(self): return 'hello world' h = g
Обратите внимание, что эта практика обычно только запутывает читателя программы. Теперь f , g и h — это все атрибуты класса C , которые относятся к функциональным объектам, и, следовательно, все они являются методами экземпляров класса C . Метод h точно эквивалентны g .
Методы могут вызывать другие методы, используя атрибуты метода собственного аргумента:
class Bag: def __init__(self): self.data = [] def add(self, x): self.data.append(x) def addtwice(self, x): self.add(x) self.add(x)
Методы могут ссылаться на глобальные имена так же, как обычные функции. Глобальной областью видимости, связанной с методом, является модуль, содержащий его определение. Класс никогда не используется в качестве глобальной области видимости. Хотя редко встречаются веские причины для использования глобальных данных в методе, существует много законных вариантов использования глобальной области видимости. Функции и модули, импортированные в глобальную область, могут использоваться методами, а также функциями и классами, определенными в нем. Обычно класс, содержащий метод, сам определяется в этой глобальной области видимости.
Поддержка получения произвольных атрибутов методами.
Связанные методы имеют два специальных атрибута, доступных только для чтения: m.__ self__ — это объект, с которым работает метод, и m.__func__ — это функция, реализующая метод. Вызов m(arg-1, arg-2, . arg-n) полностью эквивалентен вызову m.__func__(m.__self__, arg-1, arg-2, . arg-n) .
Как и объекты функций, связанные объекты методов поддерживают получение произвольных атрибутов. Однако, поскольку атрибуты метода фактически хранятся в базовом объекте функции ( meth.__func__ ), то установка атрибутов метода для связанных методов запрещена. Попытка установить атрибут в методе приводит к возникновению исключения AttributeError . Чтобы установить атрибут метода, необходимо явно установить его для базового объекта функции:
>>> class C: . def method(self): . pass . >>> c = C() >>> c.method.whoami = 'my name is method' # can't set on the method # Traceback (most recent call last): # File "", line 1, in # AttributeError: 'method' object has no attribute 'whoami' >>> c.method.__func__.whoami = 'my name is method' >>> c.method.whoami # 'my name is method'
- ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
- Пространство имен и область видимости в классах
- Определение классов
- Объект класса и конструктор класса
- Создание экземпляра класса
- Метод экземпляра класса
- Что такое метод класса и зачем нужен
- Что такое статический метод в классах Python и зачем нужен
- Атрибуты класса и переменные экземпляра класса
- Кэширование методов экземпляра декоратором lru_cache
- Закрытые/приватные методы и переменные класса Python
- Наследование классов
- Множественное наследование классов
- Абстрактные классы
- Перегрузка методов в классе Python
- Что такое миксины и как их использовать
- Класс Python как структура данных, подобная языку C
- Создание пользовательских типов данных
- Специальные (магические) методы класса Python
- Базовая настройка классов Python магическими методами
- Настройка доступа к атрибутам класса Python
- Дескриптор класса для чайников
- Протокол дескриптора класса
- Практический пример дескриптора
- Использование метода .__new__() в классах Python
- Специальный атрибут __slots__ класса Python
- Специальный метод __init_subclass__ класса Python
- Определение метаклассов metaclass
- Эмуляция контейнерных типов в классах Python
- Другие специальные методы класса
- Как Python ищет специальные методы в классах
- Шаблон проектирования Фабрика и его реализация
Python: Методы как выражения
Методы — такие же выражения, как переменные или вызовы функции, значит, их можно по-разному комбинировать.
Например, использовать в операциях:
name = 'Shaya' 'hi, ' + name.upper() + '!' # hi, SHAYA!
Или использовать в параметрах функций:
name = 'robb' print(name.lower()) # => robb num1 = 5 num2 = 30 # bit_length() — вычисляет количество бит, необходимых для представления числа в двоичном виде print(num1.bit_length() + num2.bit_length()) # => 8
Задание
Найдите символы N и , (запятая) внутри текста в переменной text . Выведите на экран их индексы. Ожидаемый тестами вывод:
Index Of N: 0 Index Of ,: 25
Ваша задача найти эти индексы в строке с помощью метода .find() и вставить в print() , не используя промежуточные переменные. Это упражнение можно решить как при помощи интерполяции, так и при помощи конкатенации. Если вы используете конкатенацию, то полученный результат необходимо привести к строковому типу. Для разбиения вывода на две строки, вам может понадобится \n .
Упражнение не проходит проверку — что делать?
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
- Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Мой код отличается от решения учителя
Это нормально , в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Прочитал урок — ничего не понятно
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Определения
- Метод — это функция или процедура, принадлежащая какому-то классу или объекту.
Чем метод отличается от функции в Python?
В отличие от функции, метод узко специализирован и может быть применен только к объектам, которые его поддерживают. Например, метод списков append() может быть применен только к ним. Применение данного метода к другим объектам, которые его не поддерживают (строки или кортежи) вызовет ошибку. Но есть и такие методы, которые хорошо работают с несколькими типами объектов, например метод count() может применяться к строкам, спискам или кортежам
13 февраля 2023
Метод по сути это та же функция, но так как она определена внутри класса, и первым её аргументом является self , то она становится связанным методом bound method , получившим доступ к атрибутам связанного объекта (экземпляра класса).
# Обычная функция: def greet(name): print(f'Hello, name>') class Person: # Инициализатор класса, требующий присваивать значение атрибута name при инстанцировании объекта def __init__(self, name): self.name = name # Связанный метод, имеющий доступ к атрибуту name: def greet(self): print(f'Hello , self.name>. ') bob = Person('Bob') # Вызов связанного метода класса: bob.greet() # => Hello , Bob. # Вызов функции, не имеющий доступа к атрибутам объекта: greet(bob) # => Hello, # Вызов обычной функции, которой можно передать любое значение: greet('Bob') # => Hello, Bob greet(23) # => Hello, 23 greet('apple') # => Hello, apple
Что такое метод класса в Python и зачем нужен
Альтернативный конструктор (несколько конструкторов) класса в Python
Сразу начнем с примера простого класса, который содержит обычный метод и метод класса:
class MyClass: def method(self): return 'instance method called', self @classmethod def classmethod(cls): return 'class method called', cls
Как работают методы класса в Python?
В Python, методы класса отмечаются декоратором @classmethod , следовательно в приведенном выше примере, метод класса будет определен в функции classmethod() .
Как можно заметить, метод класса вместо того, чтобы принимать аргумент self , принимает аргумент cls . При вызове метода этот аргумент указывает на сам класс, а не на экземпляр класса.
Поскольку метод класса имеет доступ только к аргументу cls , он не может изменять состояние экземпляра объекта. Для этого потребуется доступ к аргументу self . НО все же методы класса могут изменять состояние класса, которое применяется ко всем экземплярам класса.
MyClass() настроен таким образом, что реализация каждого метода возвращает кортеж для отслеживания, что происходит, и к каким частям класса или объекта метод может получить доступ.
Вот что происходит, когда мы вызываем метод экземпляра:
>>> obj = MyClass() >>> obj.method() # ('instance method called', ) # Можно передать объект `obj` экземпляра вручную, # для получения того же результата >>> MyClass.method(obj) # ('instance method called', )
Этот кусок кода подтвердил, что метод экземпляра класса имеет доступ к экземпляру объекта, напечатанному как через аргумент self .
Кстати, методы экземпляра также могут получить доступ к самому классу через атрибут self.__class__ . Это делает методы экземпляра мощными с точки зрения ограничений доступа — они могут изменять состояние как экземпляра объекта, так и самого класса.
Попробуем вызвать метод класса:
>>> obj.classmethod() # ('class method called', )
Вызов метода класса obj.classmethod() показал, что он не имеет доступа к объекту , а только к объекту , представляющему сам класс (в Python все является объектом, даже сами классы).
Обратите внимание, как Python автоматически передает класс в качестве первого аргумента функции, когда вызывается MyClass.classmethod() . Вызов метода в Python через точечную нотацию запускает это поведение. Параметр self в методах экземпляра работает точно так же.
Теперь посмотрим, что происходит, когда попытаться вызвать эти методы в самом классе — без предварительного создания экземпляра объекта:
>>> MyClass.classmethod() # ('class method called', ) >>> MyClass.method() # Traceback (most recent call last): # File "", line 1, in # TypeError: method() missing 1 required positional argument: 'self'
Из примера видно, что можно нормально вызвать метод класса MyClass.classmethod() , но попытка вызвать метод экземпляра MyClass.method() завершилась ошибкой TypeError . Этого следовало ожидать, ведь экземпляр объекта не создан, что означает, что Python не может заполнить аргумент self и следовательно, вызов не выполняется.
Для чего нужны методы класса в Python?
Следующие примеры кода должны сделать понимание метода класса более ясным. Далее рассмотрим пример класса, имеющего дело с информацией о дате (это будет шаблон):
class Date: def __init__(self, day=0, month=0, year=0): self.day = day self.month = month self.year = year def string_to_db(self): return f'self.year>-self.month>-self.day>'
Этот класс, очевидно, можно использовать для хранения информации об определенных датах, без информации о часовом поясе (предположим, что все даты представлены в формате UTC).
Здесь есть конструктор __init__ , типичный инициализатор экземпляров классов Python, который получает аргументы как типичный метод экземпляра, имея первый необязательный аргумент self , который содержит ссылку на вновь созданный экземпляр.
Например есть несколько задач, которые можно решить при помощи будущих методов этого класса, не только определенного для примера метода, банального перевода числовых значений в формат строки с датой для баз данных.
Предположим, что мы хотим создать много экземпляров класса Date() с информацией о дате, поступающей из внешнего источника, в виде строки с форматом dd.mm.yyyy . Предположим, нужно сделать это в разных местах исходного кода проекта.
Итак, что для этого необходимо сделать:
- Выполнить синтаксический анализ строки, получить день, месяц и год как три целочисленные переменные или кортеж из трех элементов, включающий эти переменные.
- Создать экземпляр Date , передав эти значения в конструктор класса при его создании.
Это будет выглядеть так:
>>> string_date = '10.10.2020' >>> day, month, year = map(int, string_date.split('.')) >>> date = Date(day, month, year) >>> date.string_to_db() # '2020-10-10'
Для выполнения этой задачи, например C++ или Java может реализовать такую возможность с перегрузкой метода __init__ , но в Python перегрузка методов отсутствует. Вместо нее необходимо использовать метод класса (декоратор @classmethod).
Создадим еще один «конструктор».
class Date(object): def __init__(self, day=0, month=0, year=0): self.day = day self.month = month self.year = year @classmethod def from_string(cls, date_as_string): day, month, year = map(int, date_as_string.split('.')) date1 = cls(day, month, year) return date1 def string_to_db(self): return f'self.year>-self.month>-self.day>'
Более подробно о перегрузке смотрите в материале «Перегрузка методов в Python».
Обратите внимание, как используется аргумент cls в методе класса from_string() вместо прямого вызова конструктора класса Date() .
Теперь создать новый экземпляр Date , так же, можно следующим образом:
>>> date1 = Date.from_string('30.12.2020') >>> date1.string_to_db() # '2020-12-30' >>> date2 = Date.from_string('01.01.2021') >>> date2.string_to_db() # '2021-1-1'
Рассмотрим приведенную выше реализацию чтобы понять, какие преимущества здесь есть:
- Реализован синтаксический анализ строки даты в одном месте, и теперь его можно использовать повторно.
- Инкапсуляция здесь отлично работает. Если вы думаете, что можете реализовать синтаксический анализ строк как единственную функцию в другом месте, это решение намного лучше соответствует парадигме ООП.
- cls — это объект, который содержит сам класс, а не его экземпляр. Это довольно круто, потому что, если мы наследуем класс Date , для всех дочерних элементов также будет определен метод класса from_string() .
Используя методы класса, можно добавить столько альтернативных конструкторов, сколько необходимо. Такое поведение может сделать интерфейс создаваемых классов самодокументированным (до определенной степени конечно) и упростить их использование.
- ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
- Пространство имен и область видимости в классах
- Определение классов
- Объект класса и конструктор класса
- Создание экземпляра класса
- Метод экземпляра класса
- Что такое метод класса и зачем нужен
- Что такое статический метод в классах Python и зачем нужен
- Атрибуты класса и переменные экземпляра класса
- Кэширование методов экземпляра декоратором lru_cache
- Закрытые/приватные методы и переменные класса Python
- Наследование классов
- Множественное наследование классов
- Абстрактные классы
- Перегрузка методов в классе Python
- Что такое миксины и как их использовать
- Класс Python как структура данных, подобная языку C
- Создание пользовательских типов данных
- Специальные (магические) методы класса Python
- Базовая настройка классов Python магическими методами
- Настройка доступа к атрибутам класса Python
- Дескриптор класса для чайников
- Протокол дескриптора класса
- Практический пример дескриптора
- Использование метода .__new__() в классах Python
- Специальный атрибут __slots__ класса Python
- Специальный метод __init_subclass__ класса Python
- Определение метаклассов metaclass
- Эмуляция контейнерных типов в классах Python
- Другие специальные методы класса
- Как Python ищет специальные методы в классах
- Шаблон проектирования Фабрика и его реализация