Forced naming of parameters in Python

后端 未结 11 1245
日久生厌
日久生厌 2020-11-27 12:15

In Python you may have a function definition:

def info(object, spacing=10, collapse=1)

which could be called in any of the following ways:<

相关标签:
11条回答
  • 2020-11-27 12:51

    As other answers say, changing function signatures is a bad idea. Either add new parameters to the end, or fix every caller if arguments are inserted.

    If you still want to do it, use a function decorator and the inspect.getargspec function. It would be used something like this:

    @require_named_args
    def info(object, spacing=10, collapse=1):
        ....
    

    Implementation of require_named_args is left as an exercise for the reader.

    I would not bother. It will be slow every time the function is called, and you will get better results from writing code more carefully.

    0 讨论(0)
  • 2020-11-27 12:56

    The python3 keyword-only arguments (*) can be simulated in python2.x with **kwargs

    Consider the following python3 code:

    def f(pos_arg, *, no_default, has_default='default'):
        print(pos_arg, no_default, has_default)
    

    and its behaviour:

    >>> f(1, 2, 3)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: f() takes 1 positional argument but 3 were given
    >>> f(1, no_default='hi')
    1 hi default
    >>> f(1, no_default='hi', has_default='hello')
    1 hi hello
    >>> f(1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: f() missing 1 required keyword-only argument: 'no_default'
    >>> f(1, no_default=1, wat='wat')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: f() got an unexpected keyword argument 'wat'
    

    This can be simulated using the following, note I've taken the liberty of switching TypeError to KeyError in the "required named argument" case, it wouldn't be too much work to make that the same exception type as well

    def f(pos_arg, **kwargs):
        no_default = kwargs.pop('no_default')
        has_default = kwargs.pop('has_default', 'default')
        if kwargs:
            raise TypeError('unexpected keyword argument(s) {}'.format(', '.join(sorted(kwargs))))
    
        print(pos_arg, no_default, has_default)
    

    And behaviour:

    >>> f(1, 2, 3)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: f() takes exactly 1 argument (3 given)
    >>> f(1, no_default='hi')
    (1, 'hi', 'default')
    >>> f(1, no_default='hi', has_default='hello')
    (1, 'hi', 'hello')
    >>> f(1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 2, in f
    KeyError: 'no_default'
    >>> f(1, no_default=1, wat='wat')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 6, in f
    TypeError: unexpected keyword argument(s) wat
    

    The recipe works equally as well in python3.x, but should be avoided if you are python3.x only

    0 讨论(0)
  • 2020-11-27 12:56

    You could declare your functions as receiving **args only. That would mandate keyword arguments but you'd have some extra work to make sure only valid names are passed in.

    def foo(**args):
       print args
    
    foo(1,2) # Raises TypeError: foo() takes exactly 0 arguments (2 given)
    foo(hello = 1, goodbye = 2) # Works fine.
    
    0 讨论(0)
  • 2020-11-27 12:57

    You can force people to use keyword arguments in Python3 by defining a function in the following way.

    def foo(*, arg0="default0", arg1="default1", arg2="default2"):
        pass
    

    By making the first argument a positional argument with no name you force everyone who calls the function to use the keyword arguments which is what I think you were asking about. In Python2 the only way to do this is to define a function like this

    def foo(**kwargs):
        pass
    

    That'll force the caller to use kwargs but this isn't that great of a solution as you'd then have to put a check to only accept the argument that you need.

    0 讨论(0)
  • 2020-11-27 13:02

    You could use the ** operator:

    def info(**kwargs):
    

    this way people are forced to use named parameters.

    0 讨论(0)
  • 2020-11-27 13:08
    def cheeseshop(kind, *arguments, **keywords):
    

    in python if use *args that means you can pass n-number of positional arguments for this parameter - which will be accessed as a tuple inside the function.

    And if use **kw that means its keyword arguments, that can be access as dict - you can pass n-number of kw args, and if you want to restrict that user must enter the sequence and arguments in order then don't use * and ** - (its pythonic way to provide generic solutions for big architectures...)

    if you want to restrict your function with default values then you can check inside it

    def info(object, spacing, collapse)
      spacing = 10 if spacing is None else spacing
      collapse = 1 if collapse is None else collapse
    
    0 讨论(0)
提交回复
热议问题