Zen of Python 'Explicit is better than implicit'
Asked Answered
F

3

12

I'm trying to understand what 'implicit' and 'explicit' really means in the context of Python.

a = []

# my understanding is that this is implicit
if not a:
   print("list is empty")

# my understanding is that this is explicit
if len(a) == 0:
   print("list is empty")

I'm trying to follow the Zen of Python rules, but I'm curious to know if this applies in this situation or if I am over-thinking it?

Flotilla answered 25/9, 2020 at 19:13 Comment(7)
Why a? Why list? Typo?Fredette
Yes, typo. Apologies for the mistake.Flotilla
That is indeed a bit weird. Changed it to == 0. In this case, it sounds like "len(a) == 0" is more explicit than "not a", but they are both considered explicit?Flotilla
It's only implicit in the sense that you need to know the "truthiness" of a list, but that's a pretty well established notion in Python.Rotenone
if not a is explicitly checking if a is falsey (in this case empty). if len(a)==0 is explicitly checking if the length of a is equal to zero.Heirdom
Think mathematically: ∅ is the empty set, and you can consider it to be nothing. If something doesn't exist, it's not true. There's a leap between asking "Do we have any items in the list?" and "Is the count of items in the list exactly zero?". In most cases you'd probably care about the first question more than the second, although they're equivalent.Enthusiastic
since it's a weakly typed language, it's laughableChrist
F
14

The two statements have very different semantics. Remember that Python is dynamically typed.

For the case where a = [], both not a and len(a) == 0 are equivalent. A valid alternative might be to check not len(a). In some cases, you may even want to check for both emptiness and listness by doing a == [].

But a can be anything. For example, a = None. The check not a is fine, and will return True. But len(a) == 0 will not be fine at all. Instead you will get TypeError: object of type 'NoneType' has no len(). This is a totally valid option, but the if statements do very different things and you have to pick which one you want.

(Almost) everything has a __bool__ method in Python, but not everything has __len__. You have to decide which one to use based on the situation. Things to consider are:

  • Have you already verified whether a is a sequence?
  • Do you need to?
  • Do you mind if your if statement crashed on non-sequences?
  • Do you want to handle other falsy objects as if they were empty lists?

Remember that making the code look pretty takes second place to getting the job done correctly.

Fredette answered 25/9, 2020 at 19:19 Comment(1)
Thanks for the explanation! It seems like I was focusing on the readability rather than the underlying meaning of what's going on and the original intended purpose.Flotilla
O
5

Though this question is old, I'd like to offer a perspective.

In a dynamic language, my preference would be to always describe the expected type and objective of a variable in order to offer more purpose understanding. Then use the knowledge of the language to be succinct and increase readability where possible (in python, an empty list's boolean result is false). Thus the code:

lst_colours = [] 

if not lst_colours: 
  print("list is empty")

Even better to convey meaning is using a variable for very specific checks.

lst_colours = []
b_is_list_empty = not lst_colours

if b_is_list_empty: 
  print("list is empty")

Checking a list is empty would be a common thing to do several times in a code base. So even better such things in a separate file helper function library. Thus isolating common checks, and reducing code duplication.

lst_colours = []

if b_is_list_empty(lst_colours): 
  print("list is empty")


def b_is_list_empty (lst):
  ......

Most importantly, add meaning as much as possible, have an agreed company standard to chose how to tackle the simple things, like variable naming and implicit/explicit code choices.

Osber answered 2/3, 2022 at 19:8 Comment(1)
This is the only answer actually tackling the zen aspect of the case. The conditional question we're asking is "Are there any items in the list?". There's a subtle leap between that question and "Is the count of items in the list zero?", and it would potentially matter if you made a custom subclass with a specific case. Using a function like is_empty(some_list) expresses the meaning to the reader, which is exactly what we want. The even better way would be for lists in Python to have list.is_empty as a dynamic attribute. Accepting that False is equivalent to an empty set ∅ is also possibleEnthusiastic
K
2

Try to think of:

if not a:
    ...

as shorthand for:

if len(a) == 0:
    ...

I don't think this is a good example of a gotcha with Python's Zen rule of "explicit" over "implicit". This is done rather mostly because of readability. It's not that the second one is bad and the other is good. It's just that the first one is more skillful. If one understands boolean nature of lists in Python, I think you find the first is more readable and readability counts in Python.

Koziol answered 25/9, 2020 at 19:25 Comment(5)
One is not more skillful than the other. They mean different things. One only works for sequences, the other does not, for example. Knowing the differences is where the skill comes in. Otherwise this would be an opinion based question.Fredette
Good point but that's a matter of opinion I suppose. I wanted to point out that this is more for readability rather than a demonstration of explicit vs implicit.Koziol
And I'm pointing out that there is a semantic difference. At that point, readability takes second place.Fredette
I think that's fair.Koziol
As a fresh student of Python, readability has mattered quite a lot to me. Of course, that is assuming that the code is working as intended first :PFlotilla

© 2022 - 2024 — McMap. All rights reserved.