Pull to refresh

Comments 20

Если честно, по заголовку и описанию рассчитывал прочитать историю (как до этого докатились) аргументов, а тут скорее снимок текущего состояния.
Я бы еще рассказал, что значения по-умолчанию вычисляются один раз — при объявлении функции:
b=1
def foo (a=b):
    print (a)
foo()
b=2
foo()

Выведет:
1
1

Что еще хитрее:
def foo (x=[0]):
    x[0]+=1
    print (x)
foo()
foo()

Выведет:
[1]
[2]

Т.к. x — это список, изменяемый (mutable) тип, передаваемый по ссылке. И при вызове foo без аргументов передается ссылка на заданный при объявлении foo список, который можно модифицировать внутри функции.

вы бы хоть проверяли свои примеры.
пример с def foo(var, kvar=0, *args,**kwargs): у вас дан неверно.
я даже сначала подумал, что сам понимаю что-то неправильно.
перепроверил.
таки да — ошибка у вас.
правильно так:


In [1]: def foo(var, kvar=0, *args,**kwargs): 
   ...:     print(var, kvar, args, kwargs) 
   ...:                                                                                                                             

In [2]: foo(1, a=1,)                                                                                                                
1 0 () {'a': 1}

In [3]: foo(1, 1)                                                                                                                   
1 1 () {}

In [4]: foo(1, 2)                                                                                                                   
1 2 () {}

In [5]: foo(1, 2, a='a', b='b', c='c')                                                                                              
1 2 () {'a': 'a', 'b': 'b', 'c': 'c'}

In [6]: foo(1, 2, 3, a='a', b='b', c='c')                                                                                           
1 2 (3,) {'a': 'a', 'b': 'b', 'c': 'c'}

In [7]: foo(1, 2, 3, a=1, b=2)                                                                                                      
1 2 (3,) {'a': 1, 'b': 2}

In [8]: foo(1, 2, a=1, b=2)                                                                                                         
1 2 () {'a': 1, 'b': 2}

а у вас в примерах "Вызов 2" и "Вызов 3" даны с ошибками

В "Вызов 4" тоже ошибка.

>>> foo(1, 2, 3, 4, a=1, b=2)
1 2 (3, 4) {'a': 1, 'b': 2}

И в других примерах тоже ошибки в выводах.

например, вот тут:

foo(1, 2, a=1, b=2, c=3)                   # Вызов 2
# 1 0 () {'a': 1, 'b': 2, 'c': 3}

интересно - тест на внимательность или халатное оформление статьи?

Возможно ошибки были в оригинальной статье на момент перевода, переводчик перевел и на этом его работа закончилась.

Еще неучтенный Вами вариантдля пункта «3. Назначение значений аргументов, применяемых по умолчанию»:
def f(a=1, b=2, c=3):
     print(a,b,c)
     
f(1,2,b=4)
Traceback (most recent call last):
  File ".../python2.7/site-packages/IPython/core/interactiveshell.py", line 2882, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-10-66b68040163e>", line 1, in <module>
    f(1,2,b=4)
TypeError: f() got multiple values for keyword argument 'b'

Хороший пример, недавно попался на похожем, но с передачей кортежа:


def foo(a, b, c=5, *args):
print(a, b, c, args)


cor = (1, 2, 3, 4)
foo(1,2,c=10,*cor)


Получается, что аргумент 'с' ссылается как на именнованный 'с=10', так и на позиционный cor[0].


Возможно, указанные примеры плохого кода?

Если честно не понятно о чём вообще статья. А «трюки» из первых примеров, которые должны удивить, не удивят никого, что видел книгу по питону. За перевод спасибо, а содержание показалось невнятным.
Мне кажется где-то потерялась четверка.
foo(1, 2, 3, 4, a=1, b=2)                  # Вызов 4
# 1 2 (3,) {'a': 1, 'b': 2}

В остальном спасибо, теперь понятней стало.
В тексте оригинальной статьи закралась пара ошибок, перешедших в этот первод, в выводе одной из функций:
def foo(var, kvar=0, *args,**kwargs):
    print(var, kvar, args, kwargs)
…
foo(1, 2, a=1, b=2, c=3)                   # Вызов 2
# 1 0 () {'a': 1, 'b': 2, 'c': 3}          – неверно
# 1 2 () {'a': 1, 'b': 2, 'c': 3}          – верно

foo(1, 2, 3, a=1, b=2)                     # Вызов 3
# 1 2 () {'a': 1, 'b': 2}                  – неверно
# 1 2 (3,) {'a': 1, 'b': 2}                – верно

foo(1, 2, 3, 4, a=1, b=2)                  # Вызов 4
# 1 2 (3,) {'a': 1, 'b': 2}                – неверно
# 1 2 (3, 4) {'a': 1, 'b': 2}              – верно
Спасибо.
Вчера перед сном читал статью и не сразу понял, в чём были такая причина.
Сейчас же всё прояснилось )
Я написал об этом автору оригинальной статьи, и он уже её исправил :-)
Также, полагаю, стоило бы упомянуть про недавно добавленные positional-only аргументы (PEP-570):
def foo(a, b, /, bar):
    pass

foo(1, 2, bar=3)  # correct
foo(1, b=2, bar=3)  # incorrect
# TypeError: foo() got some positional-only arguments passed as keyword arguments: 'b'

Можно добавить, что args и kwargs это всего лишь имена переменных, их можно называть как угодно в ваших функциях.

Если в методе есть необходимость писать подобное foo(var, kvar=0, *args,**kwargs), то явно вы делаете что-то не так…
Автор с первых же строк заметки вводит в блуд читателя, особенно новичков, т.к. например, код:
def foo(lst):
    lst = lst + ['new entry']
    print(lst)                # Выводит ['Book', 'Pen', 'new entry']

lst = ['Book', 'Pen']
print(lst)                    # Выводит ['Book', 'Pen']
foo(lst)
print(lst)

выведет
['Book', 'Pen']
['Book', 'Pen', 'new entry']
['Book', 'Pen']

Соотв. и в комментарии надо было документировать ИМЕННО ТАКОЕ поведение, а не то которое удобно автору для запутывания читателя и открытия ему СОКРОВЕННЫХ ТАЙН ПОД ПОКРОВАМИ…
Sign up to leave a comment.