We have launched EaseAnnotate!

Try Out Now!
Pythonify logo
tricks

10 Things You Didn't Know About Python

9 min read
pythonify
10 Things You Didn't Know About Python

As a Python Developer you must know that Python is named after Monty Python, the famous comedy group. You must also know that import antigravity will take you to xkcd. But did you know these 10 lesser known some actually useful features?

Enhancing Numeric Readability

Starting with Python 3.6, you can use underscores for increased readability of numbers, particularly useful in large numbers or binary/hexadecimal/decimal representations. They don't change the value of the number but provide "visual" separators to make the numbers more readable. Here's an example:

python
# A large number without underscores large_number = 1000000000 # The same number with underscores for thousands separation readable_number = 1_000_000_000 print(large_number == readable_number) # prints: True

In the above Python snippet, large_number and readable_number are equal in value. The underscores in readable_number simply make it easier to discern the scale of the number at a glance.

Exploring Python with the help() Function

The help() function in Python is an inbuilt function used to display the documentation of modules, functions, classes, keywords etc. It's particularly useful to understand the working of any built-in or custom Python object.

Here's an example:

python
# Seeking help on a built-in Python function e.g., len() help(len)

The above will output a description of the len() function, explaining what it does and showing how to use it.

You can even use help() on user-defined functions or classes:

python
def my_function(): """This is a demo function for the help() example.""" pass help(my_function)

This will display the docstring ("""This is a demo function for the help() example.""") as well as some basic info about my_function.

Drop into Interactive Session

The -i flag in Python is used when running a script to enter an interactive session after the script finishes executing. This allows you to continue interacting with the data or results generated by your script.

Here's an example. Suppose you have a Python script called my_script.py:

python
# my_script.py x = 10 y = 20

To run this script from the terminal and then enter an interactive Python session afterwards, you would use the following command:

shell
python -i my_script.py

After the script executes, you'll find yourself in an interactive Python session. Here, you can access the variables x and y and continue to interact with them as needed.

Generators that take Input in each step

Python generators are a powerful tool for handling sequences in a memory-efficient manner. Usually, we retrieve data from a generator using the next() function which automatically sends None into the generator function. However, Python provides the send() method to pass data back into a generator from outside.

Let's take a look at an example:

python
def simple_generator(): received_value = None while True: received_value = yield received_value if received_value is None: break gen = simple_generator() # 'None' is yielded and '1' is sent into the generator print(gen.send(None)) # prints: None print(gen.send(1)) # prints: 1 print(gen.send(None)) # this will terminate the generator

In the example above:

  • First, we have to prime the generator using gen.send(None). This starts the generator but stops at the first yield expression.
  • Then, we send in 1 using gen.send(1). The generator resumes, assigns 1 to received_value, and then hits the yield statement again.
  • We can continue to send values into our generator in this way as needed.

Remember, you must always prime the generator by sending None after its creation, before sending in actual values. This gets the generator to the first yield expression. Then, you can send values into the generator

Using the Walrus Operator in Python

Python 3.8 introduced the "walrus operator" (:=), officially known as Assignment Expressions. This operator allows you to assign and return a value in the same expression.

Here's an example of its usage:

python
data = [1, 2, 3, 0, 4, 5] # Using walrus operator to simplify code if (n := len(data)) > 4: print(f"The list has {n} elements.")

In the expression (n := len(data)) > 4, the length of data is calculated, then the result is both assigned to n and used for the comparison. This can make some patterns cleaner and more efficient by removing the need for duplicate calculations or function calls.

Leveraging the else Clause in Python Loops

Python features an often-overlooked bit of functionality when it comes to loops: the else clause. Unlike other programming languages, Python allows an else statement after for and while loops. This else block executes after the loop completes normally—i.e., when the loop concludes without encountering a break statement.

Here's an example of how it can be used:

python
def find_prime(n): for num in range(2, n): if n % num == 0: print(f"{n} is not a prime number") break else: # will run if loop didn't encounter a break statement print(f"{n} is a prime number") find_prime(11) # Output: 11 is a prime number find_prime(15) # Output: 15 is not a prime number

In this function, the else block executes only when the number is prime—because in that case, the loop will complete without hitting the break statement. When the number is not prime, the break statement is hit and the else block is skipped. Therefore, this feature is useful when you want to perform a certain action after the loop finishes, but only if the loop didn't encounter a break.

Use of slots to Save Memory in Python Classes

Python's flexibility allows for the dynamic addition of attributes to objects, which although quite handy, also consumes more memory. However, Python provides a less popular but efficient feature called __slots__ to minimize the memory usage of objects.

By defining __slots__ in the class definition, you essentially tell Python, "These are the only instance variables in this class." This can drastically improve memory usage if you have a lot of instances of that class.

Here's an example:

python
class MyClassWithSlots: __slots__ = ['name', 'age'] class MyClassWithoutSlots: pass # Create instances obj_with_slots = MyClassWithSlots() obj_without_slots = MyClassWithoutSlots() # Now you can only assign attributes listed in __slots__ to obj_with_slots obj_with_slots.name = "John" obj_with_slots.age = 25 # obj_without_slots can get arbitrary new attributes, because it doesn't define __slots__ obj_without_slots.name = "John" obj_without_slots.surname = "Doe"

In this example, objects of MyClassWithSlots will consume less memory as they are limited to have only attributes listed in __slots__. This feature is especially useful when creating a large number of instances of a class.

Execution of String Formatted Programs

Python offers the exec() function, a dynamic execution function that is capable of executing Python code, which can be a string or object code. Although it's not recommended for daily use due to security implications and inefficiency, exec() can be useful in certain special applications.

Here's an example on how to use it:

python
code_in_string = """ def multiply(x, y): return x*y result = multiply(5, 3) print('The result is:', result) """ # Using exec() to execute the Python program contained in the string exec(code_in_string)

This code first defines a Python function multiply() inside a string, assigns the result of a function execution to a variable result, and prints the result. The entire string is then executed as a Python program using the exec() function.

Combining Else with Try-Except Blocks in Python

Python allows an else clause to be used along with try/except blocks. The else block will only execute if the try block didn't raise an error. This is a lesser-known feature but it can help to increase code clarity by clearly separating the error handling code from the normal execution code.

Here's an example:

python
data = {'a': 1, 'b': 2} try: value = data['c'] except KeyError: print("A KeyError occurred!") else: print("No error occurred. The value is:", value)

In this code snippet, if data['c'] does not raise a KeyError, the else block will execute. If data['c'] raises a KeyError, the except block will execute and the else block will be skipped.

This feature allows for writing cleaner code by clearly separating the normal case (the else block) from the error handling case (the except block).

Identifying Python's Garbage Collection

The gc (garbage collection) module in Python allows you to interface with Python's garbage collector. Garbage collection is the process of identifying and cleaning up memory that's being used by objects in your code that are no longer needed.

A less-known but useful function in the gc module is gc.collect(), which forces an immediate collection of all garbage. Although Python's garbage collector runs automatically, in some cases, manually running garbage collection can be beneficial.

Here's an example of how to use it:

python
import gc # Force a garbage collection sweep collected = gc.collect() print(f"Garbage collector: collected {collected} objects.")

The function gc.collect() returns the number of objects it has collected and deallocated. This feature can help in managing memory in your Python application, particularly when dealing with large data or complex object relationships.

Conclusion

Python continues to surprise us with its handy features and flexibility. Although the language is easy to learn and user-friendly, it presents a host of lesser-known features, like the use of __slots__ to optimize memory, the ability to combine else with try/except blocks, or the use of the walrus operator for in-line assignment, which help to make programming more efficient and effective.

Understanding and utilizing these lesser-known Pythonic features can give you a unique edge in writing cleaner, more efficient, and more Pythonic code. As we've seen, Python is full of such treasures. All we need to do is continue exploring to become even more proficient in our journey with this versatile language.

Remember, each tool and trick has its appropriate use-case. While it's good to know about and understand these tools, always aim for readability and simplicity in your code. As stated in the Zen of Python, "Readability counts."

More Reads

Python for javascript programmers
Python

Python for javascript programmers

December 18, 2023