Во время определения класса переменная класса, определенная как словарь, используется при создании второй переменной класса словаря, подмножества, срезанного по сравнению с первым, например:
class C(object):
ALL_ITEMS = dict(a='A', b='B', c='C', d='D', e='E')
SUBSET_X = {k: v for k, v in ALL_ITEMS.items() if k in ('a', 'b', 'd')} # (this works)
SUBSET_Y = {k: ALL_ITEMS[k] for k in ('a', 'b', 'd')} # (this fails)
Довольно простые вещи, но чистый эффект от выполнения этого кода меня довольно удивляет.Моим первым подходом был код в строке 4, но вместо этого мне пришлось прибегнуть к решению в строке 3.В правилах определения объема словаря есть что-то тонкое, что я явно не могу понять.
В частности, ошибка возникает в случае сбоя:
File "goofy.py", line 4, in <dictcomp>
SUBSET_Y = {k: ALL_ITEMS.get(k) for k in ('a', 'b', 'd')}
NameError: name 'ALL_ITEMS' is not defined
Природа этой ошибкисбивает с толку меня по нескольким причинам:
- Задание для
SUBSET_Y
является правильно сформированным словарным пониманием и ссылается на символ, который должен быть внутри области видимости и доступен. - В последующем случае (присвоение
SUBSET_X
), которое также является словарным пониманием, символ ALL_ITEMS
является совершенно четким и доступным.Таким образом, тот факт, что возбужденное исключение является NameError
в случае неудачи, представляется явно неверным.(Или, в лучшем случае, вводит в заблуждение.) - Почему правила области видимости отличаются для
items()
против __getitem__
или get()
?(Такое же исключение происходит при замене ALL_ITEMS[k]
на ALL_ITEMS.get(k)
в случае сбоя.)
(Даже более десяти лет назад, как разработчик Python, я никогда не сталкивался с этой ошибкой, котораялибо означает, что мне повезло, либо я жил скрытно: ^)
Один и тот же сбой происходит в различных версиях 3.6.x CPython, а также в версиях 2.7.x.
РЕДАКТИРОВАТЬ: НетЭто не дубликат предыдущего вопроса.Это относилось к списку пониманий, и даже если кто-то должен был проецировать одно и то же объяснение на словарь, это не объясняет разницу между двумя приведенными мною случаями.А также, это не феномен только для Python 3.