Простое веб приложение на web.py.

Basics of Python and Django. -> Декораторы.

Декораторы

Декораторы - это такая конструкция языка, которая может изменить поведение функции, метода, класса и т.д. не изменяя ее саму.

Это идеальный способ что то изменить в программе без модификации кода изменяемого объекта.

Разберем процесс декорирования функции.

Для начала, рассмотрим некоторые особенности функций.

Присвоение функции переменной.

def greet(name):
    return "hello "+name

greet_someone = greet
print greet_someone("John")

# Outputs: hello John

Как видно, функция может быть присвоена переменной как обычное значение и следовательно быть передана как параметр другой функции.

Определение функции внутри другой функции.

def greet(name):
    def get_message():
        return "Hello %s" % name
    result = get_message()+'!'
    return result
print greet("John")

# Outputs: Hello John

При определении внутренней функции все переменные, переданные во внешнюю, буду сохранены во внутреннем пространстве (замыкании) внешней функции и доступны из внутренней.

Передача функции как параметра другой функции.

def greet(name):
   return "Hello " + name

def call_func(func):
    other_name = "John"
    return func(other_name)

print call_func(greet)

# Outputs: Hello John

Функция может быть передана параметром и быть вызвана изнутри той функции, в которую была передана.

Функция может возвращать другую функцию.

Иными словами - функция может создавать функцию.

def compose_greet_func():
    def get_message():
        return "Hello there!"

    return get_message

greet = compose_greet_func()
print greet()

# Outputs: Hello there!

Внутрення функция имеет доступ к замыкающему пространству имен внешней.

def compose_greet_func(name):
    def get_message():
        return "Hello there "+name+"!"

    return get_message

greet = compose_greet_func("John")
print greet()

# Outputs: Hello there John!

Обратите внимание на то как мы забираем переменную name из замыкания и возвращаем внутреннюю функцию.

В момент вызова greet = compose_greet_func(“John”) в greet будет находится строка “John”.

Декоратор.

Давайте совместим идеи, изложенные выше и построим декоратор.

Putting the ideas mentioned above together, we can build a decorator. In this example let’s consider a function that wraps the string output of another function by p tags.

В примере предположим, что нам необходимо изменить вывод функции get_text, заключив ее вывод в тэги

.

def get_text(name):
   return "Hello, {0}".format(name)

def p_decorate(func):
   def func_wrapper(name):
       return "<p>{0}</p>".format(func(name))
   return func_wrapper

my_get_text = p_decorate(get_text)

print my_get_text("John")

# <p>Hello, John</p>

Это и был наш первый декоратор. Т.е. функция-декоратор, принимающаю другую (декорируемую) функцию в качестве аргумента и изменяющая ее поведение. Поведение изменяется внутри вложенной функции декоратора строкой return “

{0}

“.format(func(name)). При этом мы вызываем декорируемую функцию в том месте, где хотим получить ее результат. В конце возвращаем эту вложенную функцию, которая называется оберткой (wrapper).

Синтаксис декоратора в Python.

Применение декоратора может быть упрощено использованием знака @.

Этот знак - эквивалент процедуры my_get_text = p_decorate(get_text) из примера выше.

def p_decorate(func):
   def func_wrapper(name):
       return "<p>{0}</p>".format(func(name))
   return func_wrapper

@p_decorate
def get_text(name):
   return "lorem ipsum, {0} dolor sit amet".format(name)

print get_text("John")

# Outputs <p>lorem ipsum, John dolor sit amet</p>

Now let’s consider we wanted to decorate our get_text function by 3 other functions.

Теперь представим, что нам нужно задекорировать не одной а тремя функциями последовательно, добавив дополнительные теги strong и div.

Определим эти три функции-декоратора.

def p_decorate(func):
   def func_wrapper(name):
       return "<p>{0}</p>".format(func(name))
   return func_wrapper

def strong_decorate(func):
    def func_wrapper(name):
        return "<strong>{0}</strong>".format(func(name))
    return func_wrapper

def div_decorate(func):
    def func_wrapper(name):
        return "<div>{0}</div>".format(func(name))
    return func_wrapper

With the basic approach, decorating get_text would be along the lines of

При стандартном подходе, чтобы задекорировать всеми тремя нужно выполнить такой код:

get_text = div_decorate(p_decorate(strong_decorate(get_text)))

Однако при использовании синтаксиса декоратора Python это можно написать гораздо проще и понятней.

@div_decorate
@p_decorate
@strong_decorate
def get_text(name):
   return "lorem ipsum, {0} dolor sit amet".format(name)

print get_text("John")

# Outputs <div><p><strong>lorem ipsum, John dolor sit amet</strong></p></div>

Декораторы с аргументом.

Что если нам нужно менять тег, в который мы помещаем вывод декорируемой функции из примеров выше.

Очевидно, для этого тег необходимо передавать в качестве параметра декоратору:

def decorator(opentag,closetag):

    def real_decorator(decfunc):

        def wrapper(name):

            return opentag+' '+ decfunc(name) +' '+closetag

        return wrapper


    return real_decorator

В таком случае, при декорировании, передаем эти параметры:

@decorator('<h1>','</h1>') 
def myf(name):
    return name


print myf('Dima')
Basics of Python and Django. -> Рекурсивный коктейль.

Рекурсивный коктейль.

Состоит из 30% воды 20% спирта и 50% рекурсивного коктеля :-).

print("Making recousion coctail!!!")

def make(water,alcohol):
    mix = 0
    mix = mix + (water*30)
    mix = mix + (alcohol*20)
    mix = mix + (make(water,alcohol)*50)
    return mix

print(make(4,5))

RuntimeError: maximum recursion depth exceeded

Добавим счетчик итерации и ограничим рекурсию.

def make(water,alcohol,cnt):
    cnt += 1
    mix = 0
    mix = mix + (water*30)
    mix = mix + (alcohol*20)
    if cnt >10:
        return mix
    mix = mix + (make(water,alcohol,cnt)*50)
    return mix

cnt = 0    
print(make(4,5,cnt))
Basics of Python and Django. -> Веб-сервер на web.py

WEB.PY

Установка

pip install web.py

Использование.

Простейшее веб приложение сервер.

import web

urls = (
    '/', 'hello'
)

app = web.application(urls,globals())#1

class hello:
    def GET(self):
        return "Hello world!"

if __name__ == "__main__":
    app.run()

1 - globals это функция, возвращающая словарь который содержит все переменные, определенные в глобальном прострастве.

Если она вызывается из функции, то возвратит словарь пространства того модуля, где ф-ция была определена а не где ее вызвали.

Запуск на порту 8989.

python server.py 8989

Определение параметра в URL.

import web

urls = (
    '/(.*)', 'hello'
)
app = web.application(urls, globals())

class hello:        
    def GET(self, name):
        if not name: 
            name = 'World'
        return 'Hello, ' + name + '!'

if __name__ == "__main__":
    app.run()

web.py

URL обработака (роутинг)

urls = (
    '/', 'index',
    /news', 'news',
    '/view_news/(\d+)', 'view_news',

)

class index: 
    ...
class news: 
    ...
class view_news: 
    def GET(self, id):
        """ View single news """
        post_id = int(id)

Templating

Let’s make a new directory for our templates (we’ll call it templates). Inside, make a new file whose name ends with HTML (we’ll call it index.html). Now, inside, you can just write normal HTML

<em>Hello</em>, world!

Or you can use web.py’s templating language to add code to your HTML:

$def with (name)

$if name:
    I just wanted to say <em>hello</em> to $name.
$else:
    <em>Hello</em>, world!

Under the first line, add:

import web
render = web.template.render('templates/')



....
def GET(self, name):
    return render.index(name)

Databasing

Installing MySQLdb

pip install MySQL-python

First you need to create a database object.

db = web.database(dbn='mysql', user='username', pw='password', db='dbname')


def GET(self, name):
    users = db.select('user')
    out = 'Hello '
    for u in users:
        out = out+' '+u.name
    return out

Output

Hello  dmitry sergey

Insert records

class insert:        
def GET(self, name):
    n = db.insert('user', name=name)
    return 'Ok'
Basics of Python and Django. -> Домашнее задание. Игра Очко.

Домашнее задание.

Написать консольную игру “Очко”.

Правила.

Игроку предлагается выбрать карту (элемент из списка колоды).

Колода имеет вид:

koloda = [2,3,4,5,6,7,8,9,10,11.... и т.д.]

Перед началом игры колода перемешивается.

Игроку последовательно выдается первый элемент карты из списка, при этом элемент удаляется из колоды.

Далее игрок может взять еще карту или прекратить. В случае набора 21 очков либо при прекращении набора вступает в игру компьютер и берет последовательно карты до достижения 18 очков, либо до счета, превышающего счет игрока.

Если компьюьер набирает 18 очков, он прекращает набор и определяется победитель.

Если один из игроков набирает больше 21 он считается проигравшим.

Выигрывает тот у кого больше очков.

Basics of Python and Django. -> Домашнее задание. Импорт компаний.

Импортировать базу компаний.

Сайт flagma.kz

Создать проект Django c такой командой.

from django.core.management.base import BaseCommand, CommandError

from app.models import Person, MainDocuments, Person2Document, Company, City, Person2Company, Import
import re
import psycopg2
import bs4
import requests
import time

    def parse_company(c):
        try:
            city = City.objects.get(name_ru__icontains=c.city_text)
            c.city = city
            c.save()
        except:
            print('City not found')

        namear = c.faunders_text.split(',')
        p = Person()
        p.raw_name = namear[0]
        p.role = namear[1]
        p.source = 'flagma.kz'
        p.save()
        p.parse()

        p2c = Person2Company()
        p2c.company = c
        p2c.person = p
        p2c.save()

        print('Saving person %s' % namear[0])



    class Command(BaseCommand):

        def handle(self, *args, **options):
            print('Importing.')   
            Company.objects.all().delete()
            Person.objects.filter(source='flagma.kz').delete()
            Person2Company.objects.all().delete()
            urls = []
            for cnt in range(1,1000):
                urls.append('https://flagma.kz/kompanii-k-%s.html' % cnt)

            for url in urls:
                print("Importing %s" % url)
                time.sleep(1)
                i = Import()
                i.url = url
                i.save()
                rez = requests.get(url)
                soup = bs4.BeautifulSoup(rez.text, 'html.parser')
                items = soup.findAll('div',{"class": "page-list-item-info"})
                for i in items:
                    name = i.find('a').text
                    location = i.find('span',{"itemprop": "location"}).text
                    boss = i.find('span',{"itemprop": "employee"}).text
                    arrboss = boss.split(',')
                    c = Company()
                    c.name_ru = name
                    c.name_kz = name
                    c.faunders_text = boss
                    c.city_text = location
                    c.save()
                    parse_company(c)
                    print('Saving.....%s' % name)

Создать модель данных для того, чтобы эта команда работала и заполняла таблицу.