What is the asterisk in defining a function in Python? [duplicate]

5

For example, in the documentation for the module pickle it is common to see such notation:

  • pickle.dump(obj, file, protocol=None, *, fix_imports=True)
  • pickle.dumps(obj, protocol=None, *, fix_imports=True)
  • pickle.load(file, *, fix_imports=True, encoding="ASCII", errors="strict")
  • pickle.loads(bytes_object, *, fix_imports=True, encoding="ASCII", errors="strict")

What is the function of this asterisk in these cases?

    
asked by anonymous 06.07.2018 / 16:20

1 answer

7

The answer you are looking for exists and is called PEP. Pepe Legal? No, PEP 3102.

As the PEP title has already denounced, this syntax allows you to define functions that receive only named, non-positional arguments. But this is partially true. What happens is that the function will receive only arguments named after the asterisk. Before it the arguments can still be positional.

For example, in the pickle.load function you can receive the file argument positionally, but any other argument should be named.

obj = pickle.load('arquivo', encoding='utf-8')  # Ok, um argumento posicional e outros nomeados
obj = pickle.load(file='arquivo', encoding='utf-8')  # Ok, todos os argumentos nomeados
obj = pickle.load('arquivo', 'utf-8')  # Erro, argumento posicional após o asterisco

If the asterisk is as the first argument, the function will only allow named arguments and if passed any positional value a TypeError error will be raised.

def soma(*, a, b):
    return a + b

The only way to invoke the function is soma(a=1, b=2) . Generally this technique is used when the function in question receives one (or more) positional arguments that are of trivial understanding and other arguments "options", that will determine the behavior of the function.

Imagine a function that compares two strings , and can be sensitive to upper-case characters:

def comparar(a, b, case_sensitive=False):
    ...

If you call comparar('teste', 'Teste', case_sensitive=True) it is very clear what the function will do, even if the function body has not been defined. However, if you call the comparar('teste', 'Teste', True) function you will probably have to look at the function documentation to know what True will represent.

Before the PEP was implemented, it was possible to do something like:

def comparar(a, b, *ignorar, case_sensitive=False):
    ...

But so you define an argument that will not even be used, which only pollutes the code, without considering that it would allow you to call the function by defining any number of positional arguments, even if two were actually used:

comparar('teste', 'Teste', True, True, ['/', '|'], case_sensitive=True)

Imagine how much time could be lost until the reader realizes that all these parameters will be ignored or even need to be there?

You could even avoid this by checking the value of the parameter and issuing an exception:

def comparar(a, b, *ignorar, case_sensitive=False):
    if ignorar:
        raise TypeError

I would avoid calling with unnecessary arguments, but would add a logic in the implementation to values that will not even be used.

With this in mind, they have defined PEP 3102, and by omitting the argument name after the asterisk, magic happens.

    
06.07.2018 / 16:20