Комментарии 82
>>> def f(a: str):
... print(a)
... return
...
>>> f('a')
a
>>> f(1.0)
1.0
>>> import sys
>>> sys.version
'3.5.2 (default, Nov 12 2018, 13:43:14) \n[GCC 5.4.0 20160609]'
Ссылка: the state of type hints in Python
В общем Python списывает хорошее у Haskell ещё начиная со списковых выражений.
подробнее здесь: docs.python.org/3/library/typing.html
чтобы у меня дженерик был не поверх любого типа T, а поверх только U[T] для фиксированного (или нет) U?
Кажется, да.
Много можно чего ещё скопировать из Haskell (и раздуться похлеще монстра C++), но задачи такой, как я понимаю, не стоит. Я просто имел в виду, что разработчики Python в сторону Haskell смотрят внимательно и заимствуются фичи оттуда давно, потому что list comprehensions в Python с 2000 года.
Можно указать типы при создании TypeVar и будет он co-, contra- или in- вариантным. К сожалению, пока этот механизм в том же mypy и pycharm работает с проблемами
Код python исполняется интерпретатором, а он в свою очередь все эти аннотации типов полностью игнорирует, что вы же в своём примере и продемонстрировали.
Аннотации это для чего угодно, но не для исполнения кода: для читаемости, для подсказок в IDE, для статического анализа (mypy тот же самый), etc.
Байт-код все равно исполняется виртуальной машиной.
Т.е. у чистого интерпретатора мало смысла в проверке типов.
Я то сам, дне думаю, что для динамического языка не стоит внедрять обязательную проверку типов. Ну если только в качестве опции в виде билбиотеки. Не в ядре.
Я за то, чтобы сохранять ядро как можно более компактным.
Байт-код все равно исполняется виртуальной машиной.
И это в ответ на утверждение, что питон компилируется. Из контекста я понял, что вы считаете его интерпретируемым. Или я ошибаюсь?
Вот когда начнёт исполняться — тогда и будет компилируемым.
Машкод тоже может не исполнятся непосредственно на процессоре. В современных процах он собственно и не исполняется, а транслируется в микрокоды, которые затем исполняются.
Компилируемый язык программирования — язык программирования, исходный код которого преобразуется компилятором в машинный код.
В машинный.
p.s. Тут какой-то спор о терминах, которые уже давно устоялись.
Кроме того, существуют реализации языков, которые компилируют исходный текст программы в байт-код, который затем либо интерпретируется, либо выполняется т. н. JIT-компилятором (или виртуальной машиной). Это привносит ещё больше неясности в вопрос о том, где именно должна быть проведена граница между компилируемым языком и языком интерпретируемым.
Можно и поспорить ;)
И нет, если вы запакуете виртуальную машину и байт-код в один файл, то это все равно не будет скомпилированной программой. Ваша программа (а не ВМ) должна быть переведена в машинные коды, которые смогут исполняться процессором целевой платформы.
Во-вторых, компилятор может вообще не генерировать никаких файлов, а компилировать программу в памяти, снаружи он будет подобен интерпретатору, но компилятором от этого быть не перестанет.
если вы запакуете виртуальную машину и байт-код в один файл, то это все равно не будет скомпилированной программой
Здрасьте, а байткод откуда взялся, если не был скомпилирован?
Я бы называл питон компилируемым в байт-код. Но да, сам байткод при этом интерпретируется (как и машинный код).
После последней фразы могу запостить только эту ссылку. Финиш, конечно:
www.youtube.com/watch?v=LLk9_EH6Pfo
Если все тащить в одну кучу получится еще один C++, точнее получим все недостатки C++, без его достоинств.
В моей практике ошибки с типами так редки, что ИМХО не стоит городить огород.
Ну мне кажется что все таки неплохо иметь возможность при необходимости использовать типизацию (пусть даже если для того что бы она работала в рантайме надо подключить какой ни будь enforce) в основном для себя языке программирования.
По моему это просто мода. Лично я накушался строгой типизации в C++. А так сначала можно затащить строгую типизацию в питон, а потом без дизайн паттернс ни шагу ступить нельзя будет.
Ну и уж совсем мечты это нормально предсказание типов для LLVM и для компилятора в WebAssemly, а то питон сейчас жив одним ML
статическую проверку типов в рантайм
Статическая проверка не может быть в рантайме, она выполняется на этапе компиляции, проверки в рантайме называются динамическими.
Если нужна строгая типизация можно просто взять другой язык
Типизация в питоне, кстати, строже чем в большинстве скриптовых. Хоть функции и принимают любые объекты, но вольностей, типа складывания строки с числом он не позволяет, и неявных приведений типов (как в js — лишь бы что-то выполнить) он не делает.
$ php -r 'var_dump(3 === "10");'
bool(false)
Правильнее так:>> 3 == "10" False
>>> print( 10 == "10")
False
Если числа разные — непонятно, что есть False
>>> 3 == "10"
File "<stdin>", line 1
3 == "10"
^
IndentationError: unexpected indent
Стоит отметить, что pydantic использует свои классы вместо питоновских dataclasses, что может ограничивать применимость. Я в свободное время пилю библиотечку, которая может быть применима для уже существующих датаклассов без необходимости как-то их менять.
Еще бы добавить аннотаций для функционального программирования и будет еще круче
аннотаций для функционального программирования
Вы мне лучше скажите, какая аннотация должна быть у функции, принимающей совпадение по регулярке (тип _sre.SRE_Match)?
Какие возможности Python 3 вы добавили бы в приведённый здесь список?asyncio и холиварный
:=
(3.8+)очень классно было бы действительно по желанию включать проверку либо по названию класса либо структуры обьекта в рантейме и где можно на этапе интерпретации, а то перепутаешь места в функции, а ошибку выдаёт из чёрт знает какого места, а потом в коде хорошо протестенном отключать
и очень интересная фича LRU кэш, я чессно не знал и dict юзал
кста вроде одинакого по скорости этот кэш и ручной через dict, кто нибудь протестил нормально скорость??
имхо, в Питон версии 100500 + следует ввести:
- инспекцию структуры любого обьекта с преттипринтом или лучше в визуальном представлении, когда берёшь неизвестный модуль, где документация плохая а все типы стёрты
- обьединить нотацию для класса и dicta, inst['field'] эквивалентно inst.field
интерпретировать сложные comprehention декларативно с оптимизаций и кешем где надо
встроить без геморa частичные функции, с поддержкой интерпретатора заместо partial:
def fn ( a,b,c)
k = fn(1,2) #-> обьявление частичной функции k(c) c изсестными a,b,
потом
k[0] = 3 # безгеморная замена параметра на определённом месте
сложные lambda обьявления с функционалом как обычный метод
fib = lambda @lru_cache(maxsize=512), a: int ,b : int -> int : if number == 0: return 0
if number == 1: return 1
return fib_memoization(number-1) + fib_memoization(number-2)
оно и раньше так же примерно работало
"Hello {user}!".format(**locals)
или **vars
Type Trial 1 Trial 2 Trial 3
%: 0.273233943000 0.268914790000 0.273714235000
str.format(): 0.7942503730000681 0.793637686999773 0.7926878570001463
str.Template(): 3.3321329630002765 3.3256752329998562 3.315622544999769
f-string: 0.1914799450000828 0.18900782099990465 0.19004946999984895
Тестировалось на python 3.7, оригинал.оно и раньше так же примерно работало
Нет, не так же. Можно было только подставлять значения, а делать вычисления прямо внутри было нельзя (теперь в f-string можно). Так что теперь нужно быть осторожнее с такими строками. <sarkazm>
Это почти как маленький php внутри python.</sarkazm>
Ко всему + то что сказал lega производительность в разы больше.
~ $ python3.7 -m timeit 'a = 1' 'b = "string"' '"Test strings formatting: {a} {b}".format(**locals())'
500000 loops, best of 5: 620 nsec per loop
~ $ python3.7 -m timeit 'a = 1' 'b = "string"' 'f"Test strings formatting: {a} {b}"'
2000000 loops, best of 5: 157 nsec per loop
~ $ python3.6 -m timeit 'a = 1' 'b = "string"' '"Test strings formatting: {a} {b}".format(**locals())'
1000000 loops, best of 3: 0.599 usec per loop
~ $ python3.6 -m timeit 'a = 1' 'b = "string"' 'f"Test strings formatting: {a} {b}"'
10000000 loops, best of 3: 0.142 usec per loop
~ $ python2.7 -m timeit 'a = 1' 'b = "string"' '"Test strings formatting: {a} {b}".format(**locals())'
1000000 loops, best of 3: 0.435 usec per loop
Изменения крутые и полезные.
Очень хотелось бы что бы исправили концептуальные проблемы языка, даже если это означает python 4 и сломанную обратную совместимость.
Например те же импорты все ещё очень сложны для понимания новичками (особенно по сравнению с другими языками). При этом циркулярные импорты падают в рантайме с неадекватной ошибкой, а orm фреймворки вроде той же алхимии предлагают решать проблему просто — указывать название классов текстом *facepalm".
К сожалению, я изучал питон очень давно и не могу 100% вспомнить какие у меня были проблемы. Но, кажется, импорты — это не та вещь, которая мне показалась непонятной.
Про циклические импорты действительно не мешало бы добавить текст более явный, хотя если посмотреть на стек это и глазами довольно легко понять.
В ОРМ циклические завимости надо решать не написанием названий классов текстом, а правильной расстановкой relation, мне кажется это в 95% случаев возможно (если я не прав — прошу привести пример).
На мой взгляд, циклическая зависимость в большинстве — ошибка проектирования и должна исправляться переразбиением модулей или снижением связности кода (иногда — использованием DI, например).
циклическая зависимость легко может разрешаться интерпретатором без жалобы на якобы ошибкиКак такая цикличекая зависимость может решиться интерпретатором?
# a.py
import b
value = b.value + 5
# b.py
import a
value = a.value + 7
PS: В питоне нормально решаются циклические зависимости, проблемы не в питоне, а «в руках».
её не разруливает даже maven в своих проэктах
Имхо, с ней намного проще получить в проекте одну и ту же зависимость с разными версиями. И долго искать причину фокусов в рантайме.
if x := True:
print(f'{x}')
# Выведет: True
x = 2
print([y := x**x, y**2, y**3])
# Выведет: [4, 16, 64]
И много разговоров про None-aware operators (PEP 505), значительно сокращающие код:
# Old
data = data if data is not None else []
# New
data = data ?? []
# Old
if lst:
lst.append('string')
# New
lst?.append('string')
# Old
if callable(foo):
foo()
# New
foo?()
# Old
if x:
x + 1
# New
x? + 1
# Old
result = a
try:
result = result.b
except AttributeError:
pass
else:
result = result.c
try:
result = result.d
except AttributeError:
pass
else:
result = result.e
# New
a?.b.c?.d.e
Однако PEP 505 сейчас в состоянии Deferred.
Ну и конечно следовало в статье упомянуть asyncio — это важная часть, по которой сделано много хорошей и качественно работы.
Возможности Python 3, достойные того, чтобы ими пользовались