2015-08-11 2 views
4

Я прочитал решение в кулинарных книгах Python для создания функции, которая допускает только аргументы имени. Я написал свой собственный код, чтобы попробовать его:Функция, которая разрешает только аргументы имени

class Reporter(object): 
    def __init__(self, *, testline=None, sw_ver= None, directory=None): 
     pass 

if __name__ == "__main__" 
    r = Reporter() 

Однако интерпретатор показывает эту ошибку:

File "Reporter.py", line 6 
    def __init__(self, *, testline=None, sw_ver= None, directory=None): 
         ^
SyntaxError: invalid syntax 

Почему это показывает это?

+0

Довольно, что вы не можете иметь 'star' один, что вы пытаетесь сделать с этим? –

+0

Вы уверены, что правильно скопировали текст из книги? Может быть, у книги было имя (имя переменной) после звезды перед запятой? –

+0

[IMG] http://i60.tinypic.com/2dui9sx.jpg [/ IMG] это код из этой книги –

ответ

1

Звездный оператор (*) используется для unpacking. Вы не можете использовать его в качестве аргумента.

Вы можете прочитать Variable-Length Argument Tuples:

Functions can take a variable number of arguments. A parameter name that begins with * gathers arguments into a tuple. For example, printall takes any number of arguments and prints them:

def printall(*args): 
    print args 

The gather parameter can have any name you like, but args is conventional. Here’s how the function works:

>>> printall(1, 2.0, '3') (1, 2.0, '3') 
0

звезда (*) не является допустимым Python 2.7 идентификатор, это оператор. Я думаю, что вы допустили ошибку при копировании кода из кулинарной книги.

Однако, это действительный код в Python 3, как Padraic Cunningham answered.

0

В питоне 2. *:

Параметров имен, полученных в качестве законов переменных имен в любых языках программирования. но в python 2. * Знак STAR используется перед именами параметров для determining special situation и одним номером STAR знак как ошибка повышения имени параметра.

Но в питон 3. *:

Параметр, равный СТАР не может присвоить любое значение в этом и следующих параметров позиции не может дать значение по позиции, и только может оценить по имени параметра ,

+0

Это фото кода из книги http://i60.tinypic.com/2dui9sx.jpg –

4

Вы не можете использовать только *. В объявлении функции это означает «распаковать любой другой неназванный аргумент в этой переменной», поэтому вы должны указать ему имя переменной.

Вы можете добиться того, что вы хотите, дав ему имя, а затем проверить его пуст, как это:

class Reporter(object): 
    def __init__(self, *args): 
     assert not args, "Reporter.__ini__ only accepts named arguments" 

Затем вы хотите добавить аргументы, которые вы можете позволить, как это:

# won't work 
def __init__(self, *args, testline=None, sw_ver= None, directory=None): 

... кроме * args должно быть в конце. Но если вы поместите их в конец, вы увидите, что вы все равно можете передать другие аргументы, не названные в первую очередь.

Вы должны отменить логику и взять только kwargs.

class Reporter(object): 
    def __init__(self, **kwargs): 
     testline = kwargs.pop('testline', None) 
     sw_ver = kwargs.pop('sw_ver', None) 
     directory = kwargs.pop('directory', None) 
     assert not kwargs, 'Unknown arguments: %r' % kwargs 

Теперь, если кто-то попытается дать неназванные суждения, они будут отклонены.

+0

спасибо, но ваше решение также генерирует синтаксическую ошибку: Файл «Reporter.py», строка 6 def __init __ (self, * args, testline = None, sw_ver = None, directory = None): ^ СинтаксисError: недействительный синтаксис –

+0

Я получил только половину своих рассуждений и отвлекся, сожалею об этом. Теперь это исправлено. – spectras

6

код используется является допустимым синтаксисом, но для Python3 поэтому книга должна использовать синтаксис python3, он позволяет только именованные аргументы, pep-3102:

python 3 new syntax

You can also use a bare * in the parameter list to indicate that you don’t accept a variable-length argument list, but you do have keyword-only arguments.

с помощью своей код и передача не ключевого слова в python 3 будет ошибкой, но по другой причине:

TypeError         Traceback (most recent call last) 
<ipython-input-2-b4df44fa1e0c> in <module>() 
     1 if __name__ == "__main__": 
----> 2   r = Reporter(4) 
     3 

TypeError: __init__() takes 1 positional argument but 2 were given 

После того, как вы используете ключевое слово он работает отлично:

In [4]: if __name__ == "__main__": 
      r = Reporter(testline=4) 
    ...:  

Использование функции с тем же синтаксисом, что, возможно, даст более очевидную ошибку:

def f(*, foo=None, bar=None): 
    return foo, bar 


In [6]: f(4) 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-6-a122d87dbe99> in <module>() 
----> 1 f(4) 

TypeError: f() takes 0 positional arguments but 1 was given 

Является также полезно, если вы хотите, чтобы некоторые позиционные арги и имеют дополнительные ключевые слова арг прошел, но только по имени:

def f(a,b, *, foo=None, bar=None): 
    return a, b, foo, bar 

Затем проходит 3 позиционных аргов будет ошибка:

In [8]: f(1,2,3) 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-8-b61741968103> in <module>() 
----> 1 f(1,2,3) 

TypeError: f() takes 2 positional arguments but 3 were given 
1

Это несколько декораторов, которые я написал по касательной для проекта Python 2, над которым я работал. Исключения составляют как можно более близкие зеркала, созданные функциями Python 3, которые используют синтаксис аргументов только для ключевых слов.

Они не запрещают позиционные аргументы, но могут потребовать/ограничить аргументы ключевых слов. Вы можете создать еще один декоратор, который запретил бы позиционные аргументы.

import functools 

def original_wrapped_function(f): 
    try: 
     while True: 
      f = f.__wrapped__ 
    except AttributeError: 
     return f 


def restrict_kwargs(*allowed_keywords): 
    def restrict_kwargs_decorator(func): 
     @functools.wraps(original_wrapped_function(func)) 
     def restrict_wrapper(*args, **kwargs): 
      for keyword in kwargs: 
       if keyword not in allowed_keywords: 
        msg = "%s() got an unexpected keyword argument '%s'" 
        raise TypeError(msg % (func.__name__, keyword)) 
      return func(*args, **kwargs) 
     restrict_wrapper.__wrapped__ = func 
     return restrict_wrapper 
    return restrict_kwargs_decorator 


def require_kwargs(*required_keywords): 
    def require_kwargs_decorator(func): 
     @functools.wraps(original_wrapped_function(func)) 
     def require_wrapper(*args, **kwargs): 
      missing_keywords = [] 
      for keyword in required_keywords: 
       if keyword not in kwargs: 
        missing_keywords.append(keyword) 
      if missing_keywords: 
       func_name = func.__name__ 
       count = len(missing_keywords) 
       if count == 1: 
        arg_word = 'argument' 
        missing_keywords_str = "'%s'" % missing_keywords[0] 
       else: 
        arg_word = 'arguments' 
        and_join_str = ' and ' if count == 2 else ', and ' 
        missing_keywords_str = ', '.join(
         ("'%s'" % mk) for mk in missing_keywords[:-1]) 
        missing_keywords_str = and_join_str.join((
         missing_keywords_str, ("'%s'" % missing_keywords[-1]))) 
       msg = "%s() missing %d required keyword-only %s: %s" 
       raise TypeError(msg % (func_name, count, arg_word, 
             missing_keywords_str)) 
      return func(*args, **kwargs) 
     require_wrapper.__wrapped__ = func 
     return require_wrapper 
    return require_kwargs_decorator 


def exact_kwargs(*exact_keywords): 
    def exact_kwargs_decorator(func): 
     @restrict_kwargs(*exact_keywords) 
     @require_kwargs(*exact_keywords) 
     @functools.wraps(original_wrapped_function(func)) 
     def exact_wrapper(*args, **kwargs): 
      return func(*args, **kwargs) 
     exact_wrapper.__wrapped__ = func 
     return exact_wrapper 
    return exact_kwargs_decorator 

Некоторые примеры:

>>> @restrict_kwargs('five', 'six') 
... def test_restrict_kwargs(arg1, arg2, *moreargs, **kwargs): 
...  return (arg1, arg2, moreargs, kwargs) 
... 
>>> 
>>> @require_kwargs('five', 'six') 
... def test_require_kwargs(arg1, arg2, *moreargs, **kwargs): 
...  return (arg1, arg2, moreargs, kwargs) 
... 
>>> 
>>> @exact_kwargs('five', 'six') 
... def test_exact_kwargs(arg1, arg2, *moreargs, **kwargs): 
...  return (arg1, arg2, moreargs, kwargs) 
... 
>>> 
>>> 
>>> 
>>> test_restrict_kwargs(1, 2, 3, 4, five=5) 
(1, 2, (3, 4), {'five': 5}) 
>>> 
>>> test_restrict_kwargs(1, 2, 3, 4, five=5, six=6) 
(1, 2, (3, 4), {'six': 6, 'five': 5}) 
>>> 
>>> test_restrict_kwargs(1, 2, 3, 4, five=5, six=6, seven=7) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "SO_31939890.py", line 19, in restrict_wrapper 
    raise TypeError(msg % (func.__name__, keyword)) 
TypeError: test_restrict_kwargs() got an unexpected keyword argument 'seven' 
>>> 
>>> 
>>> 
>>> test_require_kwargs(1, 2, 3, 4, five=5) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "SO_31939890.py", line 49, in require_wrapper 
    missing_keywords_str)) 
TypeError: test_require_kwargs() missing 1 required keyword-only argument: 'six' 
>>> 
>>> test_require_kwargs(1, 2, 3, 4, five=5, six=6) 
(1, 2, (3, 4), {'six': 6, 'five': 5}) 
>>> 
>>> test_require_kwargs(1, 2, 3, 4, five=5, six=6, seven=7) 
(1, 2, (3, 4), {'seven': 7, 'six': 6, 'five': 5}) 
>>> 
>>> 
>>> 
>>> test_exact_kwargs(1, 2, 3, 4, five=5) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "SO_31939890.py", line 20, in restrict_wrapper 
    return func(*args, **kwargs) 
    File "SO_31939890.py", line 49, in require_wrapper 
    missing_keywords_str)) 
TypeError: test_exact_kwargs() missing 1 required keyword-only argument: 'six' 
>>> 
>>> test_exact_kwargs(1, 2, 3, 4, five=5, six=6) 
(1, 2, (3, 4), {'six': 6, 'five': 5}) 
>>> 
>>> test_exact_kwargs(1, 2, 3, 4, five=5, six=6, seven=7) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "SO_31939890.py", line 19, in restrict_wrapper 
    raise TypeError(msg % (func.__name__, keyword)) 
TypeError: test_exact_kwargs() got an unexpected keyword argument 'seven' 
>>> 

 Смежные вопросы

  • Нет связанных вопросов^_^