Объектно-ориентированное программирование
Python имеет множество встроенных типов, например, int, str и так далее, которые мы можем использовать в программе. Но также Python позволяет определять собственные типы с помощью классов . Класс представляет некоторую сущность. Конкретным воплощением класса является объект.
Можно еще провести следующую аналогию. У нас у всех есть некоторое представление о человеке, у которого есть имя, возраст, какие-то другие характеристики Человек может выполнять некоторые действия — ходить, бегать, думать и т.д. То есть это представление, которое включает набор характеристик и действий, можно назвать классом. Конкретное воплощение этого шаблона может отличаться, например, одни люди имеют одно имя, другие — другое имя. И реально существующий человек будет представлять объект этого класса.
Класс определяется с помощью ключевого слова class :
class название_класса: атрибуты_класса методы_класса
Внутри класса определяются его атрибуты, которые хранят различные характеристики класса, и методы — функции класса.
Создадим простейший класс:
class Person: pass
В данном случае определен класс Person, который условно представляет человека. В данном случае в классе не определяется никаких методов или атрибутов. Однако поскольку в нем должно быть что-то определено, то в качестве заменителя функционала класса применяется оператор pass . Этот оператор применяется, когда синтаксически необходимо определить некоторый код, однако мы не хотим его, и вместо конкретного кода вставляем оператор pass.
После создания класса можно определить объекты этого класса. Например:
class Person: pass tom = Person() # определение объекта tom bob = Person() # определение объекта bob
После определения класса Person создаются два объекта класса Person — tom и bob. Для создания объекта применяется специальная функция — конструктор , которая называется по имени класса и которая возвращает объект класса. То есть в данном случае вызов Person() представляет вызов конструктора. Каждый класс по умолчанию имеет конструктор без параметров:
tom = Person() # Person() - вызов конструктора, который возвращает объект класса Person
Методы классов
Методы класса фактически представляют функции, которые определенны внутри класса и которые определяют его поведение. Например, определим класс Person с одним методом:
class Person: # определение класса Person def say_hello(self): print("Hello") tom = Person() tom.say_hello() # Hello
Здесь определен метод say_hello() , который условно выполняет приветствие — выводит строку на консоль. При определении методов любого класса следует учитывать, что все они должны принимать в качестве первого параметра ссылку на текущий объект, который согласно условностям называется self . Через эту ссылку внутри класса мы можем обратиться к функциональности текущего объекта. Но при самом вызове метода этот параметр не учитывается.
Используя имя объекта, мы можем обратиться к его методам. Для обращения к методам применяется нотация точки — после имени объекта ставится точка и после нее идет вызов метода:
объект.метод([параметры метода])
Например, обращение к методу say_hello() для вывода приветствия на консоль:
tom.say_hello() # Hello
В итоге данная программа выведет на консоль строку «Hello».
Если метод должен принимать другие параметры, то они определяются после параметра self , и при вызове подобного метода для них необходимо передать значения:
class Person: # определение класса Person def say(self, message): # метод print(message) tom = Person() tom.say("Hello METANIT.COM") # Hello METANIT.COM
Здесь определен метод say() . Он принимает два параметра: self и message. И для второго параметра — message при вызове метода необходимо передать значение.
self
Через ключевое слово self можно обращаться внутри класса к функциональности текущего объекта:
self.атрибут # обращение к атрибуту self.метод # обращение к методу
Например, определим два метода в классе Person:
class Person: def say(self, message): print(message) def say_hello(self): self.say("Hello work") # обращаемся к выше определенному методу say tom = Person() tom.say_hello() # Hello work
Здесь в одном методе — say_hello() вызывается другой метод — say() :
self.say("Hello work")
Поскольку метод say() принимает кроме self еще параметры (параметр message), то при вызове метода для этого параметра передается значение.
Причем при вызове метода объекта нам обязательно необходимо использовать слово self , если мы его не используем:
def say_hello(self): say("Hello work") # ! Ошибка
То мы столкнемся с ошибкой
Конструкторы
Для создания объекта класса используется конструктор. Так, выше когда мы создавали объекты класса Person, мы использовали конструктор по умолчанию, который не принимает параметров и который неявно имеют все классы:
tom = Person()
Однако мы можем явным образом определить в классах конструктор с помощью специального метода, который называется __init__() (по два прочерка с каждой стороны). К примеру, изменим класс Person, добавив в него конструктор:
class Person: # конструктор def __init__(self): print("Создание объекта Person") def say_hello(self): print("Hello") tom = Person() # Создание объекта Person tom.say_hello() # Hello
Итак, здесь в коде класса Person определен конструктор и метод say_hello() . В качестве первого параметра конструктор, как и методы, также принимает ссылку на текущий объект — self. Обычно конструкторы применяются для определения действий, которые должны производиться при создании объекта.
Теперь при создании объекта:
tom = Person()
будет производится вызов конструктора __init__() из класса Person, который выведет на консоль строку «Создание объекта Person».
Атрибуты объекта
Атрибуты хранят состояние объекта. Для определения и установки атрибутов внутри класса можно применять слово self . Например, определим следующий класс Person:
class Person: def __init__(self, name): self.name = name # имя человека self.age = 1 # возраст человека tom = Person("Tom") # обращение к атрибутам # получение значений print(tom.name) # Tom print(tom.age) # 1 # изменение значения tom.age = 37 print(tom.age) # 37
Теперь конструктор класса Person принимает еще один параметр — name. Через этот параметр в конструктор будет передаваться имя создаваемого человека.
Внутри конструктора устанавливаются два атрибута — name и age (условно имя и возраст человека):
def __init__(self, name): self.name = name self.age = 1
Атрибуту self.name присваивается значение переменной name. Атрибут age получает значение 1.
Если мы определили в классе конструктор __init__, мы уже не сможем вызвать конструктор по умолчанию. Теперь нам надо вызывать наш явным образом опреледеленный конструктор __init__, в который необходимо передать значение для параметра name:
tom = Person("Tom")
Далее по имени объекта мы можем обращаться к атрибутам объекта — получать и изменять их значения:
print(tom.name) # получение значения атрибута name tom.age = 37 # изменение значения атрибута age
В принципе нам необязательно определять атрибуты внутри класса — Python позволяет сделать это динамически вне кода:
class Person: def __init__(self, name): self.name = name # имя человека self.age = 1 # возраст человека tom = Person("Tom") tom.company = "Microsoft" print(tom.company) # Microsoft
Здесь динамически устанавливается атрибут company, который хранит место работы человека. И после установки мы также можем получить его значение. В то же время подобное определение чревато ошибками. Например, если мы попытаемся обратиться к атрибуту до его определения, то программа сгенерирует ошибку:
tom = Person("Tom") print(tom.company) # ! Ошибка - AttributeError: Person object has no attribute company
Для обращения к атрибутам объекта внутри класса в его методах также применяется слово self:
class Person: def __init__(self, name): self.name = name # имя человека self.age = 1 # возраст человека def display_info(self): print(f"Name: Age: ") tom = Person("Tom") tom.display_info() # Name: Tom Age: 1
Здесь определяется метод display_info(), который выводит информацию на консоль. И для обращения в методе к атрибутам объекта применяется слово self: self.name и self.age
Создание объектов
Выше создавался один объект. Но подобным образом можно создавать и другие объекты класса:
class Person: def __init__(self, name): self.name = name # имя человека self.age = 1 # возраст человека def display_info(self): print(f"Name: Age: ") tom = Person("Tom") tom.age = 37 tom.display_info() # Name: Tom Age: 37 bob = Person("Bob") bob.age = 41 bob.display_info() # Name: Bob Age: 41
Здесь создаются два объекта класса Person: tom и bob. Они соответствуют определению класса Person, имеют одинаковый набор атрибутов и методов, однако их состояние будет отличаться.
При выполнении программы Python динамически будет определять self — он представляет объект, у которого вызывается метод. Например, в строке:
tom.display_info() # Name: Tom Age: 37
Это будет объект tom
bob.display_info()
Это будет объект bob
В итоге мы получим следующий консольный вывод:
Name: Tom Age: 37 Name: Bob Age: 41
Как вывести все объекты класса python
Начиная с 3-й версии в языке программирования Python все классы неявно имеют один общий суперкласс — object и все классы по умолчанию наследуют его методы.
Одним из наиболее используемых методов класса object является метод __str__() . Когда необходимо получить строковое представление объекта или вывести объект в виде строки, то Python как раз вызывает этот метод. И при определении класса хорошей практикой считается переопределение этого метода.
К примеру, возьмем класс Person и выведем его строковое представление:
class Person: def __init__(self, name, age): self.name = name # устанавливаем имя self.age = age # устанавливаем возраст def display_info(self): print(f"Name: Age: ") tom = Person("Tom", 23) print(tom)
При запуске программа выведет что-то наподобие следующего:
Это не очень информативная информация об объекте. Мы, конечно, можем выйти из положения, определив в классе Person дополнительный метод, который выводит данные объекта — в примере выше это метод display_info.
Но есть и другой выход — определим в классе Person метод __str__() (по два подчеркивания с каждой стороны):
class Person: def __init__(self, name, age): self.name = name # устанавливаем имя self.age = age # устанавливаем возраст def display_info(self): print(self) # print(self.__str__()) # или так def __str__(self): return f"Name: Age: " tom = Person("Tom", 23) print(tom) # Name: Tom Age: 23 tom.display_info() # Name: Tom Age: 23
Метод __str__ должен возвращать строку. И в данном случае мы возвращаем базовую информацию о человеке. Если нам потребуется использовать эту информацию в других методах класса, то мы можем использовать выражение self.__str__()
И теперь консольный вывод будет другим:
Name: Tom Age: 23 Name: Tom Age: 23
Встроенная функция для вывода всех текущих свойств и значений объекта в Python
Одна из обычных проблем, с которой сталкиваются новички в программировании на Python, это отслеживание состояния объектов в процессе выполнения скрипта.
Алексей Кодов
Автор статьи
7 июля 2023 в 17:40
Одна из обычных проблем, с которой сталкиваются новички в программировании на Python, это отслеживание состояния объектов в процессе выполнения скрипта. Например, есть некий объект, и требуется узнать, какие у него сейчас свойства и какие значения этих свойств.
class MyClass: def __init__(self, value1, value2): self.property1 = value1 self.property2 = value2 my_object = MyClass(10, 20)
В данном случае хотелось бы вывести на экран все свойства объекта my_object и их значения.
В языке программирования Python нет встроенной функции, аналогичной функции print_r в PHP, однако есть несколько способов, которые могут помочь в решении этой задачи.
Использование функции vars
Функция vars в Python возвращает словарь, который содержит атрибуты данного объекта.
print(vars(my_object))
Результат выполнения этого кода может выглядеть следующим образом:
Использование функции dir
Функция dir в Python возвращает список имен атрибутов объекта.
print(dir(my_object))
Однако, функция dir возвращает все атрибуты, включая служебные методы класса, что может быть избыточно. Но с ее помощью можно получить список всех атрибутов объекта, а затем получить их значения.
for attribute_name in dir(my_object): attribute_value = getattr(my_object, attribute_name) print(f': ')
Использование модуля pprint
Если объект содержит сложную структуру, то его может быть сложно отображать с помощью обычного print . В этом случае на помощь приходит модуль pprint (pretty-print), который предоставляет возможности для более красивого вывода данных.
import pprint pprint.pprint(vars(my_object))
Важно помнить, что эти функции могут не всегда работать с некоторыми типами объектов, например, встроенными типами данных, такими как списки или словари.
Можно ли получить все существующие объекты класса через класс? [дубликат]
У меня есть класс Cluster и несколько его экземпляров. В каждом экземпляре класса Cluster есть поле elements, которое представляет собой список координат элементов кластера. Я хочу описать статический метод, который бы получал координаты элемента и возвращал объект кластера, к которому он относится, а для этого мне нужно получить доступ ко всем созданным над данный момент объектам класса. Вопрос: как это сделать? Вот упрощенный код класса кластера:
class Cluster: def __init__(self, x, y, label): self.elements = [] # Список координат элементов кластера # Метод добавления элемента в кластер def add_element(self, x, y): self.elements.append((x, y)) # Метод проверки наличия элемента в кластере def have_element(self, x, y): return (x, y) in self.elements # Метод поиска кластера элемента @staticmethod def find_element_cluster(x, y): pass # Что тут надо писать?
А вот результат, которого я хочу добиться:
element = 4, 6 cluster = Cluster.find_element_cluster(element[0], element[1]) # Теперь в переменной cluster хранится объект кластера, который имеет элемент element