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

Python

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

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

Ссылки (27.03.2016) #

«  ‹  1  2  следующая ›  последняя »

Пенсионная реформа (06.02.2019) #

Была у меня одна простенькая задачка - определять по дате рождения пенсионер человек или нет.

До недавнего времени отлично работало следующее решение: из текущей даты вычитаем 60 и 55 лет и получаем минимальную дату рождения мужчины и женщины, для которых наступил пенсионный возраст. После этого сравниваем эту дату с датой рождения конкретного человека и определяем пенсионер он или нет. Ниже приведён код данного решения (только обсуждаемая часть):

import datetime

now_date = datetime.date.today() # Текущая дата (без времени)
cur_year = now_date.year # Год текущий
men_retirement_date = now_date.replace(year = cur_year - 60)
women_retirement_date = now_date.replace(year = cur_year - 55)

...

for people in list:
    if isMale:
        isPensioner = brs_date < men_retirement_date
    else:
        isPensioner = brs_date < women_retirement_date    

Решение было всем хорошее, кроме одного момента - при вычитании годов (для определения даты выхода на пенсию) не учитывалось, что в високосные годы в феврале на 1 день больше, поэтому при запуске 29 февраля программка вылетела с ошибкой преобразования даты.

Теперь же, после принятия новой пенсионной реформы, появился переходный период и пришлось писать отдельную функцию для того же функционала:

import datetime

def isPensioner(isMale, dtBirth):
    """Вычисляет является человек пенсионером или нет.

    Параметры:
      isMale - пол: для мужчин - True, для женщин - False
      dtBirth - дата рождения"""

    is_pensioner = False # пенсионер?
    retirement_age = 55
    addhalfyear = False

    retirement_date = dtBirth
    birth_year = dtBirth.year
    birth_month = dtBirth.month
    birth_day = dtBirth.day

    if isMale:
        if birth_year <= 1958:
            retirement_age = 60
        elif birth_year == 1959:
            retirement_age = 60
            addhalfyear = True
        elif birth_year == 1960:
            retirement_age = 61
            addhalfyear = True
        elif birth_year == 1961:
            retirement_age = 63
        elif birth_year == 1962:
            retirement_age = 64
        else:
            retirement_age = 65
    else: # Female
        if birth_year <= 1963:
            retirement_age = 55
        elif birth_year == 1964:
            retirement_age = 55
            addhalfyear = True
        elif birth_year == 1965:
            retirement_age = 56
            addhalfyear = True
        elif birth_year == 1966:
            retirement_age = 58
        elif birth_year == 1967:
            retirement_age = 59
        else:
            retirement_age = 60

    # прибавим к дате рождения пенсионный возраст
    if birth_day > 28:
        retirement_date = retirement_date.replace(day = 28)
    retirement_date = retirement_date.replace(year = birth_year + retirement_age)
    if addhalfyear:
        if birth_month > 6:
            retirement_date = retirement_date.replace(year = birth_year + retirement_age + 1)
            retirement_date = retirement_date.replace(month = birth_month + 6 - 12)
        else:
            retirement_date = retirement_date.replace(month = birth_month + 6)
    if birth_day > 28:
        nday = 28
        while nday < birth_day:
            nday += 1
            try:
                retirement_date = retirement_date.replace(day = nday)
            except ValueError:
                pass

    is_pensioner = now_date > retirement_date
    return is_pensioner

for people in list:
    if isMale:
        isPensioner = isPensioner(True, brs_date)
    else:
        isPensioner = isPensioner(False, brs_date)    

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

PS Для прибавления 6 месяцев к указанной дате на StackOverflow предложили использовать отдельную библиотеку dateutil, но мне показалось, что в данном случае это было бы избыточно, да и лишнюю зависимость "тащить" не хотелось. Ниже предложенное там решение:

from datetime import date
from dateutil.relativedelta import relativedelta

six_months = date.today() + relativedelta(months=+6)

Напомню, что предварительно библиотеку надо установить: pip install python-dateutil

Python: коллекции (05.02.2017) #

Наткнулся на интересную для начинающих изучать Python серию статей посвященную коллекциям.

  • Часть 1: классификация, общие подходы и методы, конвертация
  • Часть 2: индексирование, срезы, сортировка
  • Часть 3: объединение коллекций, добавление и удаление элементов
  • Часть 4: Все о выражениях-генераторах, генераторах списков, множеств и словарей

Рекомендую к прочтению.

Произвольные коды (02.01.2016) #

На днях возникла необходимость получить 3,5 тысячи уникальных, но произвольных 12 значных цифровых кодов. Решений, очевидно, можно придумать массу, но скрипт на Python показался самым простым:

#-*- coding: utf-8 -*-
import random as r
codes = []
with file('oo.csv', 'w+') as f:
    while len(codes) < 3500:
        # cod = '11' + str(r.randint(int('1'*9), int('9'*9)))
        cod = '11' + ('0'*5 + str(r.randint(0, int('9'*5))))[-5:] 
        if cod not in codes:
            codes.append(cod)
            f.write(cod + '\n')

На всякий случай зарезервировал первые две позиции для "типа" - мало ли потом понадобится ещё что-то аналогичное, а также добавил (не в этом скрипте) в конец контрольный разряд (или число), который рассчитал по методу Луна (Lunh, см. Wikipedia).

UPD: Немного скорректировал скрипт: было решено сократить длину кода до 8 знаков, тогда для увеличения количества кодов решил произвольные составляющие искать с нуля, а не со всех единиц, как в первоначальном варианте, что потребовало выравнивания нулями слева. Первоначальный вариант тоже сохранил - закомментированная строка.

Тест на знание Python (23.05.2015) #

Коллега по работе прислал интересный тест на знание Python: https://alexbers.com/python_quiz/.
Тест в основном ориентирован на знание тонкостей и особенностей языка и классического интерпретатора.

Тест я, к сожалению, прошёл плохенько, так как мало практики и в нескольких местах поторопился и плохо подумал.
Интересующимся Python рекомендую попробовать пройти.

UPD: А вот коллега тест прошел очень хорошо - в 10 лучших! Говорит, что главное не торопиться и внимательно смотреть задание.

Python 2.7.x и 3.x (обзор различий) (08.08.2014) #

Коллега по работе прислал ссылку на интересное сравнение посвященное различиям второй и третьей версии Python.

Отдельно хотелось бы отметить два коварных момента, которые выявить будет довольно сложно, так как ошибки выполнения они не вызовут (просто программа будет работать не корректно):

Транспортный налог (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).

«  ‹  1  2  следующая ›  последняя »

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