Класи. Модульність.
Основи Python и Django. -> Класи
Класи
Клас – це проект об’єкта.
Класи складаються з властивостей та методів.
Властивості – змінні класу.
Методи – функції класу.
Найпростіша форма визначення класу:
class ClassName(object):
<statement-1>
.
.
.
<statement-N>
У дужках ми вказуємо від чого успадковується клас.
У python 3 вказівка (object) не є обов’язковою.
Ім’я має бути з великої літери.
При успадкування клас-нащадок отримує всі методи та властивості від батьківського.
приклад класу.
class User(object):
"""docstring - a simple example class"""
name = 'Dima'
def say_name(self):
print('my name is %s' % name)
user = User()
user.name
user.say_name()
У пітоні все є об’єктами якогось класу.
Щоб подивитися якому класу належить об’єкт можна скористатися функцією type()
>>> type('hello')
<type 'str'>
>>> type(2)
<type 'int'>
>>> type(2.)
<type 'float'>
Щоб подивитися структуру об’єкта можна скористатися функцією dir(). dir().
print(dir(object))
Результат виведення структури об’єкта цілого числа.
dir(3)
>>> ['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__format__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'imag', 'numerator', 'real']
З наголошення починаються службові (внутрішні) методи, які програмісту викликати не потрібно.
Класи мають особливий метод під назвою init (конструктор).
Цей метод викликається щоразу, коли ви створюєте (чи створюєте екземпляр) об’єкт з урахуванням цього класу.
Метод init викликається один раз і не може бути викликаний знову всередині програми.
У цьому вся методі зазвичай проводять ініціалізацію властивостей створюваних об’єктів.
class Animal(object):
"""docstring"""
def __init__(self, color, size):
"""Constructor"""
self.color = color
self.size = size
def what_color(self):
return self.color
## клиентский код
cat = Animal('grey','20sm')
print(cat.what_color())
Кожен метод передається обов’язковий (якщо метод не статичний) параметр self, який представляє майбутній об’єкт.
За допомогою self ми матимемо доступ до властивостей об’єкта як у прикладі вище
Функція str
Кожен об’єкт має своє рядкове уявлення.
За нього відповідає метод str.
Цей метод приховано використовує оператор print при спробі вивести об’єкт.
Це дуже зручно при налагодженні.
Наприклад такий код
class Mycl():
pass
m = Mycl()
print(m)
Виведе
>>> <__main__.Mycl instance at 0x7ff704c8c488>
Що і буде рядковим поданням об’єкта, якого вимагає оператор print.
Щоб змінити це уявлення необхідно визначити функцію str у якій повернути бажаний рядок.
class Mycl():
def __str__(self):
return "This is my class"
m = Mycl()
print(m)
>>> This is my class
Приклад успадкування класів.
class Car(object):
def __init__(self):
self.doors = 2
def move(self):
return 'dr-dr-dr-d'
c = Car()
print c.doors
class Lorry(Car):
def __init__(self):
self.color = 'red'
l = Lorry()
print l.color
print l.doors
Отримуємо помилку:
AttributeError: 'Lorry' object has no attribute 'doors'
Тому що при спадкуванні ми втратили властивість color.
Щоб цього не відбувалося, потрібно викликати конструктор батьківського класу Car.
def __init__(self):
self.color = 'red'
super(Lorry, self).__init__()
Статичні способи.
.
Найчастіше використовувані методи класів - це методи об’єктів (примірників).
Що, якщо нам не потрібно оперувати екземпляром, а працювати з самим класом?
Ми могли б використовувати прості функції. Нарімер:
def get_no_of_instances(cls):
return cls.cnt
class Kls(object):
cnt = 0
def __init__(self):
Kls.cnt = Kls.cnt + 1
ik1 = Kls()
ik2 = Kls()
print(get_no_of_instances(Kls))
>> 2
Але при такому підході ми поміщаємо функцію, що працює з класом за його межами, що погано для читабельності та подальшої підтримки.
Щоб цього уникнути, використовуються статичні методи класів, в які не потрібно передавати параметр екземпляра self.
Декоратор @classmethod
Говорить у тому, що хочемо використовувати метод як статичний
class Kls(object):
cnt = 0
def __init__(self):
Kls.cnt = Kls.cnt + 1
@classmethod
def get_cnt(cls):
return cls.cnt
ik1 = Kls()
ik2 = Kls()
print ik1.get_cnt()
print Kls.get_cnt()
>> 2
Перевага такого підходу в тому, що куди б ми не викликали статичний метод, з класу, або його екземпляра - завжди як перший аргумент буде переданий сам клас.
Основи Python и Django. -> Модульна система Python.
Модульність у Python.
Будь-яка мова має забезпечувати механізм поділу програмного коду на частини.
У пітоні ці частини можуть бути каталогами - пакетами, модулями - файлами та елементами модуля - змінні класи, об’єкти та функції.
При використанні цих частин ми спочатку їх імпортуємо.
Елементи імпорту.
Програмний код може бути поділений на дві категорії – клієнтський та бібліотечний.
Зазвичай ми пишемо клієнтський код, де використовуємо бібліотечні функції, які імпортуємо за допомогою ключового слова import.
Розглянемо які програмні сутності ми можемо імпортувати.
mylib.py - бібліотечний код
GLOBAL_DOMAIN = 'domain.com'
def getDomain():
print 'My domain is %s' % GLOBAL_DOMAIN
class app():
typeApp = 'angular+python'
author = 'Dimitry'
def getBody(self):
html = '<body> this is %s application of %s</body>' % (self.typeApp, self.author)
return html
Ми маємо 3 сутності: змінну, функцію та клас.
Імпортуємо це з іншого клієнтського коду в іншому модулі.
myapp.py
import mylib
import mypackage.mylib # в случае если файл mylib.py в папке mypackage
from mylib import GLOBAL_DOMAIN
from mylib import GLOBAL_DOMAIN as D # импорт под псевдонимом чоб избежать конфликтов имен
from mylib import *
from mypackage.mylib import GLOBAL_DOMAIN
Можна імпортувати кілька сутностей в один рядок.
Як видно є багато способів імпорту які відрізняються тим, що саме ми хочемо імпортувати і де знаходиться те, що ми збираємось імпортувати.
При імпорті ми робимо навігацію через файлову систему за допомогою точкової нотації:
from root_dir.sub_rootdir.sub_sub_rootdir.module import some_issue
Важливо пам’ятати, що каталог, що містить модулі, що імпортуються, повинен містити спеціальний файл init.py
той файл використовується для позначення директорії як пакет Python і зазвичай він порожній.
Проте, т.к. він буде виконаний при кожному імпорті в ньому можна зробити певні події.
Наприклад зробити предімпорт будь-яких бібліотек з іншим, більш зручним ім’ям або створити глобальну змінну.
Наприклад так:
#__init__.py
from mylib import app
myapp = app()
# test.py
from mypackage import myapp
print myapp.getBody()
Основи Python и Django. -> Python робота з датою.
Робота із датою.
Поточна дата.
import datetime
from time import strftime
print("Current date")
print(datetime.datetime.now())
print(datetime.datetime.now().time())
Форматування дати.
now = datetime.datetime.now()
now.strftime("%Y-%m-%d %H:%M")
Додаток до дати днів.
from datetime import timedelta
d = now - timedelta(days=6)
timedelta()
datetime.timedelta(microseconds=1)
datetime.timedelta(milliseconds=1)
datetime.timedelta(seconds=1)
datetime.timedelta(minutes=1)
datetime.timedelta(hours=1)
datetime.timedelta(days=1)
datetime.timedelta(weeks=1)
Поповнення місяців (модуль dateutil).
from dateutil.relativedelta import relativedelta
date_after_month = datetime.datetime.today() + relativedelta(months=1)
print ('Today: %s' % datetime.datetime.today().strftime('%d/%m/%Y'))
print ('After Month: %s' % date_after_month.strftime('%d/%m/%Y'))
Атрибути об’єкта дати.
import datetime
today = datetime.date.today()
print ('Year: %s' % today.year)
print ('Mon : %s' % today.month)
print ('Day : %s' % today.day)
Заміна параметрів дати.
print(date_after_month.replace(year=2000))
Порівняння
t1 = datetime.time(14, 55, 0)
t2 = datetime.time(13,56,0)
print(t1<t2)
Основи Python и Django. -> Python домашнє завдання.
Домашнє завдання.
Переписати на функції.
Функції колоди
-
створення перемішаної колоди
-
діставання картки
Функції гри
-ініціалізація (створення колоди та словника статистики з окулярами для бота та гравця та виграшем)
-
ставка гравцем
-
гра бота
-
старт гри
-
кінець гри
Переписати на класах.
-
клас колоди
-
клас бота
-
клас гравця
-
клас гри
приклад.
koloda = [6,7,8,9,10,2,3,4,11] * 4
import random
from termcolor import colored
random.shuffle(koloda)
print('Пограємо в очко?')
count = 0
botcount = 0
while True:
choice = input('Братимете карту? y/n\n')
if choice == 'y':
current = koloda.pop()
bot = koloda.pop()
print(colored('Вам трапилася карта гідністю %d' %current, 'red'))
print(colored('Боту попалося карта гідністю %d' %bot, "blue"))
count += current
botcount += bot
if count > 21:
print('Вибачте, але ви програли')
break
elif count == 21:
print('Вибачте, але ви програли 21!')
print("Бот набрав %d" %botcount)
break
elif botcount == 21:
print("Бот набрав %d" %botcount )
break
elif botcount > 21:
print("Бот програв")
print("Бот програв %d" %count)
break
else:
print("-----------------------------------")
print(colored('У вас %d очок.' %count, "red"))
print(colored('У бота %d очок.' %botcount, "blue"))
elif choice == 'n':
print('У вас %d очок і ви закінчили гру.' %count)
print('У бота %d У вас %d очок і ви закінчили гру.' %botcount)
break
print('До нової зустрічі!')