Начиная с Python 3.6 порядок аргументов ключевого слова сохраняется. До версии 3.6 это невозможно, так как OrderedDict
превращается в dict
.
Первое, что нужно понять, это то, что значение, которое вы передаете в **example
, не становится автоматически значением в **kwargs
. Рассмотрим этот случай, когда kwargs
будет иметь только часть example
:
def f(a, **kwargs):
pass
example = {'a': 1, 'b': 2}
f(**example)
Или этот случай, когда он будет иметь больше значений, чем в примере:
example = {'b': 2}
f(a=1, c=3, **example)
Или вообще без перекрытия:
example = {'a': 1}
f(b=2, **example)
Итак, то, что вы просите, на самом деле не имеет смысла.
Тем не менее, было бы неплохо, если бы был какой-то способ указать, что вы хотите упорядоченные **kwargs
, независимо от того, откуда взяты ключевые слова — явные аргументы ключевых слов в порядке их появления, за которыми следуют все элементы. из **example
в том порядке, в котором они появляются в example
(что могло бы быть произвольным, если бы example
было dict
, но также могло бы иметь смысл, если бы это было OrderedDict
).
Определить все мелкие детали и сохранить приемлемую производительность оказывается сложнее, чем кажется. См. PEP 468 и связанные темы для обсуждения этой идеи. Похоже, на этот раз он застопорился, но если кто-то поднимет его и поддержит (и напишет эталонную реализацию для людей, с которой можно поиграть, что зависит от OrderedDict
, доступного из C API, но, надеюсь, это будет в версии 3.5+). ), я подозреваю, что это в конечном итоге попадет в язык.
Кстати, обратите внимание, что если бы это было возможно, оно почти наверняка использовалось бы в конструкторе для самого OrderedDict
. Но если вы попробуете это сделать, все, что вы сделаете, — это заморозите какой-то произвольный порядок как постоянный:
>>> d = OrderedDict(a=1, b=2, c=3)
OrderedDict([('a', 1), ('c', 3), ('b', 2)])
Между тем, какие у вас есть варианты?
Что ж, очевидный вариант — просто передать example
в качестве обычного аргумента, а не распаковывать его:
def f(example):
pass
example = OrderedDict([('a', 1), ('b', 2)])
f(example)
Или, конечно, вы можете использовать *args
и передавать элементы как кортежи, но это, как правило, более уродливо.
В потоках, связанных с PEP, могут быть какие-то другие обходные пути, но на самом деле ни один из них не будет лучше этого. (За исключением… IIRC, Ли Хаойи предложил решение, основанное на его MacroPy, для передачи аргументов ключевых слов, сохраняющих порядок. , но я не помню подробностей. Решения MacroPy в целом потрясающие, если вы хотите использовать MacroPy и писать код, который не совсем читается как Python, но это не всегда уместно…)
person
abarnert
schedule
05.11.2014