Effective Python Memo Item 18 Use variable-length positional arguments to make the appearance cleaner

This is a memo of O'Reilly Japan's book effective python. https://www.oreilly.co.jp/books/9784873117560/ P42~44

Use the star argument (* arg) to make it look neat

** Consider a function that saves a log of debug information **

def log(massage, values):
    if not values:
        print(massage)
    else:
        values_str = ', '.join(str(x) for x in values)
        print('%s: %s' % (massage, values_str))

log('My numbers are', [1, 2])
log('Hi there', [])

>>>
My numbers are: 1, 2
Hi there

In this case, the parameter of the log function should be given a list if there is a number, but an empty list should be given even if there is no number. I want to save this trouble, and if there is no number, I want to give no argument

Therefore, we introduce a variable-length argument called ** star argument ** with the `` `* ``` operator prepended to the argument.

def log2(massage, *values):
    if not values:
        print(massage)
    else:
        values_str = ', '.join(str(x) for x in values)
        print('%s: %s' % (massage, values_str))

log2('My numbers are', [1, 2])
log2('Hi there') #No input for the second argument

>>>

My numbers are: [1, 2]
Hi there

By setting the star argument as an argument, it processes any input and considers it absent. (If you do not make it a star argument, it will not match the number of parameters of the function and will cause a TypeError)

Also, if you already have a list, you can add the `*` operator to the list and give it to the function parameters.


favorites = [7, 33, 99]
massage = 'Favorite colors'
log2(massage, *favorites)

>>>
Favorite colors: 7, 33, 99

At first glance it's convenient, but it actually has two problems

** 1. Variadic arguments are converted to tuples before being passed to the function ** If the caller of the function is a generator, it iterates over all tuples, which can lead to memory crashes (especially when there is a lot of data).

def my_generator():
    for i in range(10):
        yield i
        
def my_func(*args): #Here the arguments are converted to tuples
    print(args)
    
it = my_generator() #Generator it is generated
my_func(*it)               #The generator converted to tuple is output

>>>
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

It is desirable that the number of argument lists accepted by the my_func function is small.

** 2. If the position of the variable length argument and the position of the argument at the time of calling deviate, the output will be corrupted **

def log3(sequence, message, *values):
    if not values:
        print('%s: %s' %(sequence, massage))
    else:
        value_set = ', '.join(str(x) for x in values)
        print('%s: %s: %s' % (sequence, massage, value_set))

log3(1, 'Favorotes', 7, 33)
log3('Favorites', 7, 33)

>>>

1: Favorotes: 7, 33
Favorites: 7: 33

In this case, in the first output, 7 and 33 are processed correctly because the third and subsequent arguments correspond to the function log3 variadic. On the other hand, in the second output, 7 is used as a parameter for massage. And in this case, no exception will occur, and it may be left unnoticed. To get rid of this, you need to pay attention to the position of the input arguments and the parameters of the function.

Recommended Posts

Effective Python Memo Item 18 Use variable-length positional arguments to make the appearance cleaner
Effective Python Memo Item 19 Give optional behavior to keyword arguments
Effective Python Memo Item 11 Use zip to process iterators in parallel
Effective Python Memo Item 3
Effective Python Note Item 20 Use None and the documentation string when specifying dynamic default arguments
Effective Python memo Item 10 Enumerate from range
Effective Python memo Item 7 Use list comprehension instead of map and filter
How to use the C library in Python
Specify the Python executable to use with virtualenv
The easiest way to use OpenCV with python
[Algorithm x Python] How to use the list
Use the Python framework "cocotb" to test Verilog.
How to use the Raspberry Pi relay module Python
I wanted to use the Python library from MATLAB
[Python] How to use the graph creation library Altair
Specify MinGW as the compiler to use with Python
[Introduction to Udemy Python3 + Application] 27. How to use the dictionary
[Introduction to Udemy Python3 + Application] 30. How to use the set
How to use the model learned in Lobe in Python
[Introduction to Udemy Python3 + Application] 52. Tupleization of positional arguments
I want to use the R dataset in python
[python] How to use the library Matplotlib for drawing graphs
Make the display of Python module exceptions easier to understand
The first API to make with python Djnago REST framework
Effective Python Memo Item 9 Consider generator expressions for large comprehensions
How to use the __call__ method in a Python class
[Hyperledger Iroha] Notes on how to use the Python SDK
[Python] I want to use the -h option with argparse
I didn't know how to use the [python] for statement
[Introduction to Udemy Python3 + Application] 50. Positional arguments, keyword arguments, and default arguments
Tips for Python beginners to use the Scikit-image example for themselves