Python: приведение словаря к кортежу неявным путем вызова метода - PullRequest
0 голосов
/ 06 июня 2018

У меня проблема с кодом из проекта с открытым исходным кодом Mininet.Я абстрагировал его по следующему сценарию:

def bar (*a, **b):
    b.update({'a':(a,)})
    foo(**b)

def foo (*a, **c):
    print(c)
    print(a)

if __name__ == '__main__':
    bar(2,3,4, x=3, y=5)

Панель методов является всего лишь помощником для создания вызова функции foo.Если я запускаю его, print (a) не выводит, потому что значения все еще хранятся в словаре b.Если я поменяю * a на a, он будет работать нормально.

И вот мой вопрос : существует ли возможность, которая не изменяет метод foo, который помещает данные в * a с данными ивызов foo как в строке 3?Это означает, что только b в панели методов может быть изменено.

Ответы [ 2 ]

0 голосов
/ 06 июня 2018

Хорошо. Итак, я хочу, чтобы вы поняли, а не просто дали ответ, потому что StackOverflow - это объяснение концепции, а не написание кода, давайте разберемся в нескольких моментах:

* args и ** kwargs используются какпроизвольное количество аргументов.

Синтаксис Kwargs ** требует отображения (например, словарь);каждая пара ключ-значение в отображении становится ключевым аргументом.

, в то время как

* args получает кортеж, содержащийпозиционные аргументы.

Теперь давайте рассмотрим простой пример, чтобы понять вашу проблему:

def check(*a,**b):
    print(a)
    print(b)

Теперь * a требуется кортеж или список или позиционный аргумент, в то время как ** b требует формат dictАргумент keyworded.

Еще один момент, прежде чем приступить к решению проблемы:

* l идиома - распаковать списки аргументов, кортежи, установить

a,*b=(1,2,3,4,5)
print(a)
print(b)

output:

1
[2, 3, 4, 5]

Теперь, если я вызову эту функцию, что-то вроде:

def check(*a,**b):
    print("value_a {}".format(a))
    print("value_b {}".format(b))


print(check({'y': 5, 'x': 3, 'a': 5,'r':56}))

Теперь * a примет значение, потому что нет аргумента с ключами:

value_a ({'x': 3, 'y': 5, 'a': 5, 'r': 56},)

Но давайте добавим несколько ключевых слов аргумент:

print(check({'y': 5, 'x': 3, 'a': 5,'r':56},key_s=5,values=10))

вывод:

value_a ({'a': 5, 'y': 5, 'r': 56, 'x': 3},)
value_b {'key_s': 5, 'values': 10}

Давайте начнем использовать метод распаковки:

print(check(*{'y': 5, 'x': 3, 'a': 5,'r':56}))

вывод будет:

value_a ('r', 'x', 'y', 'a')
value_b {}
None

Потому что, как я показал, вы * распакуете ключи dict и обработаетони как позиционный аргумент, а не как аргумент keyworded.

Теперь давайте используем ** распаковку, которая будет распаковывать dict как ключ, пары значений:

Я думаю, вы поняли, теперь давайте использовать ** дляотображает dict, поэтому он будет распаковывать dict и каждый ключ, значение будет ключевым аргументом:

print(check(**{'y': 5, 'x': 3, 'a': 5,'r':56}))

вывод:

value_a ()
value_b {'y': 5, 'r': 56, 'a': 5, 'x': 3}

Так что теперь все понятноподумайте.

Теперь вернемся к вашей проблеме:

Как вы сказали, если используете:

def check(a,**b):
    print("value_a {}".format(a))
    print("value_b {}".format(b))


print(check(**{'y': 5, 'x': 3, 'a': 5,'r':56}))

Вы получаете результат, потому что онберя значение 'a' из dict, а остальные значения берутся ** b

Теперь, если вы хотите использовать * a и ** b, вам необходимо указать:

the positional argument for *a
Keyworded argument for **b

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

def bar (*a, **b):
    foo((a,),**b)


def foo (*a, **c):
    print(c)
    print(a)

if __name__ == '__main__':
    bar(2,3,4, x=3, y=5)

output:

{'y': 5, 'x': 3}
(((2, 3, 4),),)
0 голосов
/ 06 июня 2018

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

Если метод foo остается прежним, параметр *a представляет список аргументов без имени (например, bar(2,3,4) в вашем примере).И вызов foo(**b) в строке 3 означает передачу аргументов ключевого слова (например, bar(x=3, y=5) в вашем примере), поэтому они будут переданы в **c, поскольку это аргумент ключевого слова в foo.

...