Part 1 – Part 2 – Part 3 – Part 4– Part 5 – Part 6 – Part 7
I’m back with a somewhat unplanned part seven, where I’ll return to some topics that came up on the official practice exam for the Microsoft Technology Associate certification in Python. Many of these I touched on in previous posts, but I felt it was worth revisiting to go deeper on some items that I may have glossed over or not covered at all.
*args
and **kwargs
The concepts of *args
and **kwargs
came up on a couple of questions. Here’s a good article on Real Python on the topic.
Simply put, *args allow a programmer to send any number of positional arguments to a function, which are then transformed into a tuple through which the function can iterate. Importantly, function definition parameters noted with *
are not required arguments, meaning we can choose to not send any arguments, such as when calling the function shown in the Real Python article:
def add(*args): result = 0 for x in args: result += x return result print(add()) # 0 print(add(1, 2, 3.14)) # 6.14
Since *args
get turned into a tuple, they cannot be changed. Keep this in mind if you are returning an iterable value from *args
in your functions – you’ll need to cast it as a list instead.
Similarly, **kwargs
also allows a programmer to handle any number of arguments in a function, but in this case, they are keyword arguments, meaning that each argument gets a name. For example:
def star_wars_names(**kwargs): for k, v in kwargs.items(): print(k, v) star_wars_names( Luke="Skywalker", Darth="Vader", Leia="Organa", Han="Solo", Chewbacca="" )
Output
Luke Skywalker Darth Vader Leia Organa Han Solo Chewbacca
If you haven’t had a chance to use these yet, they can be a little hard to understand in the abstract. Personally, I didn’t comprehend how these worked until I had a large file of JSON data that I needed to convert into a database format. Using the **kwargs
argument saved me a ton of manual coding through this task.
I’m always needing to remind myself that when you use args
and kwargs
in the functions themselves, the *
operator is not required. The *
operator is only required in the function definition’s call signature.
String Methods to Know
I wrote a good amount of words on strings and string methods, but the practice exam has made me aware of a few methods and other topics I should go deeper on. I was also remiss in not linking to the full list of Python string methods, this one neatly compiled by W3 Schools. It’s definitely worth reading down the list and doing a self-quiz of which methods you know and which you do not.
find()
and index()
The find()
method searches a string for a specified value and returns its index. Note that this is a synonym for the index()
method, which does the exact same thing. Both find()
and index()
have two optional arguments allowing to set the start and stop points of the search, searching a sub-string instead of the whole thing: string.find(value [, start, end])
. The optional start argument came up on at least one practice exam question. If the specified string appears multiple times in the string being searched, the index of its first occurrence is returned.
center()
, ljust()
, and rjust()
These three methods perform the same way, returning a centered, left-justified, or right-justified version of the string as specified. They take an integer as a required argument specifying the total number of characters the returned string should occupy. Unused characters default to a space:
>>> "python".rjust(10) ' python'
Each of these methods also takes a second argument equal to a single character that can fill the additional characters in lieu of a space:
>>> "python".center(10, "#") '##python##'
It’s worth noting that the practice exam also used the chr()
function in conjunction with one of these methods. This function takes an integer equal to a unicode character code (between 0 and 1,114,111) and returns the corresponding character.
Going Deeper on Advanced String Formatting
While the %
string operator from Python 2 is still available in Python 3, most Python users have moved to the more flexible format()
method. However, at least one question on the practice exam formatted strings using %
, so it’s worth learning the syntax if you’ve been writing in Python 3 for a while.
That said, the format()
method is much more prevalent on this exam, so it’s worth going through the finer points of the 2006 PEP where this method was documented. Here’s a quick overview of the items worth knowing for the exam:
1. Input Identifiers
While not strictly required, there may be circumstances where it makes sense to use input identifiers, which can be either index- or keyword-based:
>>> a = "Red" >>> b = "Dead" >>> d = "Revolver" >>> "{0} {1} {c}".format(a, b, c=d) 'Red Dead Revolver'
Each variable enclosed in curly braces is known as a field.
2. Format Specifiers
We can introduce a :
to adjust the formatting of a specific field. It’s easy for me to confuse this syntax with string slicing, but note that everything to the left of the :
is only the input identifier. For example:
print("{0:10,.2f}".format(1369))
We can also use an f-string alternative to the format()
method:
value = 1369 print(f"{value:10,.2f}")
Let’s break down the code found between the {}
:
- The initial 0 to the left of
:
is merely the input identifier (in the first example). It is not required in this case, but it can make it easier when you’re formatting multiple variables, especially if you need to do so out of order for any reason.value
(in the second example) is the variable set in the line above it. - The
:
indicates the beginning of our format specifiers. - The
10
after the:
indicates that the formatted value is to take up ten characters of space. - The
,
indicates the value should be comma-separated in typical numerical style (1,000; 1,000,000; 1,000,000,000; etc.). - The
.
indicates precision. In this case, the2f
means that the value should be a fixed-point number with two decimals. - Therefore, printing the above statement gives us this:
1,369.00
Note that the 1,369.00 value took up eight characters, so two leading spaces were provided. Numbers are right-aligned by default, but we could left-align this string by adding another character to our format specifier:
>>> print("{0:<10,.2f}".format(1369)) 1,369.00
The spaces filling this out to ten characters are now on the right. Note that strings are left-aligned by default, so the opposite arrow symbol is used to right-align them (again, spaces are shown as escape characters for clarity but are not rendered this way by Python itself):
>>> print("{:>10}".format("Python")) \s\s\s\sPython
There are a lot of format specifiers listed in this PEP, but of the questions on the practice exam, most dealt with relatively simple formatting like that above. As the PEP notes, the full syntax of a stand format specifier is:
[[fill]align][sign][#][0][minimumwidth][.precision][type]
It’s definitely worth reading and practicing with the explanations and options available for these.
File Methods to Know
I went over reading and writing a text file with pretty good detail, but there are several file methods I didn’t cover that are worth knowing. Assuming we have opened our file as f:
f.flush()
f.flush()
clears the internal file buffer. That’s about all the documentation says, and I really didn’t know what it means. Here’s the breakdown: when we write data to a file, for efficiency reasons, we are actually pushing the data into the internal buffer for later writing. If the program breaks prior to emptying that internal buffer, our data was not actually written to the file. f.flush()
forces the data in the internal buffer to be written to the file. This might be useful if you’re writing a lot of data in a program that could potentially crash during execution.
f.seek()
f.seek()
sets the file’s current position in characters. For example, say we have the following file, python.txt:
Python is an excellent programming language!
We can see f.seek()
in action by opening this file:
with open("lines.txt", "r") as f: f.seek(4) f.read()
Output
on is an excellent programming language!
Here, f.seek()
took us to the fourth position (based on a zero-index) in the file, then we read the remaining amount of the file. We can also use f.readline()
like this to get the rest of the current line. This could be useful with a for loop to eliminate repeated unwanted characters from the beginning of each line in a file.
f.tell()
This is a useful but fairly simple one: this method simply returns the current position in a file. Expanding on our last example:
with open("python.txt", "r") as f: f.seek(4) position = f.tell() # returns 4
This was necessary to know the correct answer to at least one question, so definitely have this method in your back pocket.
f.fileno()
f.fileno()
returns an integer equal to the file descriptor used by the underlying implementation. This can be useful with other lower-level functions, but I have never found a particular usefulness for this function in my own work. It appeared as a wrong answer on at least one question, but not as a correct one.
>>> with open("python.txt", "r") as f: ... f.fileno() 3
Know These Well Enough to Not Be Tricked
Finally, they’ll try to trick you with non-existent methods that are similar to real ones. For example, f.readall()
does not exist, but f.read()
does. If both are presented as options, will you know which one is the actual method and which is an attractive distractor?
Other File Types – Images, CSV, etc.
While I did a good job covering text files earlier, there were questions that came up on how to deal with other kinds of files using Python’s built-in modules. While the questions relating to these were solvable without deep knowledge of their respective modules, basic knowledge seemed to be expected for a few questions.
pickle
I admit I had never heard of pickle
before taking the practice exam for this test. The documentation for the module, which handles Python object serialization, can be found here. I don’t really have the expertise or desire to get into this module in depth, so my preparation in relation to this exam is to know that the following four methods exist in relation to pickle
:
pickle.dump() # writes data to a file object pickle.dumps() # writes data to a bytes object instead of a file pickle.load() # reads data from a file object pickle.loads() # reads data from a bytes object
These are similar to the methods found in the json
module, which I did not see on the practice exam, so I won’t be covering it, but it could be important to know.
csv
I was a bit more familiar with the csv
module, but I have not used it extensively in a project. In this case, the practice exam seemed largely to be testing whether I knew that I first needed to initialize a reader or writer, then do any reading or writing with that object. For example:
import csv with open("file.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerows(data)
Both writer.writerows(data)
and writer.writerow(data)
are available to writer objects. For reader objects, initialized with something like reader = csv.reader(f)
, it’s worth knowing that the reader object returns a Python list of values through which one can iterate.
There’s plenty more on csv
, but for the purposes of this exam, I’m comfortable with knowing this basic syntax and functionality – I’ve covered more here than came up on the practice exam, anyway.
Operator Nuances to Know
- Are you sure you know the difference between the
/
and//
operators off the top of your head? If not, commit that to memory, as you won’t have an interpreter available to double-check. Integer division uses the//
operator. This comes up in calculations on this exam a lot. - At least one question involved scientific notation like this:
float(4.1E-2)
. The E denotes that 4.1 is equal to itself times 10 raised to the power of the number after E, in this case, -2. Practically, this means that the E-2 moves the decimal two places to the left, meaning thatfloat(4.1E-2) == 0.041
. - What is 1 % 5, or for that matter, the result of any modulus operation where the dividend is smaller than the divisor? This isn’t something I’d ever seen in practice but that came up on the practice exam. The answer is always the initial smaller dividend (1 in the example), as the initial number after the operation is the remainder.
More Methods from the sys
Module
These are new to me so I won’t go deep on them, but the following functions are available: sys.stdout
, sys.stdin
, sys.stderr
. One question used an example similar to this code, which is used to capture print statements in the program to a file:
import sys with open("text.txt", "w") as f: sys.stdout = f print("This will be saved to the file!") print("As will this!")
Output
# The console does not print these any statements here. # sys.stdout has effectively highjacked the print function!
text.txt
This will be saved to the file! As will this!
I noted that using print()
outside of the with open()
block threw an I/O error, which I don’t really get – I would think that closing the file would give me back the use of the print()
command. This is a topic to dig deeper into another time, but for the purposes of this exam, knowing what the above code does will do just fine.
sys.stdin
has to do with reading user input from a file, which can be desirable in some circumstances. sys.stderr
has to do with error logging on the system level. The latter two commands were provided only as wrong answers on the practice exam.
Information Available at sys.platform
, sys.executable
, sys.version
, and sys.path
The sys
module has useful information about the local Python environment callable with simple attributes:
>>> import sys >>> sys.platform 'win32' >>> sys.executable 'C:\\Python37-32\\python.exe' >>> sys.version '3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 21:26:53) [MSC v.1916 32 bit (Intel)]' >>> sys.path ['', 'C:\\Python37-32\\python37.zip', 'C:\\Python37-32\\DLLs', 'C:\\Python37-32\\lib', 'C:\\Python37-32', 'C:\\Users\\Danny\\AppData\\Roaming\\Python\\Python37\\site-packages', 'C:\\Python37-32\\lib\\site-packages']
More Methods from the math
Module
Some more straightforward math
methods that came up as right and wrong answers on the practice exam:
math.fsum()
This takes an iterable of numbers and returns the sum of that iterable with mathematical accuracy. This is especially useful for floating point numbers, which can lose precision as the number of decimal places grow.
>>> import math >>> math.fsum([0.1, 0.1, 0.001, 0.0001]) 0.2011
math.factorial()
This takes a number and returns its factorial:
>>> math.factorial(5) 120
(This is equal to 5 * 4 * 3 * 2 * 1).
math.gcd()
This takes two numbers and returns the greatest common denominator of each of them:
>>> import math >>> math.gcd(120, 75) 15
Know These datetime
Directives
You will be expected to know the following directives for formatting dates and times (simplified explanations based on U.S. locale; your results may differ):
%A – Day of the week (“Monday”)
%a – Day of the week abbreviated (“Mon”)
%B – Month spelled out (“February”)
%b – Month abbreviated (“Feb”)
%m – Two-digit, zero-padded month (“02”)
%d – Two-digit, zero-padded day of the month (“03”)
%Y – Four-digit year (“2020”)
%y – Two-digit, zero-padded year (“20”)
%H – Two-digit, zero-padded hour based on a 24-hour clock (“21”)
%I – Two-digit, zero-padded hour based on a 12-hour clock (“09”)
%M – Two-digit, zero-padded minute (“02”)
%S – Two-digit, zero-padded second (“42”)
Truth be told, I didn’t see %a or %I in any practice exam questions, but for the sake of completion and the fact that they’re likely to come up, I’ve added them here. All the others I saw in practice questions. Definitely give these a few reviews until you’re sure you know them off the top of your head.
Tidbits from the random
module
random.choices(population, k=size)
without a k (size) argument returns a list with a size of one.random.sample(population, size)
always returns a list, even if the sample size is one.random.SystemRandom()
came up. This is an alternative torandom.random()
that generates a random number based on variables from the system and thus ignores the value fromrandom.seed()
.
Final Odds and Ends for Consideration
- Lines can end in a semicolon in Python without an error. While not required (or even recommended), it is allowed, since Python does support multiple statements on one line divided by a semicolon. Don’t do this, though.
- Order of operations – remember, operators at the same level (such as * and /), are resolved left to right.
- Be on the lookout for indentation errors in questions – this is particularly annoying because the answer options were as a rule not indented correctly.
- You’ll need to know that True in arithmetic expressions is converted to 1 and False is converted to 0. So,
2 + True
will equal3
. - Four set operators that I didn’t cover made an appearance:
&
,^
,|
, and-
. I’m still not going to cover them – set theory is well beyond the scope of this post. Overachievers might get to know them prior to an exam. - random.randint(a, b) is inclusive, whereas range(a, b) is exclusive of b. One question combined these and it got a little tricky!
os.makedir
,os.makedirs
,os.chdir
, andos.listdir
all made an appearance in practice questions. These are self-explanatory if you’re familiar with Unix commands (except thatos.makedirs
might need some explanation. Very simply, it works recursively and creates an entire path rather than just a single folder).- You’ll probably see a raw string in order to include a backslash in a path:
r'c:\users\username\code\file.py'
. Be aware of the differences between backslashes and forward slashes and which ones need to be escaped.
That’s a lot of stuff – my longest post in the series. It also addressed some of the areas in which I was weakest, which means that when I take this exam, which is scheduled extremely soon, I’ll be as ready as I need to be.
Update 2/17/2020: I took the certification exam a couple of weeks ago and passed! Huzzah!