Что такое object в python
Python. Урок 14. Классы и объекты
Данный урок посвящен объектно-ориентированному программированию в Python. Разобраны такие темы как создание объектов и классов, работа с конструктором, наследование и полиморфизм в Python.
Основные понятия объектно-ориентированного программирования
Объектно-ориентированное программирование (ООП) является методологией разработки программного обеспечения, в основе которой лежит понятие класса и объекта, при этом сама программа создается как некоторая совокупность объектов, которые взаимодействую друг с другом и с внешним миром. Каждый объект является экземпляром некоторого класса. Классы образуют иерархии. Более подробно о понятии ООП можно прочитать на википедии.
Выделяют три основных “столпа” ООП- это инкапсуляция, наследование и полиморфизм.
Инкапсуляция
Наследование
Под наследованием понимается возможность создания нового класса на базе существующего. Наследование предполагает наличие отношения “является” между классом наследником и классом родителем. При этом класс потомок будет содержать те же атрибуты и методы, что и базовый класс, но при этом его можно (и нужно) расширять через добавление новых методов и атрибутов.
Примером базового класса, демонстрирующего наследование, можно определить класс “автомобиль”, имеющий атрибуты: масса, мощность двигателя, объем топливного бака и методы: завести и заглушить. У такого класса может быть потомок – “грузовой автомобиль”, он будет содержать те же атрибуты и методы, что и класс “автомобиль”, и дополнительные свойства: количество осей, мощность компрессора и т.п..
Полиморфизм
Полиморфизм позволяет одинаково обращаться с объектами, имеющими однотипный интерфейс, независимо от внутренней реализации объекта. Например, с объектом класса “грузовой автомобиль” можно производить те же операции, что и с объектом класса “автомобиль”, т.к. первый является наследником второго, при этом обратное утверждение неверно (во всяком случае не всегда). Другими словами полиморфизм предполагает разную реализацию методов с одинаковыми именами. Это очень полезно при наследовании, когда в классе наследнике можно переопределить методы класса родителя.
Классы в Python
Создание классов и объектов
Создание класса в Python начинается с инструкции class. Вот так будет выглядеть минимальный класс.
Класс состоит из объявления (инструкция class), имени класса (нашем случае это имя C) и тела класса, которое содержит атрибуты и методы (в нашем минимальном классе есть только одна инструкция pass).
Для того чтобы создать объект класса необходимо воспользоваться следующим синтаксисом:
имя_объекта = имя_класса()
Статические и динамические атрибуты класса
Как уже было сказано выше, класс может содержать атрибуты и методы. Атрибут может быть статическим и динамическим (уровня объекта класса). Суть в том, что для работы со статическим атрибутом, вам не нужно создавать экземпляр класса, а для работы с динамическим – нужно. Пример:
В представленном выше классе, атрибут default_color – это статический атрибут, и доступ к нему, как было сказано выше, можно получить не создавая объект класса Rectangle.
width и height – это динамические атрибуты, при их создании было использовано ключевое слово self. Пока просто примите это как должное, более подробно про self будет рассказано ниже. Для доступа к width и height предварительно нужно создать объект класса Rectangle:
Если обратиться через класс, то получим ошибку:
При этом, если вы обратитесь к статическому атрибуту через экземпляр класса, то все будет ОК, до тех пор, пока вы не попытаетесь его поменять.
Проверим ещё раз значение атрибута default_color:
Присвоим ему новое значение:
Создадим два объекта класса Rectangle и проверим, что default_color у них совпадает:
Если поменять значение default_color через имя класса Rectangle, то все будет ожидаемо: у объектов r1 и r2 это значение изменится, но если поменять его через экземпляр класса, то у экземпляра будет создан атрибут с таким же именем как статический, а доступ к последнему будет потерян:
Меняем default_color через r1:
При этом у r2 остается значение статического атрибута:
Вообще напрямую работать с атрибутами – не очень хорошая идея, лучше для этого использовать свойства.
Методы класса
Добавим к нашему классу метод. Метод – это функция, находящаяся внутри класса и выполняющая определенную работу.
Методы бывают статическими, классовыми (среднее между статическими и обычными) и уровня класса (будем их называть просто словом метод). Статический метод создается с декоратором @staticmethod, классовый – с декоратором @classmethod, первым аргументом в него передается cls, обычный метод создается без специального декоратора, ему первым аргументом передается self:
Статический и классовый метод можно вызвать, не создавая экземпляр класса, для вызова ex_method() нужен объект:
Конструктор класса и инициализация экземпляра класса
В Python разделяют конструктор класса и метод для инициализации экземпляра класса. Конструктор класса это метод __new__(cls, *args, **kwargs) для инициализации экземпляра класса используется метод __init__(self). При этом, как вы могли заметить __new__ – это классовый метод, а __init__ таким не является. Метод __new__ редко переопределяется, чаще используется реализация от базового класса object (см. раздел Наследование), __init__ же наоборот является очень удобным способом задать параметры объекта при его создании.
Создадим реализацию класса Rectangle с измененным конструктором и инициализатором, через который задается ширина и высота прямоугольника:
Что такое self?
До этого момента вы уже успели познакомиться с ключевым словом self. self – это ссылка на текущий экземпляр класса, в таких языках как Java, C# аналогом является ключевое слово this. Через self вы получаете доступ к атрибутам и методам класса внутри него:
В приведенной реализации метод area получает доступ к атрибутам width и height для расчета площади. Если бы в качестве первого параметра не было указано self, то при попытке вызвать area программа была бы остановлена с ошибкой.
Уровни доступа атрибута и метода
Если вы знакомы с языками программирования Java, C#, C++ то, наверное, уже задались вопросом: “а как управлять уровнем доступа?”. В перечисленных языка вы можете явно указать для переменной, что доступ к ней снаружи класса запрещен, это делается с помощью ключевых слов (private, protected и т.д.). В Python таких возможностей нет, и любой может обратиться к атрибутам и методам вашего класса, если возникнет такая необходимость. Это существенный недостаток этого языка, т.к. нарушается один из ключевых принципов ООП – инкапсуляция. Хорошим тоном считается, что для чтения/изменения какого-то атрибута должны использоваться специальные методы, которые называются getter/setter, их можно реализовать, но ничего не помешает изменить атрибут напрямую. При этом есть соглашение, что метод или атрибут, который начинается с нижнего подчеркивания, является скрытым, и снаружи класса трогать его не нужно (хотя сделать это можно).
Внесем соответствующие изменения в класс Rectangle:
В приведенном примере для доступа к _width и _height используются специальные методы, но ничего не мешает вам обратиться к ним (атрибутам) напрямую.
Если же атрибут или метод начинается с двух подчеркиваний, то тут напрямую вы к нему уже не обратитесь (простым образом). Модифицируем наш класс Rectangle:
Попытка обратиться к __width напрямую вызовет ошибку, нужно работать только через get_width():
Но на самом деле это сделать можно, просто этот атрибут теперь для внешнего использования носит название: _Rectangle__width:
Свойства
Свойством называется такой метод класса, работа с которым подобна работе с атрибутом. Для объявления метода свойством необходимо использовать декоратор @property.
Важным преимуществом работы через свойства является то, что вы можете осуществлять проверку входных значений, перед тем как присвоить их атрибутам.
Сделаем реализацию класса Rectangle с использованием свойств:
Теперь работать с width и height можно так, как будто они являются атрибутами:
Можно не только читать, но и задавать новые значения свойствам:
Если вы обратили внимание: в setter’ах этих свойств осуществляется проверка входных значений, если значение меньше нуля, то будет выброшено исключение ValueError:
Наследование
В организации наследования участвуют как минимум два класса: класс родитель и класс потомок. При этом возможно множественное наследование, в этом случае у класса потомка может быть несколько родителей. Не все языки программирования поддерживают множественное наследование, но в Python можно его использовать. По умолчанию все классы в Python являются наследниками от object, явно этот факт указывать не нужно.
Синтаксически создание класса с указанием его родителя выглядит так:
class имя_класса(имя_родителя1, [имя_родителя2,…, имя_родителя_n])
Переработаем наш пример так, чтобы в нем присутствовало наследование:
Родительским классом является Figure, который при инициализации принимает цвет фигуры и предоставляет его через свойства. Rectangle – класс наследник от Figure. Обратите внимание на его метод __init__: в нем первым делом вызывается конструктор (хотя это не совсем верно, но будем говорить так) его родительского класса:
super – это ключевое слово, которое используется для обращения к родительскому классу.
Теперь у объекта класса Rectangle помимо уже знакомых свойств width и height появилось свойство color:
Полиморфизм
Как уже было сказано во введении в рамках ООП полиморфизм, как правило, используется с позиции переопределения методов базового класса в классе наследнике. Проще всего это рассмотреть на примере. Добавим в наш базовый класс метод info(), который печатает сводную информацию по объекту класса Figure и переопределим этот метод в классе Rectangle, добавим в него дополнительные данные:
Посмотрим, как это работает
Таким образом, класс наследник может расширять функционал класса родителя.
P.S.
Если вам интересна тема анализа данных, то мы рекомендуем ознакомиться с библиотекой Pandas. На нашем сайте вы можете найти вводные уроки по этой теме. Все уроки по библиотеке Pandas собраны в книге “Pandas. Работа с данными”.
Python. Урок 14. Классы и объекты : 18 комментариев
А вот если Вы добавите вот это
.entry-title a:last-child <
float:right;
>
в свой css будет намного удобнее, нежели вы будите использовать 2-ную табуляцию в HTML. Спасибо.
Класс, о методе super() вообще ни слова
Спасибо за замечание! Добавим!
Про self ничего не сказано. Похоже на ссылку на текущий обьект.
Да, это действительно ссылка на текущий объект. Нужно будет вообще этот урок переработать, в нем плохо раскрыты многие вопросы! Спасибо за комментарий!
О методе __new__(cls) тоже нет ни слова, а он так же участвует в конструировании экземпляра класса.
ОК, спасибо! Добавим!
Наконец-то всё стало понятно. Огромное спасибо за разъяснение на уровне 1 класса 2 четверти!
Определение инкапсуляции неверное. Приведенное определение скорее присуще самому понятию “класс”. А инкапсуляция – это сокрытие деталей реализации.
> Атрибут может быть статическим и не статическим (уровня объекта класса)
В других языках принято “не статические атрибуты” называть динамическими. Предлагаю использовать, чтобы язык не ломать 🙂
Пытаюсь разобраться с декораторами.
@property
def width(self):
return self.__width
@width.setter
def width(self, w):
if w > 0:
self.__width = w
else:
raise ValueError
Понял назначение методов уровня Класс. Но не понятно назначение классовых и статических методов (@classmethod, @staticmethod)
Столкнулся с проблемой
есть класс
class Users(): #класс списка пользователей
def __init__(self):
self.item=[]
self.num=0
есть класс пользователя
class Aduser(): #класс пользователь домена
def __init__(self):
self.fio=”” # ФИО
self.login=”” # login
self.email=”” # e-mail
self.list=[] # принадлежность к спискам
self.spec=”” # должность
self.dept=”” # отдел
self.stage=True # состояние активности учетной записи
self.desc=”” # примечание
usrs = Users()
usr = Aduser()
…
не мону понять почему не срабатывает конструкция
usrs.item.append[usr]
точнее срабатывает но в usrs.item[] приходит пустой объект Adusers()
Ссылки на предыдущие уроки не нашел, причем тут декораторы и вообще, что это (хотя бы ссылкой) тоже не нашел.
Работаю с питоном уже больше года. Долго пытался понять что такое @property и @setter, А тут автор за 10 строчек объяснил, браво!
Класно описано. Только вот про сеттеры ни слова объяснения, из кода приходится догадыватся.
Продвинутый Python, часть 3: классы и метаклассы
Это завершающая статья цикла «Продвинутый Python», в которой пойдёт речь о классах и метаклассах. В первой части мы познакомились с итераторами, генераторами и модулем itertools, а во второй говорили о замыканиях, декораторах и модуле functools.
Классы как объекты
Посмотрите пример кода, чтобы ближе познакомиться с описанными особенностями.
В некоторых языках, таких как C++, классы можно объявлять только на верхнем уровне модулей. В Python class можно использовать внутри функции. Этот подход можно использовать, чтобы создавать классы на лету. Ниже пример:
Метаклассы
Обратите внимание, второй параметр должен быть кортежем, поэтому синтаксис может выглядеть странно. Если вам нужны методы, создавайте функции и передавайте их как атрибуты. Вот пример:
Можно создавать свои метаклассы: сгодится любой вызываемый (callable) объект, который способен принять три параметра и вернуть объект класса. Такие метаклассы можно применять к классу. Метакласс можно указать при объявлении класса. Давайте рассмотрим этот приём на примере, который заодно продемонстрирует возможности метаклассов:
Как видите, у декораторов и метаклассов есть много общего. Фактически, метаклассы умеют всё, что можно сделать с помощью декоратора класса. Синтаксис декораторов более простой и читабельный, поэтому по возможности следует использовать именно их. Метаклассы умеют больше, так как они запускаются перед созданием класса, а не после, как декораторы. Чтобы убедиться в этом, давайте создадим декоратор и метакласс и посмотрим на порядок исполнения.
Изучайте Python на Хекслете Первые курсы в профессии «Python-программист» доступны бесплатно. Регистрируйтесь и начинайте учиться!
Пример использования метаклассов
Рассмотрим более полезное приложение. Предположим, мы пишем набор классов для обработки ID3v2 тегов, которые используются, например, в MP3-файлах. Подробности можно узнать в «Википедии». Для реализации примера надо понимать, что теги состоят из фреймов. Каждый фрейм содержит четырёхбуквенный идентификатор. Например, TOPE — фрейм имени артиста, TOAL — фрейм названия альбома и так далее. Предположим, нам надо написать класс для каждого типа фреймов. Также нужно дать возможность пользователям библиотеки ID3v2 тегов добавлять собственные классы фреймов для поддержки новых или кастомных фреймов. С помощью метаклассов можно реализовать паттерн «фабрика классов». Это может выглядеть так:
Конечно, задачу можно решить с помощью декораторов классов. Для сравнения посмотрите, как это может выглядеть.
Как видите, можно передавать параметры в декораторы, но не в метаклассы. Если нужно передать параметры в метаклассы, это нужно делать через атрибуты. Поэтому код с декораторами чище и проще в поддержке. Заметьте, что ко времени вызова декоратора класс уже создан. Это значит, что уже поздно менять его свойства, предназначенные только для чтения.
Метаклассы, полученные из type
Подводим итоги
Посмотрим, как Python интерпретирует код выше. Затем посмотрим на вывод, чтобы подтвердить или опровергнуть наши предположения.
Метаклассы на практике
ABCMeta — это метакласс, позволяющий создавать абстрактные базовые классы. Детали смотрите в официальной документации.
Идея djungoplugins основана на статье, в которой описывается простой фреймворк плагинов для Python. Здесь метаклассы используются для создания системы расширений. Автор оригинальной публикации считает, что такой же фреймворк можно создать с помощью декораторов.
Финальный аккорд
Понимание метаклассов помогает досконально разобраться, как ведут себя объекты и классы в Python. Но применение самих метаклассов в реальности может быть сложным, как показано в предыдущем разделе. Практически всё, что можно сделать с помощью метаклассов, можно реализовать и с помощью декораторов. Поэтому прежде чем использовать метаклассы, остановитесь на минуту и подумайте, так ли они необходимы. Если можно обойтись без них, лучше пойти по этому пути. Результат будет более читабельным и простым для поддержки и отладки.
Над адаптированным переводом статьи A Study of Python’s More Advanced Features Part III: Classes and Metaclasses by Sahand Saba работали Алексей Пирогов и Дмитрий Дементий. Мнение автора оригинальной публикации может не совпадать с мнением администрации «Хекслета».
Классы и объекты в Python
Классы и объекты в Python являются основными строительными блоками языка программирования Python.
Классы в Python
Как было бы, если бы вы могли объявить тип данных, который сам содержит более одного типа данных и может работать с ними с помощью любой функции? Класс в Python дает вам такую возможность.
Класс Python – это план, по которому создаются экземпляры класса.
Определение класса
Вот самая базовая структура определения класса Python.
Теперь поработаем с реальными примерами.
Этот пример не требует пояснений. Как мы знаем, строки, начинающиеся с символа «#», представляют собой комментарии в Python. Они объясняют исполняемые шаги, а код дает следующий результат.
Определение класса в Python:
Эта строка отмечает начало определения класса для класса «Person».
Переменные класса
«name» и «age» – две переменные-члены класса «Person». Каждый раз, когда мы объявляем объект этого класса, он будет содержать эти две переменные в качестве своих членов. Эта часть не является обязательной, так как они могут быть инициализированы конструктором.
Конструктор классов
Конструктор класса в Python – это первый фрагмент кода, который должен выполняться при создании нового объекта класса.
Прежде всего, конструктор можно использовать для помещения значений в переменные-члены. Вы также можете распечатать сообщения в конструкторе, чтобы убедиться, что объект был создан.
Метод конструктора начинается с def __init__. После этого первым параметром должно быть значение «self», так как он передает ссылку на экземпляр самого класса. Вы также можете добавить дополнительные параметры, как показано в примере. «personName» и «personAge» – это два параметра, которые необходимо отправить, когда должен быть создан новый объект.
Методы класса
Методы объявляются следующим образом:
В предустановленном примере мы видели, что метод showName() печатает значение «name» этого объекта.
Создание объектов
Создание объектов в Python довольно простое. Сначала вы указываете имя нового объекта, за которым следует оператор присваивания и имя класса с параметрами (как определено в конструкторе).
Помните, что количество и тип параметров должны быть совместимы с параметрами, полученными в функции-конструкторе.
Когда объект создан, могут быть вызваны методы-члены и доступны атрибуты-члены (при условии, что они доступны).
9. ClassesВ¶
Classes provide a means of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances of that type to be made. Each class instance can have attributes attached to it for maintaining its state. Class instances can also have methods (defined by its class) for modifying its state.
Compared with other programming languages, Python’s class mechanism adds classes with a minimum of new syntax and semantics. It is a mixture of the class mechanisms found in C++ and Modula-3. Python classes provide all the standard features of Object Oriented Programming: the class inheritance mechanism allows multiple base classes, a derived class can override any methods of its base class or classes, and a method can call the method of a base class with the same name. Objects can contain arbitrary amounts and kinds of data. As is true for modules, classes partake of the dynamic nature of Python: they are created at runtime, and can be modified further after creation.
In C++ terminology, normally class members (including the data members) are public (except see below Private Variables ), and all member functions are virtual. As in Modula-3, there are no shorthands for referencing the object’s members from its methods: the method function is declared with an explicit first argument representing the object, which is provided implicitly by the call. As in Smalltalk, classes themselves are objects. This provides semantics for importing and renaming. Unlike C++ and Modula-3, built-in types can be used as base classes for extension by the user. Also, like in C++, most built-in operators with special syntax (arithmetic operators, subscripting etc.) can be redefined for class instances.
(Lacking universally accepted terminology to talk about classes, I will make occasional use of Smalltalk and C++ terms. I would use Modula-3 terms, since its object-oriented semantics are closer to those of Python than C++, but I expect that few readers have heard of it.)
9.1. A Word About Names and ObjectsВ¶
Objects have individuality, and multiple names (in multiple scopes) can be bound to the same object. This is known as aliasing in other languages. This is usually not appreciated on a first glance at Python, and can be safely ignored when dealing with immutable basic types (numbers, strings, tuples). However, aliasing has a possibly surprising effect on the semantics of Python code involving mutable objects such as lists, dictionaries, and most other types. This is usually used to the benefit of the program, since aliases behave like pointers in some respects. For example, passing an object is cheap since only a pointer is passed by the implementation; and if a function modifies an object passed as an argument, the caller will see the change — this eliminates the need for two different argument passing mechanisms as in Pascal.
9.2. Python Scopes and NamespacesВ¶
Before introducing classes, I first have to tell you something about Python’s scope rules. Class definitions play some neat tricks with namespaces, and you need to know how scopes and namespaces work to fully understand what’s going on. Incidentally, knowledge about this subject is useful for any advanced Python programmer.
Let’s begin with some definitions.
The local namespace for a function is created when the function is called, and deleted when the function returns or raises an exception that is not handled within the function. (Actually, forgetting would be a better way to describe what actually happens.) Of course, recursive invocations each have their own local namespace.
A scope is a textual region of a Python program where a namespace is directly accessible. “Directly accessible” here means that an unqualified reference to a name attempts to find the name in the namespace.
Although scopes are determined statically, they are used dynamically. At any time during execution, there are 3 or 4 nested scopes whose namespaces are directly accessible:
the innermost scope, which is searched first, contains the local names
the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names
the next-to-last scope contains the current module’s global names
the outermost scope (searched last) is the namespace containing built-in names
If a name is declared global, then all references and assignments go directly to the middle scope containing the module’s global names. To rebind variables found outside of the innermost scope, the nonlocal statement can be used; if not declared nonlocal, those variables are read-only (an attempt to write to such a variable will simply create a new local variable in the innermost scope, leaving the identically named outer variable unchanged).
Usually, the local scope references the local names of the (textually) current function. Outside functions, the local scope references the same namespace as the global scope: the module’s namespace. Class definitions place yet another namespace in the local scope.
It is important to realize that scopes are determined textually: the global scope of a function defined in a module is that module’s namespace, no matter from where or by what alias the function is called. On the other hand, the actual search for names is done dynamically, at run time — however, the language definition is evolving towards static name resolution, at “compile” time, so don’t rely on dynamic name resolution! (In fact, local variables are already determined statically.)
A special quirk of Python is that – if no global or nonlocal statement is in effect – assignments to names always go into the innermost scope. Assignments do not copy data — they just bind names to objects. The same is true for deletions: the statement del x removes the binding of x from the namespace referenced by the local scope. In fact, all operations that introduce new names use the local scope: in particular, import statements and function definitions bind the module or function name in the local scope.
The global statement can be used to indicate that particular variables live in the global scope and should be rebound there; the nonlocal statement indicates that particular variables live in an enclosing scope and should be rebound there.
9.2.1. Scopes and Namespaces ExampleВ¶
This is an example demonstrating how to reference the different scopes and namespaces, and how global and nonlocal affect variable binding:
The output of the example code is:
Note how the local assignment (which is default) didn’t change scope_test‘s binding of spam. The nonlocal assignment changed scope_test‘s binding of spam, and the global assignment changed the module-level binding.
You can also see that there was no previous binding for spam before the global assignment.
9.3. A First Look at ClassesВ¶
Classes introduce a little bit of new syntax, three new object types, and some new semantics.
9.3.1. Class Definition SyntaxВ¶
The simplest form of class definition looks like this:
Class definitions, like function definitions ( def statements) must be executed before they have any effect. (You could conceivably place a class definition in a branch of an if statement, or inside a function.)
In practice, the statements inside a class definition will usually be function definitions, but other statements are allowed, and sometimes useful — we’ll come back to this later. The function definitions inside a class normally have a peculiar form of argument list, dictated by the calling conventions for methods — again, this is explained later.
When a class definition is entered, a new namespace is created, and used as the local scope — thus, all assignments to local variables go into this new namespace. In particular, function definitions bind the name of the new function here.
When a class definition is left normally (via the end), a class object is created. This is basically a wrapper around the contents of the namespace created by the class definition; we’ll learn more about class objects in the next section. The original local scope (the one in effect just before the class definition was entered) is reinstated, and the class object is bound here to the class name given in the class definition header ( ClassName in the example).
9.3.2. Class ObjectsВ¶
Class objects support two kinds of operations: attribute references and instantiation.
Class instantiation uses function notation. Just pretend that the class object is a parameterless function that returns a new instance of the class. For example (assuming the above class):
When a class defines an __init__() method, class instantiation automatically invokes __init__() for the newly-created class instance. So in this example, a new, initialized instance can be obtained by:
9.3.3. Instance ObjectsВ¶
Now what can we do with instance objects? The only operations understood by instance objects are attribute references. There are two kinds of valid attribute names: data attributes and methods.
The other kind of instance attribute reference is a method. A method is a function that “belongs to” an object. (In Python, the term method is not unique to class instances: other object types can have methods as well. For example, list objects have methods called append, insert, remove, sort, and so on. However, in the following discussion, we’ll use the term method exclusively to mean methods of class instance objects, unless explicitly stated otherwise.)
Valid method names of an instance object depend on its class. By definition, all attributes of a class that are function objects define corresponding methods of its instances. So in our example, x.f is a valid method reference, since MyClass.f is a function, but x.i is not, since MyClass.i is not. But x.f is not the same thing as MyClass.f — it is a method object, not a function object.
9.3.4. Method ObjectsВ¶
Usually, a method is called right after it is bound:
will continue to print hello world until the end of time.
What exactly happens when a method is called? You may have noticed that x.f() was called without an argument above, even though the function definition for f() specified an argument. What happened to the argument? Surely Python raises an exception when a function that requires an argument is called without any — even if the argument isn’t actually used…
If you still don’t understand how methods work, a look at the implementation can perhaps clarify matters. When a non-data attribute of an instance is referenced, the instance’s class is searched. If the name denotes a valid class attribute that is a function object, a method object is created by packing (pointers to) the instance object and the function object just found together in an abstract object: this is the method object. When the method object is called with an argument list, a new argument list is constructed from the instance object and the argument list, and the function object is called with this new argument list.
9.3.5. Class and Instance VariablesВ¶
Generally speaking, instance variables are for data unique to each instance and class variables are for attributes and methods shared by all instances of the class:
Correct design of the class should use an instance variable instead: