Классы. Модульность.

Классы

Класс - это проект объекта.

Классы состоят из свойств и методов.

Свойства - переменные класса.

Методы - функции класса.

Простейшая форма определения класса:

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

Преимущество такого подхода в том, что от куда бы мы не вызвали статический метод, из класса, или его экземпляра - всегда в качестве первого аргумента будет передан сам класс.

Основы 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 очков и вы закончили игру.' %botcount)
        break



print('До новых встреч!')