forked from lambdamai/lambda-help
-
Notifications
You must be signed in to change notification settings - Fork 0
/
2016-03-17.py
210 lines (154 loc) · 13.8 KB
/
2016-03-17.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#!/usr/bin/python
# -*- coding: utf-8 -*-
""" ООП на Python 3 """
"""
Объектно-ориентированное программирование (ООП) — парадигма программирования, в которой основными концепциями являются понятия объектов и классов.
Класс — тип, описывающий устройство объектов.
Объект — это экземпляр класса. Класс можно сравнить с чертежом, по которому создаются объекты. Объекты так же называют инстансами (англ instance).
Чтобы понятия класса и объекта были яснее можно привести несколько примеров.
Яблоко, апельсин и груша могут являться объектами одного класса - фрукт.
В конце концов класс это коллекция(структура) данных, в случае создания новых классов - пользовательский тип данных.
Так же класс это объединение данных и методов, тогда как при использовании структур (например dict) мы работаем только с данными.
Ближе к практике:
Представим, что мы делаем простейший форум и нам необходимо хранить данные о нескольких пользователях. Каждый пользователь уникален и имеет аналогичный другим набор информации: логин и пароль. Следовательно нам необходима структура данных для хранения этой информации.
Тогда мы создадим класс User, а все объекты этого класса будут уникальными пользователями.
"""
class User(): #ключевое слово class работает как def, но обозначает создание нового класса, а не метода.
#сюда можно поместить переменные, общие для всех объектов класса.
#Добавим поле в целях демонстрации
user_type = "Regular"
#def внутри объявления класса объявляет метод класса
#методы с двумя поччеркиваниями(__) в начале и в конце являются служебными. Это не значит, что их не надо переопределять.
def __init__(self, login, password): # init (полн. initialize - инициализировать, создать) определяет создание экземпляра класса - какие параметры должны подаваться на вход, через аргументы метода, для создания объекта класса.
#init принято называть конструктором класса
#self это ссылка на объект класса. self это обязательный первый аргумент любого метода, оперирующего объектом класса.
#в init self содержит пустой объект, в который можно записать данные.
self.login = login #здесь self.login это поле login нового объекта класса User, а login справа - значение, переданное конструктору
self.password = password
## Рассмотрим наглядно.
## Класс объявлен и мы можем создать объект юзера.
login = 'boris'
password = '12345'
first_user = User(login, password) #запускает метод __init__ и возвращает полученный объект
login = 'kolya'
password = '54321'
second_user = User(login, password)
#first_user и second_user содержат два разных объекта одного класса
print("User types:%s and %s"%(first_user.user_type, second_user.user_type)) #Оба объекта вернут одно значение, хотя мы не вводили его в конструктор. Это поле общее для всех объектов класса.
# Это так же значит, что если мы переопределим user_type у first_user, значение поменяется и у second_user.
print("User logins:%s and %s"%(first_user.login, second_user.login)) #Логины разные, потому что это независимые друг от друга объекты.
# Конечно же мы можем получить класс объекта
print("Object classes:%s and %s"%(first_user.__class__, type(second_user)))#Аналогичный результат
"""
Ещё немного теории.
В python всё является объектами - и строки, и списки, и словари, и всё остальное. Это значит, что у всего есть класс.
ООП как парадигма, независимо от языка, строится на четырех основных принципах.
Скажем о них кратко:
1. Полиморфизм: в разных объектах одна и та же операция может выполнять различные функции. Простым примером полиморфизма может служить оператор сложения. Выражение 1 + 1 производит сложение целых чисел, а [1] + [1] производит создание нового списка являющегося объединением "слагаемых" списков.
В нашем случае полиморфизм можно продемонстрировать через вывод имени пользователя.
Служебный метод __str__ отвечает за преобразование объекта в строковый вид. Мы можем его переопределить
"""
class User():
user_type = "Regular"
def __init__(self, login, password):
self.login = login
self.password = password
def __str__(self): #обратите внимание на self
return self.login
login = 'boris'
password = '12345'
first_user = User(login, password)
login = 'kolya'
password = '54321'
second_user = User(login, password)
#Логины этих юзеров можно получить как обратившись к полю login, так и сделав преобразование объекта в строку
print("User logins with __str__:%s and %s"%(str(first_user), second_user.login))
"""
2. Инкапсуляция: можно скрыть ненужные внутренние подробности работы объекта от окружающего мира. \
В нашем примере инкапсуляция может применяться при установке значения пароля и при запросе его значения. Например мы хотим зашифровать пароль при его записи и расшифровать при получении. Это скроет поле password от прямого доступа, оно будет доступно только через определенные методы.
"""
def encrypt(password):
return password
def decrypt(password):
return password
## Методы шифрования и дешифровки я описывать не буду, используйте воображение и представьте, что они правда шифруют и дешифруют.
class User():
user_type = "Regular"
def __init__(self, login, password):
self.login = login
self.set_password(password)
def set_password(self, password):
self.password = encrypt(password)
def get_password(self, password):
return decrypt(self.password)
def __str__(self): #обратите внимание на self
return self.login
"""
3. Наследование: можно создавать специализированные классы на основе базовых. Это позволяет нам избегать написания повторного кода.
Представим, что нам нужно создать одного обычного пользователя и одного пользователя модератора.
Модератор имеет все те же данные, что и обычный пользователь (логин, пароль) плюс данные, которых не имеет обычный пользователь (раздел модерации).
Чтобы не добавлять в класс User поля, которые нужны только модераторам, логично создать новый класс: Moderator.
Python позволяет классу Moderator наследоваться от User, а значит перенять все его свойства и при необходимости переопределить их.
"""
def encrypt(password):
return password
def decrypt(password):
return password
class User():
user_type = "Regular"
def __init__(self, login, password):
self.login = login
self.set_password(password)
def set_password(self, password):
self.password = encrypt(password)
def get_password(self, password):
return decrypt(self.password)
def __str__(self): #обратите внимание на self
return self.login
class Moderator(User): #В скобках пишем имя класса, от которого наследуется данный класс
#на самом деле когда мы не пишем ничего в скобках применяется наследование от базового класса, который и содержит __str__, __init__ и прочее.
user_type = "Moderator"
def __init__(self, login, password, forum_part):
User.__init__(self, login, password) #Сначала инициализируем базовый класс
self.forum_part = forum_part
# Модератор так же наследует все методы Юзера такие как set_password, get_password.
def __str__(self): #обратите внимание на self
return self.login + ' moderator of ' + self.forum_part
login = 'boris'
password = '12345'
first_user = User(login, password)
login = 'kolya'
password = '54321'
forum_part = 'flood'
second_user = Moderator(login, password, forum_part)
print("User and moderator with __str__:%s and %s"%(str(first_user), str(second_user))) #Коля получил повышение до модератора
print("User and moderator logins:%s and %s"%(first_user.login, second_user.login)) #Однако у Коли так же есть поле логин, хотя мы его и не обозначали в его конструкторе явно
print("User and moderator user types:%s and %s"%(first_user.user_type, second_user.user_type)) #Типы пользователей разные
""" Если нам надо узнать какого типа наш пользователь стоит воспользоваться isinstance """
if isinstance(first_user, Moderator):
print("First user is a moderator!")
elif isinstance(second_user, Moderator):
print("Second user is a moderator!")
else:
print("No moderators!")
"""
Композиция: объект может быть составным и включать в себя другие объекты.
Особенности ООП в Python:
1. множественное наследование;
2. производный класс может переопределить любые методы базовых классов;
3. в любом месте можно вызвать метод с тем же именем базового класса;
4. все атрибуты класса в питоне по умолчанию являются public, т.е. доступны отовсюду; все методы — виртуальные, т.е. перегружают базовые.
Источники:
http://pythonworld.ru/osnovy/obektno-orientirovannoe-programmirovanie-obshhee-predstavlenie.html
https://jeffknupp.com/blog/2014/06/18/improve-your-python-python-classes-and-object-oriented-programming/
http://anandology.com/python-practice-book/object_oriented_programming.html
http://www.python-course.eu/object_oriented_programming.php
Служебные методы, операторы и другое:
http://pythonworld.ru/osnovy/peregruzka-operatorov.html
Для закрепления:
Измените парсер из лекций 1 и 2 так, чтобы для каждого сайта в коде парсера существовал класс имеющий:
- метод parse, получающий на вход ничего и возвращающий список тайтлов книг
- метод find_titles() получающий на вход BeautifulSoup объект и возращающий список тайтлов
Должен быть базовый класс Site, а каждый класс сайта должен от него наследоваться.
Вся индивидуальная логика парсинга конкретного сайта должна быть в классе этого сайта, логика относящаяся ко всем сайтам - в классе Site.
"""