Jun 01, 2021 Article blog
2. 2. Check that the container is empty
3. 3. Use Split() to create a list of strings
5. 5. Statement with file object
6. 6. Evaluate multiple conditions
7. 7. Use the default value in the function declaration
8. 8. Use counters for element counting
9. 9. Sort by order requirements
Programming is an interesting thing, and programming with
Python
is even more interesting because there are many different ways to implement a feature in
Python
H
owever, most of the time there are some preferred implementation methods, which some people call
Pythonic
A common feature of
Pythonic
is that the implementation code is concise.
Programming in
Python
or any coding language is not rocket-like science, it's all about skill. I
f you're interested in experimenting with
Pythonic
coding, these technologies will soon be part of our toolkit, and we'll find it more and more natural to use them in our projects.
So let's explore some of these simple tips.
People like to use sequences because when we know the order of the elements, we can manipulate them sequentially. S
trings, tuples, and lists are the most common sequence data types in
Python
W
e can use indexes to access individual items. L
ike other mainstream programming languages,
Python
supports a 0-based index in which we use zero to access the first element in parentheses.
In addition, we can use tile objects to retrieve specific elements of the sequence, as shown in the following code example.
>>> # Positive Indexing
... numbers = [1, 2, 3, 4, 5, 6, 7, 8]
... print("First Number:", numbers[0])
... print("First Four Numbers:", numbers[:4])
... print("Odd Numbers:", numbers[::2])
... First Number: 1
First Four Numbers: [1, 2, 3, 4]
Odd Numbers: [1, 3, 5, 7]
However,
Python
went one step further by supporting negative indexes. S
pecifically, we can use -1 to refer to the last element in the sequence and count backward. F
or example, the index of the last element is -2, and so on.
Importantly, negative indexes can also be used with positive indexes in sliced objects.
>>> # Negative Indexing
... data_shape = (100, 50, 4)
... names = ["John", "Aaron", "Mike", "Danny"]
... hello = "Hello World!"
...
... print(data_shape[-1])
... print(names[-3:-1])
... print(hello[1:-1:2])
... 4
['Aaron', 'Mike']
el ol
Containers are those types of container data that can store other data. S ome of the built-in containers that are often used are tuples, lists, dictionaries, and collections. W hen working with these containers, we often need to check that they contain any elements before doing anything else. I ndeed, we can check the length of these containers, which corresponds to the number of items stored. W hen the length is zero, the container is empty. Here's a simple example.
if len(some_list) > 0:
# do something here when the list is not empty
else:
# do something else when the list is empty
However, this is not the best
Pythonic
approach. I
nstead, we can simply examine the container itself, which will be evaluated when the container
True
contains elements.
Although the following code shows you the main container data types, this usage can also be applied to strings (that is, any non-empty string is True).
>>> def check_container_empty(container):
... if container:
... print(f"{container} has elements.")
... else:
... print(f"{container} doesn't have elements.")
...
... check_container_empty([1, 2, 3])
... check_container_empty(set())
... check_container_empty({"zero": 0, "one": 1})
... check_container_empty(tuple())
... [1, 2, 3] has elements.
set() doesn't have elements.
{'zero': 0, 'one': 1} has elements.
() doesn't have elements.
We often use strings as identifiers for specific objects. F
or example, we can use strings as keys in a dictionary. I
n a data science project, strings are usually column names for data. W
hen you select multiple columns, you inevitably need to create a list of strings. I
ndeed, we can create strings using the text in the list. H
owever, we have to write pairs of quotation marks to enclose each string, which is a bit cumbersome for "lazy" people.
Therefore, I prefer to use the
split()
method of strings to create a list of strings, as shown in the following snippet.
>>> # List of strings
... # The typical way
... columns = ['name', 'age', 'gender', 'address', 'account_type']
... print("* Literals:", columns)
...
... # Do this instead
... columns = 'name age gender address account_type'.split()
... print("* Split with spaces:", columns)
...
... # If the strings contain spaces, you can use commas instead
... columns = 'name, age, gender, address, account type'.split(', ')
... print("* Split with commas:", columns)
...
* Literals: ['name', 'age', 'gender', 'address', 'account_type']
* Split with spaces: ['name', 'age', 'gender', 'address', 'account_type']
* Split with commas: ['name', 'age', 'gender', 'address', 'account type']
As shown above,
split()
By default, this method uses spaces as separators and creates a list of strings based on strings.
It is important to note that when you create a list of strings that contain some elements that contain spaces, you can choose to use other types of separators (for example, commas).
This usage is inspired by some built-in features. F
or example, when you create a tuple class, we can do this:
Student = namedtuple(“Student”, [“name”, “gender”, “age”])
T
he string list specifies the "properties" of the tuple. H
owever, you can also define the class to support it locally by:
Student = namedtuple(“Student”, “name gender age”)
For another instance, create an
Enum
class that supports the same alternative solution.
(Recommended tutorial: python tutorial)
In many use cases, we need to define variables with specific values based on conditions, and we can simply use
if ... else
statement to check the condition. H
owever, it requires a few lines of code. I
f you are working with assignments for only one variable, you may need to use a troy expression that checks the condition and completes the assignment with just one line of code. I
n addition, it's shorter in format, making the code cleaner.
Consider the following example.
# The typical way
if score > 90:
reward = "1000 dollars"
else:
reward = "500 dollars"
# Do this instead
reward = "1000 dollars" if score > 90 else "500 dollars"
Sometimes we can get some data from defined functions, and we can take advantage of this and write a simple operation of a troy expression, as shown below.
# Another possible scenario
# You got a reward amount from somewhere else, but don't know if None/0 or not
reward = reward_known or "500 dollars"
# The above line of code is equivalent to below
reward = reward_known if reward_known else "500 dollars"
We often need to read data from a file and write it to a file.
The most common approach is to simply open a file using the built-in
open()
function, which creates a file object that we can manipulate.
>>> # Create a text file that has the text: Hello World!
...
... # Open the file and append some new data
... text_file0 = open("hello_world.txt", "a")
... text_file0.write("Hello Python!")
...
... # Open the file again for something else
... text_file1 = open("hello_world.txt")
... print(text_file1.read())
...
Hello World!
In the previous snippet, we started with a text file with the text
“ Hello World!”
。 W
e then attach some new data to the file. H
owever, after a while, we want to work on the file again. W
hen we read a text file, it still has old data.
In other words, the attached text is not included in the text file.
This is because we didn't close the file object in the first place. I
f you do not close the file, you cannot save the changes. I
ndeed,
close()
can explicitly call the method on the file object. H
owever, we can do this
“with”
statement, which automatically closes the file object for us, as shown below.
When we're done with the file, we can verify that the file is closed by accessing the
closed
property of the file object.
>>> with open("hello_world.txt", "a") as file:
... file.write("Hello Python!")
...
... with open("hello_world.txt") as file:
... print(file.read())
...
... print("Is file close?", file.closed)
...
Hello World!Hello Python!Hello Python!
Is file close? True
In more general terms,
with
statement is a syntax that uses context managers in
Python
T
he previous example involved file operations because these files are shared resources that we are responsible for releasing. T
he context manager can help us get the job done.
As shown earlier, when the file operation is over, the file is automatically closed
with
statement.
Typically, we need to evaluate multiple conditions. T here are several possible scenarios. F or values, we can compare the same variable multiple times. In this case, we can link these comparisons.
# Multiple Comparisons
# The typical way
if a < 4 and a > 1:
# do something here# Do this instead
if 1 < a < 4:
# do somerthing here
In other cases, we can make multiple equal comparisons, and we can use the following
in
keyword for member testing.
# The typical way
if b == "Mon" or b == "Wed" or b == "Fri" or b == "Sun":
# do something here# Do this instead, you can also specify a tuple ("Mon", "Wed", "Fri", "Sun")
if b in "Mon Wed Fri Sun".split():
# do something here
Another technique is to use the built-in
all()
and
any()
functions to evaluate the functionality of multiple conditions. S
pecifically, the
all()
function evaluates when all the elements in the iteration are
True
so the function is suitable for replacing a series of
AND
logical comparisons. O
n the other hand, the
any()
function is calculated to
True
when any element in the iteration is
True
so it is appropriate to replace a series of
OR
logical operations.
The relevant example is shown below.
# The typical ways
if a < 10 and b > 5 and c == 4:
# do somethingif a < 10 or b > 5 or c == 4:
# do something# Do these instead
if all([a < 10, b > 5, c == 4]):
# do somethingif any([a < 10, b > 5, c == 4]):
# do something
In almost all
Python
projects, most code involves creating and calling functions. I
n other words, we keep dealing with function declarations and refactoring. I
n many cases, we need to call a function multiple times. D
epending on the set of parameters, the functionality will be slightly different. H
owever, sometimes a set of parameters may be more commonly used than others, in which case we should consider setting a default value when declaring a function.
Consider the following simple example.
# The original form:
def generate_plot(data, image_name):
"""This function creates a scatter plot for the data"""
# create the plot based on the data
...
if image_name:
# save the image
...# In many cases, we don't need to save the image
generate_plot(data, None)# The one with a default value
def generate_plot(data, image_name=None):
pass# Now, we can omit the second parameter
generate_plot(data)
One thing to note is that if you want to work with variable data types (such as lists, collections) when setting default values, make sure that you use
None
instead of constructors (for
arg_name = []
B
ecause
Python
creates a function object at a defined location, the blank list provided is "stuck" by the function object. I
n other words, a function object is not created immediately when it is called.
Instead, we'll work with the same function object in memory, including the default variable object it originally created, which can cause unexpected behavior.
When we have multiple items in a list, tuple, or string (for example, multiple characters), we often want to calculate how many elements are in each item. To do this, you can write some tedious code for this feature.
>>> words = ['an', 'boy', 'girl', 'an', 'boy', 'dog', 'cat', 'Dog', 'CAT', 'an','GIRL', 'AN', 'dog', 'cat', 'cat', 'bag', 'BAG', 'BOY', 'boy', 'an']
... unique_words = {x.lower() for x in set(words)}
... for word in unique_words:
... print(f"* Count of {word}: {words.count(word)}")
...
* Count of cat: 3
* Count of bag: 1
* Count of boy: 3
* Count of dog: 2
* Count of an: 5
* Count of girl: 1
As shown above, we must first create a collection that contains only unique words. W
e then iterate through the word set and use the
count()
method to find out what happens to each word.
However, there is a better way to use
Counter
class to accomplish this counting task.
>>> from collections import Counter
...
... word_counter = Counter(x.lower() for x in words)
... print("Word Counts:", word_counter)
...
Word Counts: Counter({'an': 5, 'boy': 4, 'cat': 4, 'dog': 3, 'girl': 2, 'bag': 2})
The counter class is available in the
collections
module. T
o use this class, we simply create a
generator:
,
x.lower() for x in words
each item will be counted.
As we can see,
Counter
object is a
dict
mapping object, with each key corresponding to the only item in the word list, and the value is the count of those items.
In addition, if we are interested in finding the items that appear most frequently in the word list, we can
Counter
advantage of the
most_common()
method. T
he following code shows this usage. W
e only need to specify an integer (N) to find the N items most frequently from the list.
With instructions, the object will also be used with other sequence data, such as strings and tuples.
>>> # Find out the most common item
... print("Most Frequent:", word_counter.most_common(1))
Most Frequent: [('an', 5)]
>>> # Find out the most common 2 items
... print("Most Frequent:", word_counter.most_common(2))
Most Frequent: [('an', 5), ('boy', 4)]
In many projects, sorting items in a list is a common task. T
he most basic sorting is based on numbers or alphabetical order, and we can use the built-in
sorted()
function. B
y default, the
sorted()
function sorts the list in ascending order (in fact, it can be iterative). I
f you specify the
reverse
parameter as
True
you can get the item in descending order.
Some simple usages are shown below.
>>> # A list of numbers and strings
... numbers = [1, 3, 7, 2, 5, 4]
... words = ['yay', 'bill', 'zen', 'del']
... # Sort them
... print(sorted(numbers))
... print(sorted(words))
...
[1, 2, 3, 4, 5, 7]
['bill', 'del', 'yay', 'zen']
>>> # Sort them in descending order
... print(sorted(numbers, reverse=True))
... print(sorted(words, reverse=True))
...
[7, 5, 4, 3, 2, 1]
['zen', 'yay', 'del', 'bill']
In addition to these basic usages, we can specify
key
parameters so that complex items, such as tuple lists, can be sorted.
Consider the following example of this situation.
>>> # Create a list of tuples
... grades = [('John', 95), ('Aaron', 99), ('Zack', 97), ('Don', 92), ('Jennifer', 100), ('Abby', 94), ('Zoe', 99), ('Dee', 93)]
>>> # Sort by the grades, descending
... sorted(grades, key=lambda x: x[1], reverse=True)
[('Jennifer', 100), ('Aaron', 99), ('Zoe', 99), ('Zack', 97), ('John', 95), ('Abby', 94), ('Dee', 93), ('Don', 92)]
>>> # Sort by the name's initial letter, ascending
... sorted(grades, key=lambda x: x[0][0])
[('Aaron', 99), ('Abby', 94), ('Don', 92), ('Dee', 93), ('John', 95), ('Jennifer', 100), ('Zack', 97), ('Zoe', 99)]
The above code shows us two examples of advanced sorting by utilizing the
lambda
function passed to the
key
argument. T
he first sorts items in descending order, and the second sorts items in the default ascending order. W
e're going to combine these two requirements, and if you consider using the
reverse
parameter, you might get an incorrect sorting tree, because if you try to sort by multiple criteria, the reverse parameter will apply to all parameters.
See the snippet below.
>>> # Requirement: sort by name initial ascending, and by grades, descending
... # Both won't work
... sorted(grades, key=lambda x: (x[0][0], x[1]), reverse=True)
[('Zoe', 99), ('Zack', 97), ('Jennifer', 100), ('John', 95), ('Dee', 93), ('Don', 92), ('Aaron', 99), ('Abby', 94)]
>>> sorted(grades, key=lambda x: (x[0][0], x[1]), reverse=False)
[('Abby', 94), ('Aaron', 99), ('Don', 92), ('Dee', 93), ('John', 95), ('Jennifer', 100), ('Zack', 97), ('Zoe', 99)]
>>> # This will do the trick
... sorted(grades, key=lambda x: (x[0][0], -x[1]))
[('Aaron', 99), ('Abby', 94), ('Dee', 93), ('Don', 92), ('Jennifer', 100), ('John', 95), ('Zoe', 99), ('Zack', 97)]
As you can see, neither is valid by setting the
reverse
parameter to
True
or
False
I
nstead, the trick is to reverse the scores, so when you sort in the default ascending order, the scores are sorted in reverse because the values are reversed.
However, this method has a warning because inversion can only be used for numeric values, not strings.
A dictionary is an effective type of data that allows us to store data as key-value pairs. I
t requires that all keys be hashed, and storing this data may involve the use of hash tables. T
his approach allows data retrieval and insertion at O(1) efficiency. H
owever, it should be noted that in addition to the built-in
dict
type, we have other dictionaries available. A
mong them, I want to discuss
defaultdict
type.
Unlike the built-in
dict
type,
defaultdict
allows us to set the default factory function, which creates elements when the key does not exist.
>>> student = {'name': "John", 'age': 18}
... student['gender']
...
Traceback (most recent call last):
File "<input>", line 2, in <module>
KeyError: 'gender'
Suppose we're working on words and want to group characters that are the same as lists, and those lists are associated with characters that are keys. T
his is a childish implementation using the built-in
dict
type.
It is important to check whether the
dict
object has a
letter
key, because if the key does not exist, calling the
append()
method throws a
KeyError
exception.
>>> letters = ["a", "a", "c", "d", "d", "c", "a", "b"]
... final_dict = {}
... for letter in letters:
... if letter not in final_dict:
... final_dict[letter] = []
... final_dict[letter].append(letter)
...
... print("Final Dict:", final_dict)
...
Final Dict: {'a': ['a', 'a', 'a'], 'c': ['c', 'c'], 'd': ['d', 'd'], 'b': ['b']}
Let's look at how to write cleaner code using
defaultdict
Although the example is simple, it only gives us some ideas about
defaultdict
class, which allows us to work with keys that do not exist in dictionary objects.
>>> from collections import defaultdict
...
... final_defaultdict = defaultdict(list)
... for letter in letters:
... final_defaultdict[letter].append(letter)
...
... print("Final Default Dict:", final_defaultdict)
...
Final Default Dict: defaultdict(<class 'list'>, {'a': ['a', 'a', 'a'], 'c': ['c', 'c'], 'd': ['d', 'd'], 'b': ['b']})
(Recommended micro-course: python3 basic micro-course)
Before reading this article, we may have learned some tricks, but we hope to still know them.
Practicing these idioms in your project will make your
Python
code more readable and performing.
Article Source: Public No. - Little White School Vision
Author: Peanuts
These are some of the 10 tips for speeding up Python programming.