"Effective Python 2nd Edition" Chapter 3 <Functions>

Introduction

Execution environment

When posting the sample code, post the result of execution in the following execution environment. We will try to provide it in the form that is as error-free as possible, but please forgive us if it does not work or is wrong.

Chapter 3

Throw an exception instead of None

What do you return if something unexpected happens when you process it in a function? I used to return None until I knew this. For example, the following code.

#Bad example (returning None when unexpected)
from datetime import datetime
def parse_datetimes(datetime_string_list):
    result = []
    for datetime_string in datetime_string_list:
        try:
            result.append(datetime.strptime(datetime_string, "%Y-%m-%d"))
        except (ValueError, TypeError):
            return None
    return result

>>> print(parse_datetimes(["2020-09-22"]))
[datetime.datetime(2020, 9, 22, 0, 0)]
>>> print(parse_datetimes([]))
[]
>>> print(parse_datetimes(["hoge"]))
None

This function accepts a list of strings representing the date as input, and returns a list converted to datetime type if parsing succeeds, and None if it fails. At first glance it looks good, but there are two problems with this.

To avoid these problems, ** throw an exception if something unexpected happens inside the function **.

#Good example (throwing an exception when unexpected)
from datetime import datetime
class MyError(Exception):
    def __init__(self, message):
        self.message = message

def parse_datetimes(datetime_string_list):
    result = []
    for datetime_string in datetime_string_list:
        try:
            result.append(datetime.strptime(datetime_string, "%Y-%m-%d"))
        except (ValueError, TypeError):
            raise MyError(f"The value entered is invalid: {datetime_string}")  #Throw an exception
    return result

>>> print(parse_datetimes(["2020-09-22"]))
[datetime.datetime(2020, 9, 22, 0, 0)]
>>> print(parse_datetimes([]))
[]
>>> print(parse_datetimes(["hoge"]))
...
Traceback (most recent call last):
  ...
__main__.MyError:The value entered is invalid: hoge

If it is implemented to throw an exception as described above, processing will not continue as it is unless the exception MyError is caught, and None and the empty list [] are the same. It's safe because there is no fear of handling it.

Do not specify an empty list [] or an empty dictionary {} as the default argument

If you want to use a value if it is specified in the argument, and use the default value if it is not specified, it is convenient to set the default argument. For example, the following code.

#This is a bad example
def square(value, result_list=[]):
    result_list.append(value ** 2)
    return result_list

This function returns the square of value added to result_list. As for the feelings of the person who implemented this,

I think you are thinking.

# result_If you specify list, the result will be returned in that list.
>>> result_list = [1, 4]
>>> result_list = square(3, result_list)
>>> print(result_list)
[1, 4, 9]

# result_If list is not specified, the result will be returned in the empty list.
>>> result_list = square(3)
>>> print(result_list)
[9]

It looks like there's no problem at all, right? But after this, something strange happens.

>>> result_list = square(1)
>>> print(result_list)
[9, 1]  #that?[1]Should be returned? ??
>>> result_list = square(2)
print(result_list)
[9, 1, 4]  #that? Why are there 3 values? ??

so. If you don't know it, you will end up with such a mysterious behavior.

In fact, ** [default arguments are evaluated only once when the module is loaded, not each time the function is called](https://docs.python.org/ja/3/ faq / programming.html # why-are-default-values-shared-between-objects) **. Therefore, if you specify an empty list [] as the default argument, the empty list will be append`ed more and more, and the contents of the list will increase each time you call it as described above. ..

It's still good if you know this and use it, but it's not a behavior that everyone knows, so it's best to avoid specifying empty lists, empty dictionaries, etc. as default arguments. Instead, write:

#Good example
def square(value, result_list=None):
    if result_list is None:
        result_list = []  #By initializing here, it will be append to the empty list every time.
    result_list.append(value ** 2)
    return result_list

If implemented as above, if result_list is not specified, the empty list will be returned with the result.

>>> result_list = square(3)
>>> print(result_list)
[9]
>>> result_list = square(1)
>>> print(result_list)
[1]
>>> result_list = square(2)
>>> print(result_list)
[4]

By the way, depending on the IDE, it may issue a warning, so be sure to respond if there is a warning. PyCharm issued the following warning.

pycharm_warning

"Position-only arguments" and "Keyword-only arguments" added from Python 3.8

Suddenly, do you know what the code below means?

def safe_division(numerator, denominator, /, hoge, *, ignore_overflow, ignore_zero_division):
    ...

You might be wondering, "Why are the arguments/and*written?" This is ["Position-only arguments (on the left side of/)" and "Keyword-only arguments (on the right side of*) added from Python 3.8"](https://docs.python.org/ja/ It is written using 3 / glossary.html # term-parameter).

What does that mean?

I think the advantages of using position-only arguments and keyword-only arguments are as follows.

Writing / or * in the argument may seem strange at first, but as mentioned above, it has advantages, so it is better to use it as needed. However, it will not work if it is less than Python 3.8, so be careful there!

Summary

Based on the contents of Chapter 3 of "Effective Python 2nd Edition", I wrote down what I learned and what I thought.

References

Reference site

Recommended Posts

"Effective Python 2nd Edition" Chapter 3 <Functions>
"Effective Python 2nd Edition" Chapter 1 <Pythonic Thinking>
Python functions
Ant book with python (chapter3 intermediate edition ~)
#Python basics (functions)
[Beginner] Python functions
Python Easy-to-use functions
Python basics: functions
[Effective Python study memo] Chapter 1: Python-style thinking (Pythonic Thinking)
Python Beginner's Guide (Functions)
Python basic course (12 functions)
[Python for Hikari-] Chapter 06-04 Functions (arguments and return value 3)
A * algorithm (Python edition)
First Python 3rd Edition
[Python] Memo about functions
[Python for Hikari-] Chapter 06-01 Functions (Intrinsic Functions and Function Definitions)
# 4 [python] Basics of functions
Python built-in functions ~ Zip ~
[Python for Hikari-] Chapter 06-03 Functions (arguments and return value 2)
[Python] Chapter 01-01 About Python (First Python)
Wrap Python built-in functions
Effective Python Memo Item 3
[Python for Hikari-] <Supplement> Chapter 06-05 Functions (arguments and return values 4)
Curry arbitrary functions with Python ....
Effective Python Learning Memorandum Day 15 [15/100]
Python> lambda> tiny functions / callback functions
Getting Started with Python Functions
Python3 programming functions personal summary
Python 2 series and 3 series (Anaconda edition)
Python for Data Analysis Chapter 4
Effective Python Learning Memorandum Day 6 [6/100]
Effective Python Learning Memorandum Day 12 [12/100]
Effective Python Learning Memorandum Day 9 [9/100]
Effective Python Learning Memorandum Day 8 [8/100]
CI environment construction ~ Python edition ~
100 Language Processing Knock Chapter 1 (Python)
Study from Python Hour3: Functions
Python installation (Mac edition) (old)
100 Language Processing Knock Chapter 2 (Python)
Overriding library functions in Python
Effective Python Learning Memorandum Day 14 [14/100]
Effective Python Learning Memorandum Day 1 [1/100]
Effective Python Learning Memorandum Day 13 [13/100]
Python for Data Analysis Chapter 2
Effective Python Learning Memorandum Day 3 [3/100]
Effective Python Learning Memorandum Day 5 [5/100]
Keyword arguments for Python functions
Python for super beginners Python #functions 1
Effective Python Learning Memorandum Day 4 [4/100]
Paiza Python Primer 7: Understanding Functions
Python 3 sorted and comparison functions
[Python] Chapter 03-02 turtle graphics (turtle behavior)
Python functions learned in chemoinformatics
Effective Python Learning Memorandum Day 7 [7/100]
Effective Python Learning Memorandum Day 2 [2/100]
Python higher-order functions and comprehensions
Python for Data Analysis Chapter 3
Python Crawling & Scraping Chapter 4 Summary