Базовые методы перегрузки
В следующей таблице перечислены некоторые общие функции, которые вы можете переопределить в своих собственных классах.
Sr.No. | Метод, описание и пример вызова |
---|---|
1 |
__init__ (self )
Конструктор (с любыми необязательными аргументами) Пример вызова: obj = className (args) |
2 |
__del __ (самостоятельно)
Деструктор, удаляет объект Образец звонка: del obj |
3 |
__repr __ (самостоятельно)
Оцениваемое строковое представление Пример вызова: repr (obj) |
4 |
__str __ (самостоятельно)
Печатное представление строки Пример вызова: str (obj) |
5 |
__cmp__ (self, x)
Сравнение объектов Пример вызова: cmp (obj, x) |
Обработка ошибок в python
Если во время выполнения программы что-то идет не так, интерпретатор python генерирует объект исключения одного из стандартных классов, в зависимости от того, что именно произошло. Все эти стандартные классы содержатся в модуле exception, который не требует дополнительного подключения.
Возникновение таких исключений может быть перехвачено в коде программы с помощью конструкции:
try: # действия, которые могут вызвать ошибку except ExceptionClass: # действия, которые должны быть выполнены в случае ошибки
Вместо ExceptionClass указывается название конкретного класса исключений, которые должны перехватываться. Исключение других классах не будут перехвачены в случае их появления. Самый простой способ определить необходимый класс исключение — это воссоздать необходимую ошибку и посмотреть название класса ее исключения в стандартном сообщении интерпретатора:
x = int(raw_input('input number:'))
В нашем примере — это ValueError.
Если необходимо перехватывать одновременно несколько классов исключений, они перечисляются в тьюпле:
x = None while not x: try: x = int(raw_input('input number:')) except (TypeError, ValueError): print 'error happened. try once more' print 'finally!'
Различные исключения могут иметь различные поля с данными, но общим для всех является поле message, в котором хранится текстовое сообщение, описывает ошибку. Для получения подробных сведений об ошибке перехвачено исключения можно сохранить как переменную:
x = None while not x: try: x = int(raw_input('input number:')) except (TypeError, ValueError) as e: print 'error { %s } happened. try once more' % (e.message) print 'finally!'
Стандартные исключения наследуются друг от друга, образуя сложную иерархию. Указывая в except исключения родительских классов, вы отлавливаете также дочерние для них исключения:
x = None while not x: try: x = int(raw_input('input number:')) except StandardError as e: print 'error { %s } happened. try once more' % (e.message) print 'finally!'
Как это работает? При возникновении ошибки работа текущей функции прекращается и генерируется объект исключения, который передается из функции, где возникла ошибка, на уровень выше — в функцию, которая ее вызвала, также прекращая ее работу, потом еще на уровень выше, и так далее до тела главной программы. Если на этом пути исключения не было перехвачено (ни одна из этих функций не находилась внутри блока try..except), работа всей программы будет таким образом остановлена и на экран будет выведено стандартное сообщение об ошибке с указанием точки в коде, где ошибка произошла.
Полная иерархия стандартных исключений выглядит следующим образом:
Какие компании используют Python
В основном Python используется стартапами и компаниями, которые разрабатывают крупные проекты. Вот лишь часть огромного списка:
- Alphabet использует язык для скраппинга в поисковике Google и реализации сервиса YouTube;
- One Laptop Per Child — для разработки интерфейса и модели функционирования;
- BitTorrent — для реализации сетей peer-to-peer;
- Агентство национальной безопасности США — для шифрования и анализа разведданных;
- ESRI — как инструмент настройки геоинформационных программ;
- Maya — для создания мультипликации;
- Pixar, Industrial Light & Magic — для создания анимационных фильмов;
- Intel, Cisco, HP, Seagate, Qualcomm и IBM — для тестирования;
- JPMorgan Chase, UBS, Getco и Citadel — для прогнозирования финансового рынка;
- NASA, Los Alamos, Fermilab, JPL — для научных вычислений;
- iRobot — для разработки коммерческих роботизированных устройств;
- IronPort — для реализации почтового сервера.
Конструктор класса и инициализация экземпляра класса
В Python разделяют конструктор класса и метод для инициализации экземпляра класса. Конструктор класса это метод __new__(cls, *args, **kwargs) для инициализации экземпляра класса используется метод __init__(self). При этом, как вы могли заметить __new__ – это классовый метод, а __init__ таким не является. Метод __new__ редко переопределяется, чаще используется реализация от базового класса object (см. раздел Наследование), __init__ же наоборот является очень удобным способом задать параметры объекта при его создании.
Создадим реализацию класса Rectangle с измененным конструктором и инициализатором, через который задается ширина и высота прямоугольника:
class Rectangle: def __new__(cls, *args, **kwargs): print("Hello from __new__") return super().__new__(cls) def __init__(self, width, height): print("Hello from __init__") self.width = width self.height = height >>> rect = Rectangle(10, 20) Hello from __new__ Hello from __init__ >>> rect.width 10 >>> rect.height 20
Статические и динамические атрибуты
Вот вы говорите конструктор, инициализатор… А что, если я объявлю и инициализирую атрибут вне метода ?
class Bird: ruClassName = "Птица" def __init__(self, name): self.name = name
И такое тоже практикуют. И такие атрибуты даже имеют свое название и применение:
b = Bird("Я объект b, класса " + Bird.ruClassName) print(b.name)
Атрибут называется статическим. А атрибут — динамическим. Заметьте, что внутри класса к статическим атрибутам мы не обращаемся через . Вне класса мы обращаемся к статическим атрибутам не через <имя объекта> с точкой, а через <Имя класса> с точкой. То же самое, кстати, требуется делать со статическим атрибутом и внутри методов класса! Иначе работать не будет.
Статические атрибуты применяются для того, чтобы иметь одну общую переменную для всех объектов класса.
Дело в том, что при создании новых объектов создаются копии всех динамических атрибутов со сброшенными к «заводским настройкам» значениями. Статические атрибуты относятся не к объекту, а к классу и имеют только одну копию.
В примере выше статический атрибут просто хранит название класса. В примере поинтереснее статический атрибут может служить для подсчета количества созданных объектов класса:
class Bird: ruClassName = "Птица" objInstancesCount = 0 def __init__(self, name): self.name = name Bird.objInstancesCount = Bird.objInstancesCount + 1 b = Bird("объект №1 класса " + Bird.ruClassName) print(b.name) b2 = Bird("объект №2 класса " + Bird.ruClassName) print(b2.name) print("Количество объектов класса " + Bird.ruClassName + ": " + str(Bird.objInstancesCount))
Результат работы:
объект №1 класса Птица объект №2 класса Птица Количество объектов класса Птица: 2
4 ответа
Заключенный в кавычки из http://www.geekinterview.com/question_details/64739:
Основным преимуществом является организация. Что-либо, что может быть выполнено с внутренними классами, может быть выполнено без них.
ответ дан 2 revs 24 November 2019 в 08:01
Нет. Они абсолютно эквивалентны определению класса обычно на верхнем уровне и затем копировании ссылки на него во внешний класс.
Я не думаю, что существуют вложенные классы любой особой причины, ‘позволяются’, кроме него не имеет никакого конкретного смысла явно ‘запрещать’ им также.
При поиске класса, который существует в течение жизненного цикла внешнего объектного / объектного владельца, и всегда имеет ссылку на экземпляр внешнего класса — inner классы, поскольку Java делает это – затем, вложенные классы Python не являются той вещью. Но можно изрубить что-то как эта вещь:
(Это использует декораторов класса, которые являются новыми в Python 2.6 и 3.0. Иначе необходимо было бы сказать “Внутренний = innerclass (Внутренний)” после определения класса.)
ответ дан 3 revs 24 November 2019 в 08:01
Существует что-то, что необходимо перенести голову, чтобы смочь понять это. На большинстве языков определения классов являются директивами к компилятору. Таким образом, класс создается, прежде чем программа когда-либо запускается. В Python все операторы являются исполняемым файлом. Это означает что этот оператор:
оператор, который выполняется во времени выполнения точно так же, как этот:
Это означает, что мало того, что можно создать классы в других классах, можно создать классы где угодно, Вы хотите. Рассмотрите этот код:
Таким образом идея «внутреннего класса» не является действительно конструкцией языка; это — конструкция программиста. У Guido есть очень хорошая сводка того, как это появилось здесь. Но по существу, основная идея, это упрощает грамматику языка.
ответ дан Jason Baker 24 November 2019 в 08:01
Вложенные классы в классах:
-
Вложенные классы чрезмерно увеличивают размер определения класса, мешающего видеть то, что продолжается.
-
Вложенные классы могут создать связь, которая сделала бы тестирование более трудным.
-
В Python можно поместить больше чем один класс в файл/модуль, в отличие от Java, таким образом, класс все еще остается рядом с высокоуровневым классом и мог даже снабдить префиксом имя класса «_», чтобы помочь показать, что другие не должны использовать его.
Место, где вложенные классы могут оказаться полезными, в функциях
Класс получает значения от функции, разрешающей Вам динамично создать класс как шаблонное метапрограммирование в C++
ответ дан 2 revs 24 November 2019 в 08:01
Другие вопросы по тегам:
Создание классов и объектов
Создание класса в Python начинается с инструкции class. Вот так будет выглядеть минимальный класс.
class C: pass
Класс состоит из объявления (инструкция class), имени класса (нашем случае это имя C) и тела класса, которое содержит атрибуты и методы (в нашем минимальном классе есть только одна инструкция pass).
Для того чтобы создать объект класса необходимо воспользоваться следующим синтаксисом:
имя_объекта = имя_класса()
Статические и динамические атрибуты класса
Как уже было сказано выше, класс может содержать атрибуты и методы. Атрибут может быть статическим и динамическим (уровня объекта класса). Суть в том, что для работы со статическим атрибутом, вам не нужно создавать экземпляр класса, а для работы с динамическим – нужно. Пример:
class Rectangle: default_color = "green" def __init__(self, width, height): self.width = width self.height = height
В представленном выше классе, атрибут default_color – это статический атрибут, и доступ к нему, как было сказано выше, можно получить не создавая объект класса Rectangle.
>>> Rectangle.default_color 'green'
width и height – это динамические атрибуты, при их создании было использовано ключевое слово self. Пока просто примите это как должное, более подробно про self будет рассказано ниже. Для доступа к width и height предварительно нужно создать объект класса Rectangle:
>>> rect = Rectangle(10, 20) >>> rect.width 10 >>> rect.height 20
Если обратиться через класс, то получим ошибку:
>>> Rectangle.width Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: type object 'Rectangle' has no attribute 'width'
При этом, если вы обратитесь к статическому атрибуту через экземпляр класса, то все будет ОК, до тех пор, пока вы не попытаетесь его поменять.
Проверим ещё раз значение атрибута default_color:
>>> Rectangle.default_color 'green'
Присвоим ему новое значение:
>>> Rectangle.default_color = "red" >>> Rectangle.default_color 'red'
Создадим два объекта класса Rectangle и проверим, что default_color у них совпадает:
>>> r1 = Rectangle(1,2) >>> r2 = Rectangle(10, 20) >>> r1.default_color 'red' >>> r2.default_color 'red'
Если поменять значение default_color через имя класса Rectangle, то все будет ожидаемо: у объектов r1 и r2 это значение изменится, но если поменять его через экземпляр класса, то у экземпляра будет создан атрибут с таким же именем как статический, а доступ к последнему будет потерян:
Меняем default_color через r1:
>>> r1.default_color = "blue" >>> r1.default_color 'blue'
При этом у r2 остается значение статического атрибута:
>>> r2.default_color 'red' >>> Rectangle.default_color 'red'
Вообще напрямую работать с атрибутами – не очень хорошая идея, лучше для этого использовать свойства.
Методы класса
Добавим к нашему классу метод. Метод – это функция, находящаяся внутри класса и выполняющая определенную работу.
Методы бывают статическими, классовыми (среднее между статическими и обычными) и уровня класса (будем их называть просто словом метод). Статический метод создается с декоратором @staticmethod, классовый – с декоратором @classmethod, первым аргументом в него передается cls, обычный метод создается без специального декоратора, ему первым аргументом передается self:
class MyClass: @staticmethod def ex_static_method(): print("static method") @classmethod def ex_class_method(cls): print("class method") def ex_method(self): print("method")
Статический и классовый метод можно вызвать, не создавая экземпляр класса, для вызова ex_method() нужен объект:
>>> MyClass.ex_static_method() static method >>> MyClass.ex_class_method() class method >>> MyClass.ex_method() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: ex_method() missing 1 required positional argument: 'self' >>> m = MyClass() >>> m.ex_method() method
9.4. Различные замечания¶
Если одно и то же имя атрибута встречается как в экземпляре, так и в
классе, то поиск атрибута выполняется сначала в экземпляре:
>>> class Warehouse purpose = 'storage' region = 'west' >>> w1 = Warehouse() >>> print(w1.purpose, w1.region) storage west >>> w2 = Warehouse() >>> w2.region = 'east' >>> print(w2.purpose, w2.region) storage east
Методы могут ссылаться на атрибуты-данные также как и обычные пользователи
(«клиенты») объекта. Другими словами, классы не подходят для разработки
чистых абстрактных типов данных. Фактически же в Python нет ничего, вынуждающего
вас скрывать данные: сокрытие основано на соглашении между программистами.
(С другой стороны, реализация Python, написанная на C, может полностью скрывать
детали разработки и, если нужно, контролировать доступ к объекту, это можно делать
в расширениях для Python, написанных на C.)
Клиенты должны использовать атрибуты-данные с осторожностью, т. к
иначе
они могут нарушить инварианты, подразумеваемые методами класса при использовании
атрибутов-данных. Заметьте, что обычно клиенты могут добавлять собственные
атрибуты-данные к объектам-экземплярам, не нарушая работы методов,
если не происходит конфликтов имён. Опять же, соглашение об именовании может
избавить вас от головной боли и в этих случаях.
Нет стенографии для ссылок на атрибуты данных (или другими методами!) из внутри
методов. Я нахожу, что это действительно повышает читабельность методов:
нет возможности спутать локальные переменные и переменные экземпляров
при просмотре метода.
Обычно, первый аргумент метода называется . Это не более чем соглашение:
имя не имеет абсолютно никакого особого значения для Python
Однако
обратите внимание на то, что без соблюдения конвенции ваш код может быть менее
читаемым для других программистов Python, и также возможно, что
программа навигации по классам может быть написана на основе такой конвенции
Любой объект-функция, являющийся атрибутом класса, определяет метод для экземпляров
этого класса
Не так важно, чтобы текст определения функции был заключён в определение
класса: присваивание объекта-функции локальной переменной класса также
работает неплохо. Например:
# Функция, определенная вне класса def f1(self, x, y): return min(x, x+y) class C f = f1 def g(self): return 'hello world' 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)
Методы могут ссылаться на глобальные имена таким же образом, как и обычные функции.
Глобальная область видимости, связанная с методом — это модуль, содержащий определение
класса. (Сам класс никогда не используется в качестве глобальной области видимости.) В то
время, как одни редко находят причины для использования глобальных данных в методах,
существует множество разумных причин использовать глобальную область видимости: для
примера, функции и модули, импортированные в глобальную область видимости, могут
использоваться в методах так же, как в функциях и классах, в ней определённых.
Обычно класс, содержащий метод, сам определён в этой глобальной области видимости,
и в следующем разделе мы найдём пару хороших причин, почему методу может быть
необходимо ссылаться на собственный класс.
Где используется Python
Python широко распространен во многих сферах: от системного администрирования до Data Science.
Системное администрирование
Системным администраторам Python нужен для автоматизации задач. Он простой, мощный и поддерживает специальные пакеты, которые повышают его эффективность. И, самое главное, он по умолчанию установлен на все серверы с ОС Linux.
Благодаря лаконичности Python можно быстро прочитать код и найти слабые места. Форматирование в языке — часть синтаксиса.
Научные исследования
В Python есть несколько библиотек, которые пригодятся для проведения исследований и вычислений:
- SciPy — библиотека с научными инструментами;
- NumPy — расширение, которое добавляет поддержку матриц и многомерных массивов, а также математические функции для работы с ними;
- Matplotlib — библиотека для работы с 2D- и 3D-графикой.
Благодаря библиотекам и простоте освоения языка многие учёные выбирают Python — особенно он популярен у математиков и физиков.
Data Science
Python — один из самых используемых в Data Science языков. На нём пишут алгоритмы программ с машинным обучением и аналитические приложения. С помощью него обслуживают хранилища данных и облачные сервисы.
Класс как шаблон для создания объектов
На самом деле классы – не модули. Они своего рода шаблоны, от которых создаются объекты-экземпляры. Такие объекты наследуют от класса его атрибуты. Вернемся к нашему классу B и создадим на его основе два объекта:
>>> class B: ... n = 5 ... def adder(v): ... return v + B.n ... >>> a = B() >>> b = B()
У объектов, связанных с переменными a и b, нет собственного поля n. Однако они наследуют его от своего класса:
>>> a.n 5 >>> a.n is B.n True
То есть поля и – это одно и то же поле, к которому можно обращаться и через имя a, и через имя b, и через имя класса. Поле одно, ссылок на него три.
Однако что произойдет в момент присваивания этому полю значения через какой-нибудь объект-экземпляр?
>>> a.n = 10 >>> a.n 10 >>> b.n 5 >>> B.n 5
В этот момент у экземпляра появляется собственный атрибут n, который перекроет (переопределит) родительский, то есть тот, который достался от класса.
>>> a.n is B.n False >>> b.n is B.n True
При этом присвоение через отразится только на b и B, но не на a:
>>> B.n = 100 >>> B.n, b.n, a.n (100, 100, 10)
Иная ситуация нас ожидает с атрибутом adder. При создании объекта от класса функция adder не наследуется как есть, а как бы превращается для объекта в одноименный метод:
>>> B.adder is b.adder False >>> type(B.adder) <class 'function'> >>> type(b.adder) <class 'method'>
Через имя класса мы вызываем функцию adder:
>>> B.adder(33) 133
Через имя объекта вызываем метод adder:
>>> b.adder(33) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: adder() takes 1 positional argument but 2 were given
В сообщении об ошибке говорится, что adder принимает только один аргумент, а было передано два. Откуда появился второй, если в скобках было указано только одно число?
Дело в том, что в отличии от функции в метод первым аргументом всегда передается объект, к которому применяется этот метод. То есть выражение как бы преобразовывается в . Сам же как объект типа method хранит сведения, с каким классом он связан и какому объекту-экземпляру принадлежит:
>>> b.adder <bound method B.adder of <__main__.B object at 0x7fcbf1ab9b80>>
В нашем случае, чтобы вызывать adder через объекты-экземпляры, класс можно переписать так:
>>> class B: ... n = 5 ... def adder(obj, v): ... return v + obj.n ... >>> b = B() >>> b.adder(33) 38
В коде выше при вызове метода adder переменной-параметру obj присваивается объект, связанный с переменной, к которой применяется данный метод. В данном случае это объект, связанный с b. Если adder будет вызван на другой объект, то уже он присвоится obj:
>>> a = B() >>> a.n = 9 >>> a.adder(3) 12
В Python принято переменную-параметр метода, которая связывается с экземпляром своего класса, называть именем self. Таким образом, более корректный код будет таким:
>>> class B: ... n = 5 ... def adder(self, v): ... return v + self.n
Можем ли мы все также вызывать adder как функцию, через имя класса? Вполне. Только теперь в функцию надо передавать два аргумента:
>>> B.adder(B, 200) 205 >>> B.adder(a, 200) 209
Здесь первым аргументом в функцию передается объект, у которого есть поле n лишь только потому, что далее к этому полю обращаются через выражение .
Однако если атрибут определен так, что предполагается его работа в качестве метода, а не функции, то через класс его уже не вызывают (нет смысла, логика программы этого не подразумевает).
С другой стороны, в ООП есть понятие «статический метод». По сути это функция, которая может вызываться и через класс, и через объект, и которой первым аргументом не подставляется объект, на который она вызывается. В Python статический метод можно создать посредством использования специального декоратора.
Создание Вложенных Классов В Python
В этом разделе мы в первую очередь сосредоточимся на создании вложенных классов. Для этого давайте рассмотрим пример.
class language: def __init__(self): .specification() def show(self): print("Language:", self.language) class specification: def __init__(self): def display(self): print("type:", self.type) print("Founded:", self.founded) () out.show() .lg ppool.display()
Language: PYTHON type: HIGH-LEVEL Founded: 1991
Здесь выше мы успешно создали вложенный класс . Теперь давайте пройдемся строчка за строчкой и поймем, что мы это сделали. Итак, сначала мы создали класс с именем language. Внутри него мы использовали ключевое слово self. Ключевое слово self-это ключ, через который мы можем получить доступ к атрибутам и методам aнашего созданного класса. Внутри класса language мы создали еще один вложенный класс под названием specification. Там мы точно так же определили спецификации. Наконец, мы получаем желаемый результат.
Наследование классов
Вместо того, чтобы начинать с нуля, вы можете создать класс, выведя его из ранее существовавшего класса, перечислив родительский класс в скобках после имени нового класса.
Дочерний класс наследует атрибуты своего родительского класса, и вы можете использовать эти атрибуты, как если бы они были определены в дочернем классе. Дочерний класс также может переопределять элементы данных и методы родительского класса.
Синтаксис
Производные классы объявляются так же, как их родительский класс; однако список базовых классов для наследования дается после имени класса
class SubClassName (ParentClass1): 'Optional class documentation string' class_suite
Пример
#!/usr/bin/python class Parent: # define parent class parentAttr = 100 def __init__(self): print "Calling parent constructor" def parentMethod(self): print 'Calling parent method' def setAttr(self, attr): Parent.parentAttr = attr def getAttr(self): print "Parent attribute :", Parent.parentAttr class Child(Parent): # define child class def __init__(self): print "Calling child constructor" def childMethod(self): print 'Calling child method' c = Child() # instance of child c.childMethod() # child calls its method c.parentMethod() # calls parent's method c.setAttr(200) # again call parent's method c.getAttr() # again call parent's method
Когда приведенный выше код выполняется, он дает следующий результат
Calling child constructor Calling child method Calling parent method Parent attribute : 200
Аналогичным образом вы можете управлять классом из нескольких родительских классов следующим образом:
class A: # define your class A ..... class B: # define your class B ..... class C(A, B): # subclass of A and B .....
Вы можете использовать функции issubclass () или isinstance (), чтобы проверить отношения двух классов и экземпляров.
- Issubclass ( к югу, вир) функция булева возвращает истину , если данный подкласс суб действительно подкласс суперкласса вир .
- Isinstance (объект, класс) Функция булева возвращает истину , если OBJ является экземпляром класса Class или является экземпляром подкласса класса
Краткий обзор ооп python
Программа/скрипт/код, написанные с использованием парадигмы объектно-ориентированного программирования, должны состоять из
- объектов,
- классов (описания объектов),
- взаимодействий объектов между собой, в результате которых меняются их свойства.
Что такое класс в ооп python?
Класс — это тип данных, состоящий из набора атрибутов (свойств) и методов — функций для работы с этими атрибутами.
Схематично класс можно представить следующим образом:
Для создания классов предусмотрена инструкция class. Тело класса состоит из блока различных инструкций.
class ИмяКласса: ПеременнаяКласса = Значение … def ИмяМетода(self, ...): self.ПеременнаяКласса = Значение … …
Методы в классах — это те же функции, которые принимают один обязательный параметр — self (с англ. можно перевести как «собственная личность»). Он нужен для связи с конкретным объектом.
Атрибуты класса — это имена переменных вне функций и имена функций. Эти атрибуты наследуются всеми объектами, созданными на основе данного класса. Атрибуты обеспечивают свойства и поведение объекта. Объекты могут иметь атрибуты, которые создаются в теле метода, если данный метод будет вызван для конкретного объекта.
Пример класса (ООП) на Python 3:
class Second: color = "red" form = "circle" def changecolor(self,newcolor): self.color = newcolor def changeform(self,newform): self.form = newform obj1 = Second() obj2 = Second() print (obj1.color, obj1.form) # вывод на экран "red circle" print (obj2.color, obj2.form) # вывод на экран "red circle" obj1.changecolor("green") # изменение цвета первого объекта obj2.changecolor("blue") # изменение цвет второго объекта obj2.changeform("oval") # изменение формы второго объекта print (obj1.color, obj1.form) # вывод на экран "green circle" print (obj2.color, obj2.form) # вывод на экран "blue oval"
Результат выполнения скрипта Python 3:
red circle red circle green circle blue oval
Конструктор и инициализатор
Теперь стало немного понятнее, зачем нужен в этом странном методе класса:
# для нашего класса Bird def __init__(self, name): self.name = name
Это один из его параметров. Он записывает значение второго параметра () в соответствующий атрибут текущего объекта. Там может быть и больше параметров. А может быть один только — . Без него нельзя.
# для класса Cird def __init__(self): self.message = "Я объект c, класса Cird"
Хорошо… но почему это так? И зачем вообще нужен этот метод?
Это инициализатор. Обычно именно здесь в атрибуты объекта записываются значения. Это могут быть значения по умолчанию (как в классе Cird: ) или значения, полученные с использованием параметров функции.
А как же создается сам объект?
В других языках программирования, например, существуют так называемые конструкторы. В Python тоже есть нечто похожее. Это специальный метод, который называется . Только в Python его код мы обычно не видим и не пишем сами. Такой конструктор существует и работает «за кулисами». В качестве единственного параметра он принимает класс, анализирует его структуру (код) и на базе этой структуры создает пустой объект. Инициализировать его — не царское дело. Пусть этим занимается инициализатор, а не конструктор. Просьба не путать их друг с другом.
Важно, что оба эти метода вызываются автоматически, когда мы создаем объект — сначала , потом. Например для b = Bird(“Сережа”) последовательность вызовов будет выглядеть так:
1. __new__(Bird) 2. __init__(b, "Сережа")
Различия
Различия между «вложенным классом» и «внутренним классом, на который имеется ссылка» перечислены ниже. Они не большие, но иногда хочется выбрать то или иное на основе них.
3.1 Инкапсуляция кода
С помощью «Вложенных классов» можно лучше инкапсулировать код, чем с «Внутренним классом, на который имеется ссылка». Класс в пространстве имен модуля — это глобальная переменная. Цель вложенных классов — уменьшить беспорядок в модуле и поместить внутренний класс внутрь внешнего класса.
Пока никто * не использует , небольшое количество переменных уровня модуля может быть приятным, например, при использовании IDE с автозавершением кода / intellisense.
*Верно?
3.2 Читаемость кода
Документация Django инструктирует использовать внутренний класс Meta для метаданных модели. Немного яснее * проинструктировать пользователей фреймворка написать с внутренним ;
вместо «напишите , затем напишите с участием «;
-
При использовании подхода «Вложенный класс» код может быть прочитан из списка вложенных маркеров, но с помощью метода «Внутренний класс, на который имеется ссылка» нужно прокрутить назад, чтобы увидеть определение чтобы увидеть его «дочерние элементы» (атрибуты).
-
Метод «Внутренний класс, на который имеется ссылка» может быть более читабельным, если уровень вложенности вашего кода растет или строки становятся длинными по какой-либо другой причине.
* Конечно, дело вкуса
3.3 Несколько иные сообщения об ошибках
Это не имеет большого значения, но для полноты картины: при доступе к несуществующему атрибуту для внутреннего класса мы видим несколько иные исключения. Продолжая пример, приведенный в разделе 2:
Это потому, что s внутренних классов