Comments 53
Читайте больше на русском, будете встречать чаще. Нет ничего плохого или некрасивого в том, чтобы писать названия на родном языке.
Как вы изящно над собой же и пошутили в контексте нашего разговора!
Если однажды русский перестанет быть для вас сложным, приходите сюда, перечитайте что получилось и посмейтесь вместе со мной.
Если же вы используете источники только на русском языке… это наверное очень круто, быть всегда на шаг позади? Зачем это искусственное огораживание от свежей информации? Зачем все эти усложнения с локализацей? Лень? Нежелание менять привычки? Ненависть ко всему нерусскому?
К автору поста у меня претензий нет, мне все равно как он написал, хотя и читается так себе. Но вот к таким как вы, лучше не раздавать людям советов.
Ваша ошибка в том, что вы принимаете за традицию кратковременный трындец, который случился со страной в Перестройку, когда на нас хлынул поток нелокализованных товаров и каждое нерусское слово в одночасье стало весомее русского.
Если же вы посмотрите на журналы и статьи, издававшиеся до этого печального времени, вы увидите, что всё писали на русском, как и должно быть — вот это и есть традиция.
Ненависти ко всему нерусскому у меня нет, разумеется, как и ко всему русскому. На английском я буду писать по-английски, на русском — по-русски.
Если же вы используете источники только на русском языке… это наверное очень круто, быть всегда на шаг позади?
Вы что-то перепутали. Я вам посоветовал читать побольше по-русски. Не пользовать источниками только на русском, а просто больше читать по-русски.
Но вот к таким как вы, лучше не раздавать людям советов.
Вы какие-то скоропалительные выводы делаете. Попробуйте задуматься, откуда в вас столько агрессии и уверенности, что вы лучше разбираетесь в традициях. Вы их изучали или что? Или вы строите свои убеждения на принципе «это все знают»?
Как будто для вас написал: http://grishaev.me/eng-terms
Я написал именно в привычном стиле.
Кроме того, заимствования из Go лежат рядом с заимствованиями из Haskell. pcall — интересно, но в одной библиотеке с дженериками? А вообще знающие люди пишут свой контекст «with as», если надо избежать множественных «try, except».
Интересно, как они это пишут? Примеры?
class SocketContext:
def __init__(self, addr, port):
self.sock = socket.socket()
self.sock.connect((addr, port))
def __enter__(self):
return self.sock
def __exit__(self, type, value, tb):
print_tb(tb)
sock.close()
return True
Это менеджер контекста, если далее
with SocketContext(«example.com», 80) as sock:
# Do smth
Срабатывает __init__(«example.com», 80), затем __enter__ передаёт значение в sock (разумеется можно несколько, я в последний раз передавал функцию, чтобы получить замыкание), при ЛЮБОМ выходе (исключение, корректное завершение, return внутри блока) из контекста вызывается __exit__, если было исключение, то его можно обработать как tb, если __exit__ вернёт False, то вроде бросится исключение наружу.
Вспоминаем известный with open(name) as fin: — суть в том, что что бы мы не делали, файл будет закрыт после выхода из контекста.
Спасибо, я знаю, как работает контекстный менеджер. Мне не ясно, как он позволит, цитирую, "избежать множественных «try, except»".
try:
return (func(*args, **kwargs), None)
except Exception, e:
return (e, None)
Для единообразной арифметики, это, пожалуй, сэкономит код, но если ты хочешь «деструктор», который бы освобождал ресурсы/закрывал дескрипторы и по-разному обрабатывал разные ошибки, то всё равно надо каждый писать что-то кастомное. В сетях и парсинге всякого текста приходится как раз таки «закрывать дескрипторы». И опять таки это 7 строчный декоратор, который не лень и самому написать.
Например, использовать внутри стандартные циклы с условиями вместо мапов и редьюсов, чтобы облегчить понимание тем, кто не знаком с ФП.
Я, конечно, не гуру Python, но мне кажется, что это несколько не python-way, и мне казалось, что обычно стараются наоборот писать декларативно.
Сам я больше использую C# и стараюсь, где возможно, использовать лямбды и LINQ (не перебарщивая, конечно). ИМХО, декларативный стиль куда нагляднее
Используя деструктивный синтаксис, можно распаковать результат на уровне сигнатуры.
Whoops

Я вот лично считаю, что тоже давольно давно работаю с питоном, лет семь, это давно по-вашему? Давнее вашего?
Знатная солянка, узнал много нового, спасибо. В особенности monadic pipeline — ваще огонь )
А вот такое легаси я бы переписал на "длинно и некрасиво":
f.L("abc").map(ord).map(str).reversed().join("-")
'99-98-97'
foo = [ord(x) for x in 'abc']
'-'.join(str(x) for x in foo[::-1])
'99-98-97'
Поинт в том, что если это есть в питоне, этого не надо объяснять новому человеку, а если он этого не знает, то обязан научиться. Ну и еще ваши типы и их методы могут быть сильно медленнее встроенных:
def test_f():
f.L("abc").map(ord).map(str).reversed().join("-")
def test_p():
foo = [ord(x) for x in 'abc']
'-'.join(str(x) for x in foo[::-1])
print(timeit.timeit(test_f, number=1000), timeit.timeit(test_p, number=1000))
0.0127332210541, 0.00602507591248
И еще я думал так тоже работать будет:
f.p_num(Decimal(10)), f.p_num('1')
False, False
Decimal(10) + 4, '1'.isdigit()
Decimal('14'), True
Хотя, конечно, вы об этом не писали.
Да, и спасибо за вклад в Open Source. Это важно и нужно.
Спасибо за полезный отзыв.
Дело в том, что быстрее лист-компрехеншена в Питоне ничего быть не может. Это самый быстрый способ обработки коллекций. Над скоростью нужно поработать.
Не согласен с тем, что вариант с компрехеншеном удобней. На мой взгляд, цепочка методов лучше описывает логику.
Насчет предикатов — да, Decimal тоже нужно учесть. А строка не долна проходить проверку на число.
foo = [ord(x) for x in 'abc']
'-'.join(str(x) for x in foo[::-1])
'99-98-97'
, можете сказать, чем он лучше, например, такого:
'-'.join(map(str, [ord(x) for x in 'abc'[::-1]]))
'99-98-97'
или даже такого:
'-'.join(map(str, map(ord, 'abc'[::-1])))
Читаемость? Или есть ещё какой-то смысл разделить более сложное выражение с мапами на два с генераторами?
По скорости map выигрывает генераторы (на хабре статья была с измерениями, не найду уже), но если мой код в test_p2 и test_p3, то как-то так:
print(timeit.timeit(test_p, number=1000), timeit.timeit(test_p2, number=1000), timeit.timeit(test_p3, number=1000))
0.0027002159040421247 0.0017352891154587269 0.001657433109357953
Вы просто оптимизировали, а я небольшой фанат матрешек, вот без мап:
def test_map(): '-'.join(map(str, [ord(x) for x in 'abc'[::-1]]))
def test_comp(): '-'.join(str(ord(x)) for x in 'abc'[::-1])
print(timeit.timeit(test_map, number=1000), timeit.timeit(test_comp, number=1000))
(0.003298044204711914, 0.0029828548431396484)
У меня comprehension быстрее.
Проморгал, что не тот вариант засунул.
2.7.11:
In [1]: import timeit
In [2]: def test_map(): '-'.join(map(str, map(ord, 'abc'[::-1])))
In [3]: def test_comp(): '-'.join(str(ord(x)) for x in 'abc'[::-1])
In [4]: print(timeit.timeit(test_map, number=1000), timeit.timeit(test_comp, number=1000))
(0.0022649765014648438, 0.0031321048736572266)
3.5.1:
In [1]: import timeit
In [2]: def test_map(): '-'.join(map(str, map(ord, 'abc'[::-1])))
In [3]: def test_comp(): '-'.join(str(ord(x)) for x in 'abc'[::-1])
In [4]: print(timeit.timeit(test_map, number=1000), timeit.timeit(test_comp, number=1000))
0.001268998021259904 0.001320684008533135
Мап быстрее в обоих случаях.
Заворачивать вызов в try с отловом четырех исключений означает сделать код абсолютно нечитаемым.
А зачем заворачивать в 4? заверните в один, и будет то же что и в pcall
try:
user = get_user(use_id)
except Exception as e:
# Do something
А если исключения все же нужно обрабатывать по разномо, то такой код помоему читабельней
try:
user = get_user(use_id)
except Exception1 as e:
# Do something
except Exception2 as e:
# Do something
except Exception3 as e:
# Do something
чем
err, user = pcall(get_user(use_id))
if isinstance(err, Exception1):
# Do something
elif isinstance(err, Exception2):
# Do something
elif isinstance(err, Exception3):
# Do something
Или не так я использую pcall?
преимущество в том, что не приходится таскать за собой блок try-catch, который вы рано или поздно забудете.
На мой взгляд просто внесение в язык полюбившейся фичи из другого языка, короче говоря не более чем вкусовщина.
а проверить кортеж на наличие в нем исключения нет?)
нет, потому что кортеж вы не сможете обработать как плоский результат.
import f as fun
Примеры накладок
def f(x):
return x * x + 1
f = open('lalala')
f.close()
Да и python-pylint реагирует на такие имена, говорит «нужно прорефакторить имя, слишком короткое».
Написал бы программу чисто на ФП, чтобы можно было посмотреть на читаемость (на соответствие Zen'у).
И да, ещё напишу: мы уже похоронили второй питон. Так что смотреть на этот дурацкий raw_input() в примерах, который вообще появился известно, по какой причине, было не очень комфортно.
Предлагаешь делать каждый раз
я этого не предлагал, где вы увидели?
линтеры pylint и flake8 гибко настраиваются.
мы уже похоронили второй питон
никому не интересно, что именно вы похоронили. Я работал в компаниях, чей бизнес крутится исключительно на втором питоне.
Я работал в компаниях, чей бизнес крутится исключительно на втором питоне.
Да всем пофиг, где ты там работал. Тебе говорят про питон вообще. Ну, сдохнет твоя библиотека вместе со вторым питоном. Да она даже не оживёт, нечему подыхать будет.
я этого не предлагал, где вы увидели?
Ты занял имя, вместо того чтобы сделать, как все делают — уникальное имя, а дальше, кому надо, тот сократит до f.
линтеры pylint и flake8 гибко настраиваются.
Не, глупая идея. Предлагаешь из-за одного твоего модуля перенастраивать их и коснуться из-за этого всего остального. С какой стати? В том-то и дело, что ты выбрал имя неправильно.
Не пойму, с чего такой грубый тон? Словно я вас к чему-то принуждаю.
Библиотека работает на диапазоне версий 2.6 — 3.5. Вы, наверное, не заметили это в тексте. Комментировать остальное я не считаю нужным.
Так принято в го, но не в питоне. В питоне принято пользоваться исключениями.
Даже если вам нравится такой стиль, это не повод тащить его в питон: функции у вас в проекте будут вести себя неконсистентно — одни будут кидать исключения, а другие — возвращать ошибку.
achain, ichain
В питоне 3.6+ будет способ это делать нативно:
None-aware operators — www.python.org/dev/peps/pep-0505
Предикаты
Я не понимаю, зачем это нужно, все приведённые примеры записываются одним выражением.
Если хочется иметь функцию, чтобы куда-то ещё её передавать, можно это выражение завернуть в лямбду.
Список и кортеж дополнительно реализуют .reversed, .sorted, .group, .distinct и .apply.
Зачем? Это всё можно делать либо встроенными функциями, либо с помощью list/dict/set comprehensions, либо с помощью generator expressions.
Нельзя отвергать хорошие идеи и паттерны из других языков только потому, что они не соответствуют чувству прекрасного авторов Python.
Библиотека f для функционального программирования в Питоне