What does the asterisk represent in the definition of a function in Python?

Asked

Viewed 238 times

6

For example, in the module documentation pickle it is common to see such a 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?

  • That? https://answall.com/q/162956/101 would not have been better to have answered there?

  • @Maniero I have my doubts. Think it would fit?

  • The question is identical except in the words, why do you have any doubt?

  • @Maniero to generalize the question to all use cases of *. But analyzing better, this is just a specific case of what was commented there, so it actually makes sense.

  • 1

    More general than "In C this operator is used in pointer variables, but in Python I don’t know the way, and what is the reason to use, so what is the meaning of the operator (*) in the Python language?" , bordered on the broad.

1 answer

7


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

As the title of PEP already reported, this syntax allows defining functions that receive only named arguments, not positional. But this is partially true. What happens is that the function will receive only named arguments after the asterisk. Before it, the arguments may also be positional.

For example, in the function pickle.load quoted you can receive the argument file 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 the first argument, the function will only allow named arguments and if you pass any positional value an error TypeError 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 "options" arguments, which will determine the behavior of the function.

Imagine a function that compares two strings, can be case sensitive:

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 body of the function has not been defined. However, calling the function comparar('teste', 'Teste', True) you will probably have to look at the documentation of the function to know what the True will represent.

Before 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 be used, that only pollutes the code, without considering that it would allow calling the function defining any amount of positional arguments, even if it was used effectively two:

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

Imagine how much time could be wasted before the reader realizes that all these parameters will be ignored and would not 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 the call with unnecessary arguments, but it would add a logic in the implementation for values that will not even be used.

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

Browser other questions tagged

You are not signed in. Login or sign up in order to post.