Есть ли способ отличить «obj[x, y]» от » obj[(x, y)]»?

#python #python-3.x

Вопрос:

Итак, я хочу реализовать класс, содержащий вложенные данные. Я хотел бы реализовать __getitem__ таким образом, чтобы это obj[x][y] можно было сократить obj[x, y] .

Однако я заметил проблему: сигнатура __getitem__ заключается в том, что вместо этого он ожидает один позиционный аргумент *args . Если задано несколько аргументов, они автоматически помещаются в кортеж.

Т. е. obj[a, b] и obj[(a, b)] то и другое, по-видимому, эквивалентно obj.__getitem__((a,b))

Но тогда как я могу отличить эти два случая

  1. Внешний слой индексируется кортежами и obj[(a, b)] должен возвращать значение по этому индексу
  2. Внешний слой не индексируется кортежами и obj[a, b] должен возвращать obj[a][b]

Единственными возможными решениями, о которых я знаю в настоящее время, являются

  1. Откажитесь от идеи принуждения obj[x, y] к obj[x][y]
  2. Если мы только хотим obj[x] всегда писать obj[x,] вместо этого.

И то, и другое на самом деле не является удовлетворительным.

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

1. Это isinstance правильный путь ?

2. @KrisI думал об этом, но, похоже, будет нелегко, если код не будет зависеть от того, какие объекты используются для индексирования внешнего/внутреннего слоя.

3. obj[(a, b),] ?

4. @iacob это именно то решение (2), которое я излагаю в посте, но я не нахожу его удовлетворительным и предпочел бы отказаться obj[x,y] , если нет лучшей альтернативы.

Ответ №1:

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

obj[a, b] и obj[(a, b)] означают точно то же самое в Python. Нет никакой семантической разницы, никакой разницы в том, как они выполняются, и нет ничего, за что можно было бы зацепиться, чтобы отличить их. Это было бы все равно, что пытаться различить пробелы в obj[a,b] и obj[a, b] .

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

1. Это действительно прискорбно. Интересно, почему python, по крайней мере, не допускает пользовательскую реализацию __getitem__ с подписью __getitem__(self, *items) вместо __getitem__(self, item)

2. @Hyperplane: Есть множество вещей, которые команда разработчиков могла бы сделать __getitem__ , например, разрешить аргументы ключевых слов и obj[x=y] … но эти вещи не дают достаточной пользы в конкретных случаях использования, чтобы оправдать дополнительную сложность. (Они могут принести некоторую пользу, но не настолько , чтобы стоило усложнять язык.)