Главная страница  Карта сайта  Печать  Написать письмо  RSS
Войти
Кнопка открытия главного меню
Персональный сайт
Стеллецкого Владимира
Обновлено: 22.12.2023 г.

Python

В 2009 году я решил изучить ещё какой-нибудь язык программирования. После анализа текущего выбора языков программирования я остановил свой выбор на Python или Ruby. После ещё некоторых колебаний склонился всё же к Python. Может быть когда-нибудь и до Ruby руки дойдут.

Если обнаружите ошибки или сможете предложить более "правильное" решение размещённых здесь задач, или же какую-то задачку для решения - пишите, буду очень признателен.

Ссылки (18.12.2019) #

« первая   ‹ предыдущая   1   2   3   ›  »

Транспортный налог (18.10.2012) #

В связи с обсуждаемым изменением ставки транспортного налога в г. Москве, набросал крошечный скрипт для его расчета по текущим и обещанным (новым) ставкам:

#-*- coding: utf-8 -*-
tnc = list()
tnc.append((0, 0, 0))
tnc.append((70, 7, 12))
tnc.append((100, 20, 25))
tnc.append((125, 30, 35))
tnc.append((150, 38, 45))
tnc.append((175, 45, 50))
tnc.append((200, 60, 65))
tnc.append((225, 75, 75))
tnc.append((250, 150, 150))
tnc.append((410, 150, 300))

while True:
    title = u'Введите количество лошадиных сил (или ENTER для выхода): '
    print title
    title_e = 'Enter the amount of horsepower (or ENTER to exit): '
    s = raw_input(title_e)
    if s == '':
        break
    x = int(s)
    for c in tnc:
            if x > c[0]:
                    c1 = c
            else:
                    break
    print u'Транспортный налог для %s "лошадей" был %s р., станет %s р. (+%s р.) \n' % (x, x*c1[1], x*c1[2], x*(c1[2] - c1[1]))

Pythonic (15.03.2012) #

Начал читать книгу Дэвида М. Бизли - Python. Подробный справочник. Идёт не очень быстро, зато, кажется, стал проникаться философией питона - pythonic (подробнее здесь или здесь). Действительно хочется красивых и элегатных решений, тем более что для этого все предоставлено.

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

History к таблице (24.01.2010) #

Довольно часто стала возникать задача сделать историю изменений для какой-либо таблицы на MS SQL-сервере. У нас это реализуется путем создания дополнительной таблицы, содержащей все поля базовой + собственный идентификатор (H_ID) и тип операции вставка/обновление/удаление. Для записи в неё на базовой таблице создаются три триггера: after insert/update/delete, в которых осуществляется копирование данных. Делать каждый раз "руками" мне было лень, и я написал следующий скрипт:

# -*- coding: utf-8 -*-
import _mssql

import sys
class error:
    def write(self, text):
        open('error.log', 'a').write(text)
sys.stderr = error()

print u"2009 Stelletsky V. "
print u"Таблицы истории и триггеров"
print
#t = u"Название таблицы: "
tbname = raw_input("Table Name: ")
if tbname == "":
    sys.exit(1)

conn = _mssql.connect(server='servername', user='username', password='password', database='databasename')
# проверка существования таблиц
st = "SELECT * FROM INFORMATION_SCHEMA.TABLES "
st = st + "WHERE TABLE_NAME IN ('" + tbname + "', '" + tbname + "_H') ORDER BY TABLE_NAME"
conn.execute_query(st)
i = 0
for row in conn:
    if tbname <> row['TABLE_NAME'] and i==0:
        print u"Таблица %s не найдена!" % (row['TABLE_NAME']) 
        raw_input("Done")
        sys.exit(1)
    if tbname + "_H" == row['TABLE_NAME'] and i==1:
        print u"Таблица %s уже создана!" % (row['TABLE_NAME']) 
        raw_input("Done")
        sys.exit(1)
    i = i + 1
if i == 0:
    print u"Таблица '%s' не найдена!" % (tbname) 
    raw_input("Done")
    sys.exit(1)

print u"Создание таблицы %s" % (tbname + '_H')
st =      "SELECT * FROM INFORMATION_SCHEMA.[COLUMNS] c "
st = st + "WHERE c.TABLE_NAME = '" + tbname + "' "
conn.execute_query(st)
st = "CREATE TABLE [dbo].[" + tbname + "_H] ("
st = st + " [H_ID] int IDENTITY(1, 1) PRIMARY KEY NOT NULL, "
st = st + " [Operand] varchar(1) NOT NULL "
st_f = ""
for row in conn:
    st = st + ", "
    st_f = st_f + ", [" + row['COLUMN_NAME'] + "]"
    st = st + " [" + row['COLUMN_NAME'] + "] " + row['DATA_TYPE'] 
    if row['CHARACTER_MAXIMUM_LENGTH'] <> None:
        st = st + "(" + str(row['CHARACTER_MAXIMUM_LENGTH']) + ") "
    if row['COLLATION_NAME'] <> None:
        st = st + "COLLATE " + row['COLLATION_NAME']
    if row['IS_NULLABLE'] == "NO":
        st = st + " NOT"
    st = st + " NULL"
st = st + ")"        
conn.execute_non_query(st)
print u"Создание триггеров"
i = 0
while i < 3:
    if i == 0: 
        st_o = "I"
        st_op = "INSERT"
        st_from = "inserted"
    elif i == 1:
        st_o = "U"
        st_op = "UPDATE"
    elif i == 2:
        st_o = "D"
        st_op = "DELETE"
        st_from = "deleted"
    st =      "CREATE TRIGGER [dbo].[" + tbname + "_A" + st_o + "] ON [dbo].[" + tbname + "] "
    st = st + "WITH EXECUTE AS CALLER "
    st = st + "FOR " + st_op + " "
    st = st + "AS "
    st = st + "BEGIN "
    st = st + "  INSERT INTO dbo.[" + tbname + "_H] "
    st = st + "  (Operand" + st_f + ") "
    st = st + "  SELECT "
    st = st + "  '" + st_o + "'" + st_f + " "
    st = st + "  FROM " + st_from + " "
    st = st + "END "
    conn.execute_non_query(st)
    i = i + 1
    
raw_input("Done")

Создание таблицы на MSSQL-сервере (13.11.2009) #

В связи со сменой работы, пропала возможность пользоваться конструктором для создания таблиц в БД. Решил реализовать необходимый мне сейчас функционал на Python. А заодно попробовать запрограммировать GUI с помощью библиотеки PyQt4. Пока реализовано только "консольное" приложение, создающее таблицу на MS SQL сервере с некоторым количеством "стандартных" полей (ID, Parent_ID, Del, Role_ID, DateChange). Количество и названия создаваемых полей легко изменить:

# -*- coding: utf-8 -*-
import _mssql

import sys
class error:
    def write(self, text):
        open('error.log', 'a').write(text)
sys.stderr = error()

print u"2009 Stelletsky V. "
print u"Создание таблицы"
print
#t = u"Название таблицы: "
tbname = raw_input("Table Name: ")
if tbname == "":
    sys.exit(1)

needpid = raw_input("Need Parent_ID (Y/N): ")
print u"Создание таблицы", tbname
# запрос на создание таблицы
st = "CREATE TABLE "
st = st + "[dbo].[" + tbname + "] ("
st = st + "[ID] int IDENTITY(1, 1) NOT NULL PRIMARY KEY, "
if needpid=="y" or needpid=="Y":
    st = st + " [Parent_ID] int DEFAULT 0 NOT NULL, "
st = st + " [Del] bit DEFAULT 0 NOT NULL, "
st = st + " [Role_ID] int NULL, "
st = st + " [DateChange] datetime NULL"
st = st + ")  "

try:
    conn = _mssql.connect(server='servername', user='username', password='password', database='databasename')
    conn.execute_non_query(st)
except _mssql.MssqlDatabaseException,e:
    if e.number == 2714 and e.severity == 16:
        print u"Tаблица", tbname, u"уже существует!"
    else:
        raise # re-raise real error
finally:
    conn.close()
raw_input("Done")

Парсер характеристик прицепов (04.09.2009) #

Появилась необходимость в прицепе. Выбирая наткнулся на сайт с огромным выбором, но на нём все прицепы для грузов свалены в одну кучу. Решил написать python-скрипт для разбора в Excel читаемый вид характеристик прицепов для последующего анализа и выбора. Заодно удалось потренироваться в программировании на Python. Все необходимые файлы, включая исходный текст программы и уже обработанный Excel с характеристиками прицепов можно найти здесь (27 kb).

Удаление PHPSESSID (14.04.2009) #

Если при построении моего сайта происходит какая-либо ошибка, то информация о ней сохраняется в таблицу err. Часто в ссылках встречается PHPSESSID, который мне не нужен и несколько мешает просматривать сообщения. Вот простенький скрипт убирающий его:

#-*- coding: utf-8 -*-
import MySQLdb

print u"2009 Stelletsky V. "
print u"Удаление PHPSESSID из таблицы errors"
print
# Соединение с БД
db = MySQLdb.connect(host='host', user='user', passwd='pass', db='database')  
db.set_character_set('utf8')
query = 'SELECT ID, URL FROM `err`'
cursor = db.cursor()
cursor.execute(query)
result = cursor.fetchall()
k = k1 = 0
for record in result:
    s = unicode(record[1], 'utf-8')
    n = s.find('PHPSESSID')
    k+=1
    if n >0:
        k1+=1
        cursor.execute("""UPDATE `err` SET Message = %s WHERE ID = %s """, [(s[:n-1] + s[n+42:]), record[0]])
print u"Всего " + str(k) + u", обработано " + str(k1)
raw_input("Done")

Рисование графика (03.11.2009) #

Постоянные посетители знают, что на странице О сайте можно посмотреть график запросов страниц сайта за последние несколько месяцев. Для его получения я каждый месяц в ручную выполнял запрос в базу данных сайта, полученное значение переносил в Excel, потом диаграмму с графиком сохранял в формате png, и закачивал на сайт. Получился прям целый ритуал, который мне порядком надоел, и я решил его автоматизировать, а раз уж взялся за изучение Python, то и реализовать решил на нём. Вот что у меня получилось.

#-*- coding: utf-8 -*-
import MySQLdb
import aggdraw
from PIL import Image, ImageDraw, ImageFont
mon = (u"Янв", u"Фев", u"Мар", u"Апр",
       u"Май", u"Июн", u"Июл", u"Авг",
       u"Сен", u"Окт", u"Ноя", u"Дек")
graphcolors = ("red", "green", "blue")
y_steps = (200, 500, 1000, 2000, 5000, 10000)

xcw = 50 # ширина ячейки

# Соединение с БД
db = MySQLdb.connect(host='host', user='user', passwd='pass', db='database')
query = 'SELECT `Counter` FROM `stat`'
cursor= db.cursor()
cursor.execute(query)
result = cursor.fetchall()
maxval = 0
minval = 1000000
for record in result:
    if record[2] > maxval:
        maxval = record[2]
    if record[2] < minval:
        minval = record[2]
# временно отключаем ограничение шкалы графика по минимальному значению
minval = 0
delta = (maxval - minval) / 10
# округляем до большего кратного
for i in y_steps:
  if delta < i:
    delta = i
    break
# диапазон для вывода графика
min_gr = 0
for i in range(100):
    if i*delta < minval:
       min_gr = i*delta
    if i*delta > maxval:
       max_gr = i*delta
       break
lcount = i
# получение масштаба по Y
m_y = 430.0 / (max_gr - min_gr)
# рисование
#image = Image.new("RGBA", (660,480), (255,255,255,255))
image = Image.new("RGB", (660,480), "white")
draw = aggdraw.Draw(image)
draw.setantialias(False)
apen = aggdraw.Pen("#999", 1)
apen1 = aggdraw.Pen("#ddd", 1)
draw.line((50,20,50,450), apen)
draw.line((50,450,650,450), apen)
arial = aggdraw.Font('#333', "C:\WINDOWS\Fonts\arial.ttf", 12)
# Черточки и подписи на оси X
for i in range(13):
    draw.line(((50+xcw*i),446,(50+xcw*i),454), apen)
    if i > 0:
        draw.line(((50+xcw*i),450,(50+xcw*i),20), apen1)
    if i < 12:
        draw.text((65+xcw*i, 455), mon[i], arial)        # подписи
#draw.line(((50+50*12),446,(50+50*12),454), apen)

# Рисование чёрточек на Y
for i in range(lcount+1):
    draw.line((48,(450-delta*m_y*i),52,(450-delta*m_y*i)), apen)
    if i > 0:
        draw.line((50,(450-delta*m_y*i),650,(450-delta*m_y*i)), apen1)
    st = str(min_gr+i*delta)
    a = draw.textsize(st, arial)
    draw.text(((45 - a[0]), (443-delta*m_y*i)), st, arial)

# Рисование  графика
draw.setantialias(True)
grColor = -1
x = y = 1
pyear = -1     # предыдущий год
px = py = -1  # предыдущие координаты
for record in result:
    # настройка цветов
    if int(record[0])<> pyear:
        pyear = record[0]
        grColor += 1
        px = py = -1
        abrush = aggdraw.Brush(graphcolors[grColor])
        apen = aggdraw.Pen(graphcolors[grColor], 2)
    x = 25 + xcw * int(record[1])
    y = 450 - (int(record[2]) - min_gr) * m_y
    draw.rectangle((x-2, y-2, x+2, y+2), apen, abrush)
    # соединяем с  предыдущей точкой
    if px <> -1 and py <> -1:
        draw.line((px, py, x, y), apen)
    px = x
    py = y
#    print record[0], "-->", record[1], "-->", record[2]
print minval, maxval, delta, min_gr, max_gr, lcount, m_y

draw.flush()
image.save("test.png", "PNG")
raw_input("Done")

Здесь приведён не окончательный вариант скрипта. Я его ещё дописываю, так как есть некоторые недостатки:

  1. Графику не хватает легенды;
  2. Скрипт не умеет загружать файл на сервер. Возможно загрузку на FTP делать не буду, а просто размещу скрипт на web-сервере.
  3. Получаемая картинка большая по объему (около 30кб), так как указана палитра в 256 бит. Но само изображение можно без видимой потери качества конвертировать до глубины цвета 4 бита, тогда изображение становится около 5кб, что приятно.

Из-за использования сторонних библиотек для работы с графикой и соединения с MySQL, пришлось отказаться от использования последней версии Python и ограничится версией 2.5.4. Несмотря ни на что, данный скрипт упростил мне работу. Новый вариант графика можно просмотреть на странице о сайте, а старый "ручной" вариант здесь.

Комментарии

swi, www (06.03.2009)
Да, но на графиках я января и февраля так и не увидел...
Странно. Возможно браузер отобразил картинку из кэша. На новом графике данные за январь и февраль показаны красным.

« первая   ‹ предыдущая   1   2   3   ›  »

  Вы 19 776 посетитель этой странички
с 05 марта 2009 года
© http://svv-home.ru
О сайте