Python New Features

Section Overview

  • The Walrus Operator
  • Positional-Only Parameters
  • References

Section 1. The Walrus Operator (Assignment Expressions)

We use an assignment expression(walrus operator). It use the walrus operator (:=) to both assign and evaluate variable names in a single expression, thus reducing repetition. It is a new syntax introduced in Python 3.8 and solve a long-standing problem with the language that can cause code duplication.

Now, let’s see:

if fake_val := fake_func():
    # do something with fake_val
while fake_val := fake_func():
    # do something with fake_val
fake_val = fake_func1()
if not fake_val:
    logging.warning('fake func1')
    fake_val = fake_func2()
    if not fake_val:
        logging.warning('fake func2')
        val = func3()
if not fake_val:
    raise ValueError('....')

After upgrading to 3.8, you could refactor it to:

if not (fake_val := fake_func1()):
    logging.warning('fake func1')
    if not (fake_val := fake_func2()):
        logging.warning('fake func2')
        if not (fake_val := fake_func3()):
            raise ValueError('....')

For example, Here, I define the contents of the basket.

fruits_in_basket = {
    'apple': 15,
    'peach': 10,
    'lemon': 5,
}

Now we want to order some lemon. So we need to make sure there is at least one lemon in the basket.

def order_func(count):
    ...
def out_of_stock():
    ...
count = fruits_in_basket.get('lemon', 0)
if count:
    order_func(count)
else:
    out_of_stock()

After upgrading to 3.8, you could refactor it to:

if count := fruits_in_basket.get('lemon', 0):
    order_func(count)
else:
    out_of_stock()

If we want to do lemon juice, we need 10 lemon.

def make_lemon_juice(count):
    ...
count = fruits_in_basket.get('lemon', 0)
if count >= 10:
    make_lemon_juice(count)
else:
    out_of_stock()

After upgrading to 3.8, you could refactor it to:

if (count := fruits_in_basket.get('lemon', 0)) >= 10:
    make_lemon_juice(count)
else:
    out_of_stock()

If we want to order for peach and lemon juice;

def make_peach_juice(count):
    ...
def make_lemon_juice(count):
    ...
count = fruits_in_basket.get('peach', 0)
if count >= 2:
    make_peach_juice(count)
else:
    count = fruits_in_basket.get('lemon', 0)
    if count >= 10:
        make_lemon_juice(count)
    else:
        # 'Nothing'

After upgrading to 3.8, you could refactor it to:

if (count := fruits_in_basket.get('peach', 0)) >= 2:
    make_peach_juice(count)
elif (count := fruits_in_basket.get('lemon', 0)) >= 10:
    make_lemon_juice(count)
else:
    # 'Nothing'

In general, when you find yourself repeating the same expression or assignment multiple times within a grouping of lines, it’s time to consider using assignment expressions in order to improve readability.

Section 2. Positional-Only Parameters

We can use / in a function definition to indicate that arguments before that are positional-only.

For example:

def func(a, /):
    pass

func('foobar')
# This raises
func(a='foobar')

If the func uses keyword argument when positional-only is required, TypeError occurs.

Here’s an example function definition which includes all argument types.

def func(a, /, b, *, c):
    pass

a: positional-only
b: positional or keyword
c: keyword-only

Thus, func can be called like this:

func('foo', 'bar', c='foobar')
func('foo', b='bar', c='foobar')

But not like this:

# TypeError: func() got some positional-only arguments passed as keyword arguments: 'a'
func(a='foo', b='bar', c='foobar')

# TypeError: func() takes 2 positional arguments but 3 were given
func('foo', 'bar', 'foobar')

Section 3. References

  • https://www.python.org/dev/peps/pep-0569/#id6
  • https://docs.python.org/3.8/whatsnew/3.8.html
  • https://www.python.org/dev/peps/pep-0572/
  • https://www.python.org/dev/peps/pep-0013/#electing-the-council
  • https://docs.python.org/3/glossary.html#keyword-only-parameter