Помеченное выражение в квадратных скобках - PullRequest
4 голосов
/ 03 апреля 2019

Кажется, что помеченные выражения нельзя использовать в квадратных скобках так, как они заключены в скобки:

>>> import numpy as np
>>> x = np.ones((3, 4))
>>> x[:, *(None, None), :]
  File "<stdin>", line 1
    x[:, *(None, None), :]
         ^
SyntaxError: invalid syntax

, хотя можно ожидать, что последние будут выводить то же самое, что и

>>> x[(slice(None), *(None, None), slice(None))]
array([[[[ 1.,  1.,  1.,  1.]]],


       [[[ 1.,  1.,  1.,  1.]]],


       [[[ 1.,  1.,  1.,  1.]]]])

Знаете ли вы какие-либо веские причины, по которым это запрещено, и есть ли планы поддержать его в следующих версиях Python?

1 Ответ

3 голосов
/ 03 апреля 2019

Что касается того, как это сделать, ответ, вероятно, будет x[:, None, None, :]. Но, возможно, у вас есть кортеж, содержащий nones = (None, None), и в этом случае вы можете сделать: x[:, nones[0], nones[1], :]. Но я согласен, что было бы лучше иметь действительный x[:, *nones, :].

На вопрос, почему это невозможно, мы можем взглянуть на грамматику Python , чтобы понять, почему это не работает:

trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
subscriptlist: subscript (',' subscript)* [',']
subscript: test | [test] ':' [test] [sliceop]
sliceop: ':' [test]

Если вы следуете за самой длинной и самой многообещающей ветвью грамматики из test, ища литерал '*' (я не представляю целое поддерево, потому что большинство других ветвей останавливаются очень рано): test -> or_test -> and_test -> comparison -> xor_expr -> and_expr -> shift_expr -> arith_expr.

Обратите внимание, что это правило, которое мы ищем, это

star_expr: '*' expr

Посмотрим, сможем ли мы найти его отсюда (arith_expr):

arith_expr: term (('+'|'-') term)*
term: factor (('*'|'@'|'/'|'%'|'//') factor)*
factor: ('+'|'-'|'~') factor | power
power: atom_expr ['**' factor]
atom_expr: ['await'] atom trailer*

Помните, trailer - это то, с чего мы начали, поэтому мы уже знаем, что нет ничего, что ведет к star_expr здесь, и atom закрывает все эти различные пути:

atom: ('(' [yield_expr|testlist_comp] ')' |
       '[' [testlist_comp] ']' |
       '{' [dictorsetmaker] '}' |
       NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False')

В принципе вам следует разрешить использовать в качестве subscriptlist любое выражение, которое мы видели в ветви (test -> ... -> arith_expr -> ... -> atom), или любое из NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False').

Есть много ветвей, которые я здесь не прошел. Для большинства из них вы можете понять почему, просто взглянув на название правила. С другой стороны, возможно, нет смысла перепроверять.

Например, при чтении выражения test:

test: or_test ['if' or_test 'else' test] | lambdef

Мы можем видеть, что ['if' or_test 'else' test] закрывает путь (как мы ищем * something). С другой стороны, я мог бы включить lambdef, так как это совершенно верно для нашего квеста, я просто проигнорировал такие пути, потому что они закрываются сразу после того, как мы их исследуем (применяя единственное правило инвалида *...), в данном случае (как вы могли догадаться):

lambdef: 'lambda' [varargslist] ':' test

Здесь мы видим 'lambda', это не выражение, которое начинается с '*', поэтому путь закрывается. Интересно, что это означает, что x[lambda e: e] - это совершенно правильный синтаксис (я бы не догадался и никогда не видел его, но это имеет смысл).

В итоге мы не увидели ни одного ведущего * выражения в процессе, поэтому не должно быть никакой двусмысленности в том, что вы предлагаете (если я не пропустил одну комбинацию правил). Может быть, имеет смысл попросить кого-то, кто действительно работал над этим, проверить, есть ли веские основания для того, чтобы не иметь этого вне потенциальных грамматических неясностей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...