Как стать автором
Обновить

Комментарии 15

Я правильно понял, что в windows вы используете функцию из модуля datetime, в Linux используете совершенно другую функцию и libc с таким же названием, и вы в шоке от того, что они ведут себя по-разному?
Не очень. В силу некоторых причин на серверах и локальных машинах стояли разные системы и я был не в шоке, но несколько удивлён, видя при воспроизведении, что в одном случае у нас падает с трэйсбеком, а в другом ничего не падает. Когда я разобрался что в разных системах вызываются разные функции, то всё стало на свои места.
а почему вы под линукс не используете тот же datetime.strptime?
Не могу ответить на этот вопрос, но могу предположить, что это сделано было для ускорения работы, так вызываться сама функция может большое количество раз.

Это классический пример того, как ускорение кода костылями ведет к багам. Питон — это не про скорость работы, а про удобство разработки. С таким подходом аннулируются все его преимущества. Если так важна скорость, писали бы сразу на Гоу, например. Не ваш огород, просто мысли вслух.

Согласен, питон — не про скорость работы, а про скорость/удобство разработки. Но представьте что нам надо вызывать функцию обработки даты большое количество раз. Я решил измерить сколько времени у нас займёт выполнение скриптов где strptime() вызывается 10000 раз, результаты под спойлером.


Сравнение скорости работы

1) $ cat python_strptime.py


from datetime import datetime

date_str = "30-10-2016 16:18"
format_str = "%d-%m-%Y %H:%M"

for i in xrange(1, 10001):
    datetime.strptime(date_str, format_str)

Результат:
$ time python python_strptime.py


real    0m0.327s
user    0m0.320s
sys     0m0.007s

2) $ cat c_strptime.py


from ctypes import *

libc = CDLL('libc.so.6')

class TM(Structure):
    _fields_ = [
        ("tm_sec", c_int),
        ("tm_min", c_int),
        ("tm_hour", c_int),
        ("tm_mday", c_int),
        ("tm_mon", c_int),
        ("tm_year", c_int),
        ("tm_wday", c_int),
        ("tm_yday", c_int),
        ("tm_isdst", c_int)
    ]

tm_struct = TM()

strptime = libc.strptime
strptime.restype = c_char_p

date_str = "30-10-2016 16:18"
format_str = "%d-%m-%Y %H:%M"

for i in xrange(1, 10001):
    strptime(date_str, format_str, pointer(tm_struct))

Результат:
$ time python c_strptime.py


real    0m0.056s
user    0m0.047s
sys     0m0.007s

А что касается Гоу — да, пожалуй соглашусь, что для скорости можно и на нём писать. Но когда это было написано про Гоу мало что было известно. Но, как я сказал раньше, что код писался разными командами это, по факту, была обёртка над датой, которая использовалась в скриптах.

Ну ускорили вы эту функцию. Что-то такое типа четверти микросекунды на вызов, если я правильно посчитал. Если вы не обсчитываете миллиардами какие-нибудь записи из логов или ещё какие источники текста с датами — то ИМХО грошовое ускорение ценой переусложнённого кода и вот таких вот проблем.

Как мне кажется, мораль этого случая в том, что если две разные функции делают одно и то же, это ещё не значит, что между ними нет каких-нибудь мелких различий, которыми можно прекрасно стрельнуть себе в ногу. Примерно как print() и file_like.write() c имплицитным '\n' и без оного.

Зачем лезть в кишки libc.so, когда есть обычный способ, да еще с защитой от неверного формата?

Ответил выше что не могу ответить на этот вопрос. Добавлю только что этот код писался другой командой и какую функцию где вызывать решали они.
Хуже чем проверять значение функции, так это писать такие функции, которые требуют проверки.
Так мораль какая? Как правильно разрабатывать, чтобы защититься от того, что кто-то вызвал не ту функцию?

1. Проверять все на каждом шагу? Есть риск, что код сильно раздует и он станет хрупким и малоподдерживаемым.

2. Использовать строгую статическую типизацию?

3. Делать на все unittest`ы, чтобы проверялись и валидные и невалидные данные?

Я бы ещё четвёртым пунктом дописал "Внедрить ревью кода?" :) Но вот как правильно разрабатывать и как бороться с подобными ошибками это, на мой взгляд, тема для отдельного разговора. Мне же просто хотелось поделиться опытом и показать что результаты некоторых багов могут быть замечены только пользователем и хорошо, если это не будет критической ситуацией.

Ждем статью про ревью кода. Тут пока говорить не о чем.
Подрядчики могли знать и умолчать, и могли НЕ знать и просто скосячить. Тут слишком много переменных. И непонятной остается ваша личная роль в проекте — вы не в желании делать код ревью, но публично высмеиваете работу подрядных программистов, через раз отписываясь «я не могу ответить на этот вопрос».

С чего Вы взяли, что я не желаю делать ревью кода? Где я это говорил? Юниттесты, ревью кода, парное программирование — разве это не способы сократить ошибки? На мой взгляд, это вещи которые следует внедрять, а вот что из этого применять на практике, когда и как применять — это достаточно большой вопрос и не для одного комментария.


Почему Вы решили, что это писали подрядчики и что я кого-то высмеиваю? Я здесь не говорил, что это писали подрядчики. Я только говорил, что разными вещами занимались разные команды, не более. А был ли это косяк или что иное и были ли виноватые, обсуждать в публичном месте я не считаю уместным. Так же существуют такие понятия как коммерческая тайна, "внутренняя кухня" и я стараюсь формулировать так, что бы было понятно, что я хочу сказать, но при этом не разглашать детали.


И, также, я не могу согласиться, что фраза «я не могу ответить на этот вопрос» была "отпиской" и, тем более, через раз — я это написал 2 раза в 2 разных комментариях, опубликованных в одно и то же время, в следствие чего авторы не могли видеть комментарии друг друга. И если Вам показалось, что я кого-то высмеиваю этой фразой — прощу прощения. Это была просто констатация факта, что я не знаю почему было принято такое решение, но зная принцип работы могу сделать предположение.


UPD. Промахнулся, ответ на комментарий

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории