Классы в python
Содержание:
- Как создаются списки в Python
- Conclusion#
- Разница в скорости между Python 2 и Python 3
- @classmethod и @staticmethod
- Изменение полей объекта
- Парсинг входных данных пользователя с input()
- Что такое наследование?
- Функции
- Класс как создатель объектов
- Устойчивость объектов
- What Is Object-Oriented Programming in Python?#
- Что такое self?
Как создаются списки в Python
Существует несколько способов создания списков в Python. Чтобы лучше понять компромиссы связанные с использованием list comprehension, давайте сначала рассмотрим способы создания списков с помощью этих подходов.
Использование цикла for
Наиболее распространенным типом цикла является цикл for. Использование цикла for можно разбить на три этапа:
- Создание пустого списка.
- Цикл по итерируемому объекту или диапазону элементов range.
- Добавляем каждый элемент в конец списка.
Допустим на надо создать список squares, то эти шаги будут в трех строках кода:
>>> squares = [] >>> for i in range(10): ... squares.append(i * i) >>> squares
Здесь мы создаем пустой список squares. Затем используем цикл for для перебора range(10). Наконец умножаем каждое число отдельно и добавляете результат в конец списка.
Использование объектов map()
map() предоставляет альтернативный подход, основанный на функциональном программировании. Мы передаем функцию и итерируемый объект (iterable), а map() создаст объект. Этот объект содержит выходные данные, которые мы получаем при запуске каждого итерируемого элемента через предоставленную функцию.
Немного запутано, поэтому в качестве примера рассмотрим ситуацию, в которой необходимо рассчитать цену после вычета налога для списка транзакций:
>>> txns = >>> TAX_RATE = .08 >>> def get_price_with_tax(txn): ... return txn * (1 + TAX_RATE) >>> final_prices = map(get_price_with_tax, txns) >>> list(final_prices)
Здесь у вас есть итерируемый объект txns (в нашем случае простой список) и функция get_price_with_tax(). Мы передаем оба этих аргумента в map() и сохраняем полученный объект в final_prices. Мы можем легко преобразовать этот объект map в список, используя list().
Использование List Comprehensions
List comprehensions — это третий способ составления списков. При таком элегантном подходе мы можем переписать цикл for из первого примера всего в одну строку кода:
>>> squares = >>> squares
Вместо того, чтобы создавать пустой список и добавлять каждый элемент в конец, мы просто определяем список и его содержимое одновременно, следуя этому формату:
new_list =
Каждое представление списков в Python включает три элемента:
- какое либо вычисление, вызов метода или любое другое допустимое выражение, которое возвращает значение. В приведенном выше примере выражение i * i является квадратом значения члена.
- является объектом или значением в списке или итерируемым объекте (iterable). В приведенном выше примере значением элемента является i.
- список, множество, последовательность, генератор или любой другой объект, который может возвращать свои элементы по одному. В приведенном выше примере iterable является range(10).
Поскольку требования к expression (выражению) настолько гибки, представление списков хорошо работает во многих местах, где вы будете использовать map(). Вы так же можем переписать пример ценообразования:
>>> txns = >>> TAX_RATE = .08 >>> def get_price_with_tax(txn): ... return txn * (1 + TAX_RATE) >>> final_prices = >>> final_prices
Единственное различие между этой реализацией и map() состоит в том, что list comprehension возвращает список, а не объект map.
Преимущества использования представления списков
Представление списков часто описываются как более Pythonic, чем циклы или map(). Но вместо того, чтобы слепо принимать эту оценку, стоит понять преимущества использования list comprehension по сравнению с альтернативами. Позже вы узнаете о нескольких сценариях, в которых альтернативы являются лучшим выбором.
Одним из основных преимуществ использования является то, что это единственный инструмент, который вы можете использовать в самых разных ситуациях. В дополнение к созданию стандартного списка, списки могут также использоваться для отображения и фильтрации. Вам не нужно использовать разные подходы для каждого сценария.
Это основная причина, почему list comprehension считаются Pythonic, поскольку Python включает в себя простые и мощные инструменты, которые вы можете использовать в самых разных ситуациях. Дополнительным преимуществом является то, что всякий раз, когда вы используете представления списков, вам не нужно запоминать правильный порядок аргументов, как при вызове map().
List comprehensions также более декларативны, чем циклы, что означает, что их легче читать и понимать. Циклы требуют, чтобы вы сосредоточились на создание списока. Вы должны вручную создать пустой список, зациклить элементы и добавить каждый из них в конец списка. Используя представления списков, вы можете вместо этого сосредоточиться на том, что хотите добавить в список, и положиться, на то что Python позаботится о том, как происходит построение списка.
Conclusion#
In this tutorial, you learned about object-oriented programming (OOP) in Python. Most modern programming languages, such as Java, C#, and C++, follow OOP principles, so the knowledge you gained here will be applicable no matter where your programming career takes you.
In this tutorial, you learned how to:
- Define a class, which is a sort of blueprint for an object
- Instantiate an object from a class
- Use attributes and methods to define the properties and behaviors of an object
- Use inheritance to create child classes from a parent class
- Reference a method on a parent class using
- Check if an object inherits from another class using
Разница в скорости между Python 2 и Python 3
Многие разработчики отмечают разницу в скорости между в Python 3 и в Python 2. Так как оба метода имплементируются одинаково разумно ожидать одинаковой скорости. Однако разница все же есть, и она обусловлена тем фактом, что Python 3 в общем и целом обычно выполняется медленнее, чем Python 2.
Python
def test_while():
i = 0
while i < 20000:
i += 1
return
1 |
deftest_while() i= whilei<20000 i+=1 return |
Python
print(‘Python’, python_version())
%timeit test_while()
1 |
print(‘Python’,python_version()) %timeittest_while() |
Shell
Python 3.8.1
100 loops, best of 3: 2.68 ms per loop
1 |
Python3.8.1 100loops,best of32.68ms per loop |
Python
print ‘Python’, python_version()
%timeit test_while()
1 |
print’Python’,python_version() %timeittest_while() |
Shell
Python 2.7.6
1000 loops, best of 3: 1.72 ms per loop
1 |
Python2.7.6 1000loops,best of31.72ms per loop |
@classmethod и @staticmethod
Я не пользовался ими ранее, так что сделал небольшое исследование.
- Декоратор <*@classmethod>* может быть вызван при помощи экземпляра класса, или напрямую, через собственный класс Python в качестве первого аргумента. В соответствии с документацией Python: он может быть вызван как в классе (например, C.f()), или в экземпляре (например, C().f()). Экземпляр игнорируется, за исключением его класса. Если метод класса вызван для выведенного класса, то объект выведенного класса передается в качестве подразумеваемого первого аргумента.
- Декоратор @classmethod, в первую очередь, используется как чередуемый конструктор или вспомогательный метод для инициализации.
- Декоратор <*@staticmethod>* — это просто функция внутри класса. Вы можете вызывать их обоих как с инициализацией класса так и без создания экземпляра класса. Обычно это применяется в тех случаях, когда у вас есть функция, которая, по вашему убеждению, имеет связь с классом. По большей части, это выбор стиля.
Если мы взглянем на пример кода, в котором показано, как работает декоратор, это может помочь понять основные принципы:
Python
# -*- coding: utf-8 -*-
class DecoratorTest(object):
«»»
Тестируем обычный метод против @classmethod против @staticmethod
«»»
def __init__(self):
«»»Конструктор»»»
pass
def doubler(self, x):
print(«умножаем на 2»)
return x*2
@classmethod
def class_tripler(klass, x):
print(«умножаем на 3: %s» % klass)
return x*3
@staticmethod
def static_quad(x):
print(«умножаем на 4»)
return x*4
if __name__ == «__main__»:
decor = DecoratorTest()
print(decor.doubler(5))
print(decor.class_tripler(3))
print(DecoratorTest.class_tripler(3))
print(DecoratorTest.static_quad(2))
print(decor.static_quad(3))
print(decor.doubler)
print(decor.class_tripler)
print(decor.static_quad)
1 |
# -*- coding: utf-8 -*- classDecoratorTest(object) «»» Тестируем обычный метод против @classmethod против @staticmethod def__init__(self) «»»Конструктор»»» pass defdoubler(self,x) print(«умножаем на 2») returnx*2 @classmethod defclass_tripler(klass,x) print(«умножаем на 3: %s»%klass) returnx*3 @staticmethod defstatic_quad(x) print(«умножаем на 4») returnx*4 if__name__==»__main__» decor=DecoratorTest() print(decor.doubler(5)) print(decor.class_tripler(3)) print(DecoratorTest.class_tripler(3)) print(DecoratorTest.static_quad(2)) print(decor.static_quad(3)) print(decor.doubler) print(decor.class_tripler) print(decor.static_quad) |
Этот пример демонстрирует, что вы можете вызывать обычный метод и оба метода декоратора одним и тем же путем
Обратите внимание на то, что вы можете вызывать обе функции @classmethod и @staticmethod прямо из класса или из экземпляра класса. Если вы попытаетесь вызвать обычную функцию при помощи класса (другими словами, DecoratorTest.doubler(2)), вы получите ошибку TypeError
Также стоит обратить внимание на то, что последний оператор вывода показывает, что decor.static_quad возвращает обычную функцию вместо связанного метода.
Изменение полей объекта
В Python объекту можно не только переопределять поля и методы, унаследованные от класса, также можно добавить новые, которых нет в классе:
>>> l.test = "hi" >>> B.test Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: type object 'B' has no attribute 'test' >>> l.test 'hi'
Однако в программировании так делать не принято, потому что тогда объекты одного класса будут отличаться между собой по набору атрибутов. Это затруднит автоматизацию их обработки, внесет в программу хаос.
Поэтому принято присваивать полям, а также получать их значения, путем вызова методов:
>>> class User: ... def setName(self, n): ... self.name = n ... def getName(self): ... try: ... return self.name ... except: ... print("No name") ... >>> first = User() >>> second = User() >>> first.setName("Bob") >>> first.getName() 'Bob' >>> second.getName() No name
Подобные методы в простонародье называют сеттерами (set – установить) и геттерами (get – получить).
Парсинг входных данных пользователя с input()
К счастью, функция была исправлена в Python 3, таким образом позволяя хранить входные данные пользователя как объекты . Во избежание опасного поведения в Python 2 при чтении в других типов, помимо string, нужно использовать .
Python 2
Python
Python 2.7.6
on darwin
Type «help», «copyright», «credits» or «license» for more information.
>>> my_input = input(‘enter a number: ‘)
enter a number: 123
>>> type(my_input)
<type ‘int’>
>>> my_input = raw_input(‘enter a number: ‘)
enter a number: 123
>>> type(my_input)
<type ‘str’>
1 |
Python2.7.6 GCC4.0.1(Apple Inc.build5493)on darwin Type»help»,»copyright»,»credits»or»license»formore information. >>>my_input=input(‘enter a number: ‘) enteranumber123 >>>type(my_input) <type’int’> >>>my_input=raw_input(‘enter a number: ‘) enteranumber123 >>>type(my_input) <type’str’> |
Python 3
Python
Python 3.4.1
on darwin
Type «help», «copyright», «credits» or «license» for more information.
>>> my_input = input(‘enter a number: ‘)
enter a number: 123
>>> type(my_input)
<class ‘str’>
1 |
Python3.4.1 GCC4.2.1(Apple Inc.build5577)on darwin Type»help»,»copyright»,»credits»or»license»formore information. >>>my_input=input(‘enter a number: ‘) enteranumber123 >>>type(my_input) <class’str’> |
Что такое наследование?
Наследование подразумевает, что дочерний класс использует код, созданный в родительском классе.
Дочерний класс, или подкласс – это класс, который наследует код из родительского, или базового класса.
Предположим, что у нас есть класс Parent с переменными last_name, height, и eye_color. Подкласс Child может наследовать эти переменные из класса Parent, то есть повторно использовать этот код. Это позволяет уменьшить объём кода и снизить избыточность.
Родительские классы
Родительский, или базовый класс создаёт шаблон кода, который в дальнейшем может наследоваться дочерними классами. Родительским классом может быть любой класс. Базовые классы – это не просто шаблоны, а полноценные функционирующие классы.
Предположим, у нас есть общий родительский класс Bank_account с дочерними классами Personal_account и Business_account. Многие параметры классов Personal_account и Business_account будут совпадать. Такие параметры можно наследовать из родительского класса Bank_account. В подклассе Business_account будут индивидуальные параметры (например, методы сбора деловых документов и форм и переменная employee_identification_number).
Аналогичным образом, класс Animal может содержать методы eating() и sleeping(), а подкласс Snake помимо вышеперечисленных наследуемых методов может также содержать методы hissing() и slithering().
Для примера попробуйте создать родительский класс Fish (в дальнейшем мы используем его, чтобы создать различные подклассы с типами рыб).
Создайте файл fish.py и добавьте в него метод конструктора __init__(), который будет содержать переменные first_name и last_name для каждого подкласса (или объекта) Fish.
Переменная last_name содержит строку «Fish», потому что почти все подклассы будут использовать это значение.
Добавьте в файл другие методы:
Теперь в файле есть методы swim() и swim_backwards(), которые будут наследоваться подклассами.
Добавьте другие атрибуты в метод __init__():
Создание родительского класса ничем не отличается от создания обычного класса. Единственный нюанс: нужно заранее продумывать, какие параметры смогут наследовать дочерние классы.
Дочерние классы
Дочерние классы, или подклассы – это классы, которые наследуют параметры родительских классов. Каждый дочерний класс сможет использовать методы и переменные родительского класса.
К примеру, дочерний класс Goldfish может наследовать из класса Fish функцию swim().
Дочерние классы начинаются немного иначе. В первой строке нужно передать родительский класс:
Класс Trout является дочерним по отношению к классу Fish (родительский класс нужно указать в круглых скобках).
В дочернем классе можно добавить больше методов, переопределить методы родительского класса или просто принять его методы с помощью ключевого слова pass, например:
Теперь создайте объект Trout и наследуйте методы родительского класса, не добавляя новых:
Теперь в файле есть объект Trout, который использует все методы класса Fish несмотря на то, что они не объявлены в самом объекте. Нужно только передать значение «Terry» переменной first_name; все остальные переменные уже инициализированы.
Запустите программу. Вы получите:
Создайте другой дочерний класс, теперь уже добавив новые методы. Класс будет называться Clownfish, его индивидуальный метод – live_with_anemone.
Создайте объект Clownfish:
Запустив программу, вы получите такой вывод:
Как видите, объект casey использует методы __init__() и swim() родительского класса Fish и индивидуальный метод live_with_anemone().
Если попробовать использовать метод live_with_anemone() в объекте Trout, получится ошибка:
Это потому, что метод live_with_anemone() принадлежит исключительно дочернему классу Clownfish.
Функции
Последнее обновление: 11.04.2018
Функции представляют блок кода, который выполняет определенную задачу и который можно повторно использовать в других частях программы. Формальное определение функции:
def имя_функции (): инструкции
Определение функции начинается с выражения def, которое состоит из имени функции, набора скобок с параметрами и двоеточия.
Параметры в скобках необязательны. А со следующей строки идет блок инструкций, которые выполняет функция. Все инструкции функции имеют отступы от начала строки.
Например, определение простейшей функции:
def say_hello(): print("Hello")
Функция называется . Она не имеет параметров и содержит одну единственную инструкцию,
которая выводит на консоль строку «Hello».
Для вызова функции указывается имя функции, после которого в скобках идет передача значений для всех ее параметров. Например:
def say_hello(): print("Hello") say_hello() say_hello() say_hello()
Здесь три раза подряд вызывается функция say_hello. В итоге мы получим следующий консольный вывод:
Hello Hello Hello
Теперь определим и используем функцию с параметрами:
def say_hello(name): print("Hello,",name) say_hello("Tom") say_hello("Bob") say_hello("Alice")
Функция принимает параметр name, и при вызове функции мы можем передать вместо параметра какой-либо значение:
Hello, Tom Hello, Bob Hello, Alice
Значения по умолчанию
Некоторые параметры функции мы можем сделать необязательными, указав для них значения по умолчанию при определении функции. Например:
def say_hello(name="Tom"): print("Hello,", name) say_hello() say_hello("Bob")
Здесь параметр name является необязательным. И если мы не передаем при вызове функции для него значение, то применяется значение по умолчанию, то есть
строка «Tom».
Именованные параметры
При передаче значений функция сопоставляет их с параметрами в том порядке, в котором они передаются. Например, пусть есть следующая функция:
def display_info(name, age): print("Name:", name, "\t", "Age:", age) display_info("Tom", 22)
При вызове функции первое значение «Tom» передается первому параметру — параметру name, второе значение — число 22 передается второму параметру — age. И так далее по порядку.
Использование именованных параметров позволяет переопределить порядок передачи:
def display_info(name, age): print("Name:", name, "\t", "Age:", age) display_info(age=22, name="Tom")
Именованные параметры предполагают указание имени параметра с присвоением ему значения при вызове функции.
Неопределенное количество параметров
С помощью символа звездочки можно определить неопределенное количество параметров:
def sum(*params): result = 0 for n in params: result += n return result sumOfNumbers1 = sum(1, 2, 3, 4, 5) # 15 sumOfNumbers2 = sum(3, 4, 5, 6) # 18 print(sumOfNumbers1) print(sumOfNumbers2)
В данном случае функция sum принимает один параметр — , но звездочка перед названием параметра указывает, что фактически на место этого
параметра мы можем передать неопределенное количество значений или набор значений. В самой функции с помощью цикла for можно пройтись по этому набору и произвести с переданными
значениями различные действия. Например, в данном случае возвращается сумма чисел.
Возвращение результата
Функция может возвращать результат. Для этого в функции используется оператор return, после которого указывается возвращаемое значение:
def exchange(usd_rate, money): result = round(money/usd_rate, 2) return result result1 = exchange(60, 30000) print(result1) result2 = exchange(56, 30000) print(result2) result3 = exchange(65, 30000) print(result3)
Поскольку функция возвращает значение, то мы можем присвоить это значение какой-либо переменной и затем использовать ее: .
В Python функция может возвращать сразу несколько значений:
def create_default_user(): name = "Tom" age = 33 return name, age user_name, user_age = create_default_user() print("Name:", user_name, "\t Age:", user_age)
Здесь функция create_default_user возвращает два значения: name и age. При вызове функции эти значения по порядку присваиваются переменным
user_name и user_age, и мы их можем использовать.
Функция main
В программе может быть определено множество функций. И чтобы всех их упорядочить, хорошей практикой считается добавление специальной функции
, в которой потом уже вызываются другие функции:
def main(): say_hello("Tom") usd_rate = 56 money = 30000 result = exchange(usd_rate, money) print("К выдаче", result, "долларов") def say_hello(name): print("Hello,", name) def exchange(usd_rate, money): result = round(money/usd_rate, 2) return result # Вызов функции main main()
НазадВперед
Класс как создатель объектов
Приведенный выше класс позволяет создавать объекты, но мы не можем применить к объекту метод adder():
>>> l = B() >>> l.n 5 >>> l.adder(100) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: adder() takes 1 positional argument but 2 were given
В сообщении об ошибке говорится, что adder() принимает только один аргумент, а было передано два. Откуда взялся второй аргумент, и кто он такой, если в скобках было указано только одно число 100?
На самом деле классы – это далеко не модули. Они идут дальше модулей и обладают своими особенностями. Класс создает объекты, которые в определенном смысле являются его наследниками. Это значит, что если у объекта нет собственного поля , то интерпретатор ищет его уровнем выше, то есть в классе. Таким образом, если мы присваиваем объекту поле с таким же именем как в классе, то оно перекрывает, т. е. переопределяет, поле класса:
>>> l.n = 10 >>> l.n 10 >>> B.n 5
Здесь и – это разные переменные. Первая находится в пространстве имен объекта . Вторая – в пространстве класса . Если бы мы не добавили поле к объекту , то интерпретатор бы поднялся выше по дереву наследования и пришел бы в класс, где бы и нашел это поле.
Что касается методов, то они также наследуются объектами класса. В данном случае у объекта нет своего собственного метода adder, значит, он ищется в классе . Однако от класса может быть порождено множество объектов. Методы же чаще всего предназначаются для обработки объектов. Таким образом, когда вызывается метод, в него надо передать конкретный объект, который он будет обрабатывать.
Понятно, что передаваемый экземпляр, это объект, к которому применяется метод. Выражение l.adder(100) выполняется интерпретатором следующим образом:
-
Ищу атрибут adder() у объекта . Не нахожу.
-
Тогда иду искать в класс , так как он создал объект .
-
Здесь нахожу искомый метод. Передаю ему объект, к которому этот метод надо применить, и аргумент, указанный в скобках.
Другими словами, выражение преобразуется в выражение .
Таким образом, интерпретатор попытался передать в метод adder() класса два параметра – объект и число 100. Но мы запрограммировали метод adder() так, что он принимает только один параметр. В Python, да и многих других языках, определения методов не предполагают принятие объекта как само собой подразумеваемое. Принимаемый объект надо указывать явно.
По соглашению в Python для ссылки на объект используется имя self. Вот так должен выглядеть метод adder(), если мы планируем вызывать его через объекты:
>>> class B: ... n = 5 ... def adder(self, v): ... return v + self.n ...
Переменная self связывается с объектом, к которому был применен данный метод, и через эту переменную мы получаем доступ к атрибутам объекта. Когда этот же метод применяется к другому объекту, то self свяжется уже с этим другим объектом, и через эту переменную будут извлекаться только его свойства.
Протестируем обновленный метод:
>>> l = B() >>> m = B() >>> l.n = 10 >>> l.adder(3) 13 >>> m.adder(4) 9
Здесь от класса создаются два объекта – и . Для объекта заводится собственное поле . Объект , за неимением собственного, наследует от класса . Можно в этом убедиться, проверив соответствие:
>>> m.n is B.n True >>> l.n is B.n False
В методе adder() выражение – это обращение к свойству , переданного объекта, и не важно, на каком уровне наследования оно будет найдено. Если метод не принимает объект, к которому применяется, в качестве первого параметра, то такие методы в других языках программирования называются статическими
Они имеют особый синтаксис и могут вызываться как через класс, так и через объект этого класса. В Python все немного по-другому. Для имитации статических методов используется специальный декоратор, после чего метод можно вызывать не только через класс, но и через объект, не передавая сам объект
Если метод не принимает объект, к которому применяется, в качестве первого параметра, то такие методы в других языках программирования называются статическими. Они имеют особый синтаксис и могут вызываться как через класс, так и через объект этого класса. В Python все немного по-другому. Для имитации статических методов используется специальный декоратор, после чего метод можно вызывать не только через класс, но и через объект, не передавая сам объект.
Устойчивость объектов
Объекты всегда имеют своё представление в памяти компьютера и их время жизни не больше времени работы программы. Однако зачастую необходимо сохранять данные между запусками приложения и/или
передавать их на другие компьютеры.
Одним из решений этой проблемы является устойчивость объектов (англ. object persistence) которая достигается с помощью хранения представлений объектов (сериализацией) в виде байтовых последовательностей и их последующего восстановления (десериализация).
Модуль является наиболее простым способом «консервирования» объектов в Python.
Следующий пример показывает, как работает сериализация и десериализация:
# сериализация >>> import pickle >>> p = set() >>> pickle.dumps(p) 'c__builtin__\nset\np0\n((lp1\nI8\naI1\naI2\naI3\naI5\natp2\nRp3\n.' # де-сериализация >>> import pickle >>> p = pickle.loads('c__builtin__\nset\np0\n((lp1\nI8\naI1\naI2\naI3\naI5\natp2\nRp3\n.') >>> print p set()
Получаемая при сериализации строка может быть передана по сети, записана в файл или специальное хранилище объектов, а позже — прочитана. Сериализации поддаются не все объекты. Некоторые объекты (например, классы и функции) представляются своими именами, поэтому для десериализации требуется наличие тех же самых классов. Нужно отметить, что нельзя десериализовать данные из непроверенных
источников с помощью модуля , так как при этом возможны практически любые
действия на локальной системе. При необходимости обмениваться данными по незащищенным каналам
или с ненадежными источниками можно воспользоваться другими модулями для сериализации.
В основе сериализации объекта стоит представление его состояния. По умолчанию состояние объекта — это все, что записано в его полях. Пользовательские классы могут управлять сериализацией, предоставляя состояние объекта явным образом (методы , и др.).
На стандартном для Python механизме сериализации построена работа модуля (shelve (англ. глаг.) — ставить на полку; сдавать в архив). Модуль предоставляет функцию
. Объект, который она возвращает, работает аналогично словарю, но объекты сериализуются и сохраняются в файле:
>>> import shelve >>> s = shelve.open("myshelve.bin") >>> s'abc' = 1, 2, 3 >>> s.close() # ..... >>> s = shelve.open("myshelve.bin") >>> s'abc' 1, 2, 3
Сериализация — не единственная возможная, и подходит не всегда. Для сериализации, не зависящей от языка программирования, можно использовать, например, XML.
What Is Object-Oriented Programming in Python?#
Object-oriented programming is a programming paradigm that provides a means of structuring programs so that properties and behaviors are bundled into individual objects.
Put another way, object-oriented programming is an approach for modeling concrete, real-world things, like cars, as well as relations between things, like companies and employees, students and teachers, and so on. OOP models real-world entities as software objects that have some data associated with them and can perform certain functions.
Another common programming paradigm is procedural programming, which structures a program like a recipe in that it provides a set of steps, in the form of functions and code blocks, that flow sequentially in order to complete a task.
Что такое self?
Классам нужен способ, что ссылаться на самих себя. Это не из разряда нарциссичного отношения со стороны класса. Это способ сообщения между экземплярами. Слово self это способ описания любого объекта, буквально. Давайте взглянем на пример, который мне кажется наиболее полезным, когда я сталкиваюсь с чем-то новым и странным:
Добавьте этот код в конец класса, который вы написали ранее и сохраните:
Python
class Vehicle(object):
«»»docstring»»»
def __init__(self, color, doors, tires):
«»»Constructor»»»
self.color = color
self.doors = doors
self.tires = tires
def brake(self):
«»»
Stop the car
«»»
return «Braking»
def drive(self):
«»»
Drive the car
«»»
return «I’m driving!»
if __name__ == «__main__»:
car = Vehicle(«blue», 5, 4)
print(car.color)
truck = Vehicle(«red», 3, 6)
print(truck.color)
1 |
classVehicle(object) «»»docstring»»» def__init__(self,color,doors,tires) «»»Constructor»»» self.color=color self.doors=doors self.tires=tires defbrake(self) «»» Stop the car return»Braking» defdrive(self) «»» Drive the car return»I’m driving!» if__name__==»__main__» car=Vehicle(«blue»,5,4) print(car.color) truck=Vehicle(«red»,3,6) print(truck.color) |
Условия оператора if в данном примере это стандартный способ указать Пайтону на то, что вы хотите запустить код, если он выполняется как автономный файл. Если вы импортировали свой модуль в другой скрипт, то код, расположенный ниже проверки if не заработает. В любом случае, если вы запустите этот код, вы создадите два экземпляра класса автомобиля (Vehicle): класс легкового и класс грузового. Каждый экземпляр будет иметь свои собственные атрибуты и методы. Именно по этому, когда мы выводи цвета каждого экземпляра, они и отличаются друг от друга. Причина в том, что этот класс использует аргумент self, чтобы указать самому себе, что есть что. Давайте немного изменим класс, чтобы сделать методы более уникальными:
Python
class Vehicle(object):
«»»docstring»»»
def __init__(self, color, doors, tires, vtype):
«»»Constructor»»»
self.color = color
self.doors = doors
self.tires = tires
self.vtype = vtype
def brake(self):
«»»
Stop the car
«»»
return «%s braking» % self.vtype
def drive(self):
«»»
Drive the car
«»»
return «I’m driving a %s %s!» % (self.color, self.vtype)
if __name__ == «__main__»:
car = Vehicle(«blue», 5, 4, «car»)
print(car.brake())
print(car.drive())
truck = Vehicle(«red», 3, 6, «truck»)
print(truck.drive())
print(truck.brake())
1 |
classVehicle(object) «»»docstring»»» def__init__(self,color,doors,tires,vtype) «»»Constructor»»» self.color=color self.doors=doors self.tires=tires self.vtype=vtype defbrake(self) «»» Stop the car return»%s braking»%self.vtype defdrive(self) «»» Drive the car return»I’m driving a %s %s!»%(self.color,self.vtype) if__name__==»__main__» car=Vehicle(«blue»,5,4,»car») print(car.brake()) print(car.drive()) truck=Vehicle(«red»,3,6,»truck») print(truck.drive()) print(truck.brake()) |
В этом примере мы передаем другой параметр, чтобы сообщить классу, какой тип транспортного средства мы создаем. После этого мы вызываем каждый метод для каждого экземпляра. Если вы запустите данный код, вы получите следующий вывод:
Python
car braking
I’m driving a blue car!
I’m driving a red truck!
truck braking
1 |
car braking I’m driving a blue car! I’mdrivingared truck! truck braking |
Это показывает, как экземпляр отслеживает свой аргумент self. Вы также могли заметить, что мы можем переместить переменные атрибутов из метода __init__ в другие методы. Это возможно потому, что все эти атрибуты связанны с аргументом self. Если бы мы этого не сделали, переменные были бы вне области видимости в конце метода __init__ .