Классы. Модульность.
Basics of Python and 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().
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
Преимущество такого подхода в том, что от куда бы мы не вызвали статический метод, из класса, или его экземпляра - всегда в качестве первого аргумента будет передан сам класс.
Basics of Python and 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()
Basics of Python and 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)
Basics of Python and 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 очков и вы закончили игру.' %botcount)
break
print('До новых встреч!')