CONTENTS
Enhancing Numeric Readability
Exploring Python with the help() Function
Drop into Interactive Session
Generators that take Input in each step
Using the Walrus Operator in Python
Leveraging the else Clause in Python Loops
Use of slots to Save Memory in Python Classes
Execution of String Formatted Programs
Combining Else with Try-Except Blocks in Python
Identifying Python's Garbage Collection
Conclusion
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:
pythondef 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:
shellpython -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:
pythondef 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 firstyield
expression. - Then, we send in
1
usinggen.send(1)
. The generator resumes, assigns1
toreceived_value
, and then hits theyield
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:
pythondata = [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:
pythondef 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:
pythonclass 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:
pythoncode_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:
pythondata = {'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:
pythonimport 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."