## How to Stand Out in a Python Coding Interview - Functions, Data Structures & Libraries

Rated 4.5/5 based on 14 customer reviews

# How to Stand Out in a Python Coding Interview - Functions, Data Structures & Libraries

6K

Any coding interview is a test which primarily focuses on your technical skills and algorithm knowledge. However, if you want to stand out among the hundreds of interviewees, you should know how to use the common functionalities of Python in a convenient manner.

The type of interview you might face can be a remote coding challenge, a whiteboard challenge or a full day on-site interview. So if you can prove your coding skills at that moment, the job letter will reach you in no time. You may go through some of the top Python interview questions and answers provided by experts which are divided into three levels- beginner, intermediate and advanced. A thorough practice of these questions and answers on Python will definitely help you achieve your dream job as a Python Developer, Full Stack engineer, and other top profiles.

A Python coding interview is basically a technical interview. They are not just about solving problems, they are more about how technically sound you are and how you can write clean productive Python code. This will show your depth of knowledge about Python and how you can use Python’s built-in functions and libraries to implement your code. Go through our Python Tutorials to learn more about  concepts related to Python. Let us look into some of the built-in functions provided by Python and how to select the correct one, learn about the effective use of data structures, how standard libraries in Python can be utilized and so on.

## How to Select the Correct Built-in Function?

Python’s library of built-in functions is small as compared to the standard library. The built-in functions are always available and are not needed to be imported. It is suggested to learn each function before sitting for the interview. Till then, let us learn a few built-in functions and how to use them and also what alternatives can be used.

### Perform iteration with enumerate() instead of range()

Consider a situation during a coding interview: You have a list of elements and you have to iterate over the list with the access to both the indices and values.

To differentiate between iteration with enumerate()  and iteration with range(), let us take a look at the classic coding interview question FizzBuzz. It can be solved by iterating over both indices and values. You will be given a list of integers and your task will be as follows:

1. Replace all integers that are evenly distributed by 3 with “fizz”.
2. Replace all integers divisible by 5 with “buzz”.
3. Replace all integers divisible by 3 and 5 with “fizzbuzz”.

Developers make use of range() in these situations which can access the elements by index:

>>> list_num = [30, 29, 10, 65, 95, 99]
>>> for i in range(len(list_num)):
if list_num[i] % 3 == 0 and list_num[i] % 5 == 0:
list_num[i] = 'fizzbuzz'
elif list_num[i] % 3 == 0:
list_num[i] = 'fizz'
elif list_num[i] % 5 == 0:
list_num[i] = 'buzz'

>>> list_num
['fizzbuzz', 22, 14, 'buzz', 97, 'fizz']

Though range() can be used in a lot of iterative methods, it is better to use enumerate() in this case since it can access the element’s index and value at the same time:

>>> list_num = [30, 29, 10, 65, 95, 99]
>>> for i,num in enumerate(list_num):
if list_num[i] % 3 == 0 and list_num[i] % 5 == 0:
list_num[i] = 'fizzbuzz'
elif list_num[i] % 3 == 0:
list_num[i] = 'fizz'
elif list_num[i] % 5 == 0:
list_num[i] = 'buzz'

>>> list_num
['fizzbuzz', 22, 14, 'buzz', 97, 'fizz']

The enumerate() function returns a counter and the element value for each element. The counter is set to 0 by default which is also the element’s index.

However, if you are not willing to start your counter from 0, you can set an offset using the start parameter:

>>> list_num = [30, 29, 10, 65, 95, 99]
>>> for i, num in enumerate(list_num, start=11):
print(i, num) 
11 30
12 29
13 10
14 65
14 95
16 99

You can access all of the same elements using the start parameter. However, the count will start from the specified integer value.

### Using List Comprehensions in place of map() and filter()

Python supports list comprehensions which are easier to read and are analogous in functionality as map() and filter(). This is one of the reasons why Guido van Rossum, the creator of Python felt that dropping map() and filter() was quite uncontroversial.

An example to show  map() along with this equivalent list comprehension:

>>> list_num = [1, 2, 3, 4, 5, 6]
>>> def square_num(z):
...    return z*z
...
>>> list(map(square_num, list_num))
[1, 4, 9, 16, 25, 36]

>>> [square_num(z) for z in numbers]
[1, 4, 9, 16, 25, 36]

Though map() and list comprehension returns the same values but the list comprehension part is easier to read and understand.

An example to show  filter() and its equivalent list comprehension:

>>> def odd_num_check(z):
return bool(z % 2)

>>> list(filter(odd_num_check, num_list))
[1, 3, 5]

>>> [z for z in numbers if odd_num_check(z)]
[1, 3, 5]

It is the same with filter()as it was with map(). The return values are the same but the list comprehension is easier to follow.

List comprehensions are easier to read and beginners are able to catch it more intuitively.

Though other programming language developers might argue to the fact but if you make use of list comprehensions during your coding interview, it is more likely to communicate your knowledge about the common functionalities to the recruiter.

### Debugging With breakpoint() instead of print()

Debugging is an essential part of writing software and it shows your knowledge of Python tools which will be useful in developing quickly in your job in the long run. However, using print() to debug a small problem might be good initially but your code will become clumsy. On the other hand, if you use a debugger like breakpoint(), it will always act faster than print().

If you’re using Python 3.7, you can simply call breakpoint() at the point in your code where you want to debug without the need of importing anything:

# Complicated Code With Bugs
...
...
...
breakpoint()

Whenever you call breakpoint(), you will be put into The Python Debugger - pdb. However, if you’re using Python 3.6 or older, you can perform an explicit importing which will be exactly like calling breakpoint():

import pdb; pdb.set_trace()

In this example, you’re being put into the pdb by the pdb.set_trace().  Since it’s a bit difficult to remember, it is recommended to use breakpoint() whenever a debugger is needed. There are also other debuggers that you can try. Getting used to debuggers before your interview would be a great advantage but you can always come back to pdb since it’s a part of the Python Standard Library and is always available.

### Formatting Strings with the help of f-Strings

It can be confusing to know what type of string formatting should we use since Python consists of a number of different string formatting techniques. However, it is a good approach and is suggested to use Python’s f-strings during a coding interview for Python 3.6 or greater.

Literal String Interpolation or f-strings is a powerful string formatting technique that is more readable, more concise, faster and less prone to error than other formatting techniques. It supports the string formatting mini-language which makes string interpolation simpler. You also have the option of adding new variables and Python expressions and they can be evaluated before run-time:

>>> def name_and_age(name, age):
return f"My name is {name} and I'm {age / 10:.5f} years old."

>>> name_and_age("Alex", 21)
My name is Alex and I'm 2.10000 years old.

The f-string allows you to add the name Alex into the string and his corresponding age with the type of formatting you want in one single operation.

Note that it is suggested to use Template Strings if the output consists of user-generated values.

### Sorting Complex Lists with sorted()

There are a lot of interview questions that are mostly based on sorting and it is one of the most important concepts you should be clear about before you sit for a coding interview. However, it is always a better option to use sorted() unless you are asked to make your own sorting algorithm by the interviewer.

Example code to illustrate simple uses of sorting like sorting numbers or strings:

>>> sorted([6,5,3,7,2,4,1])
[1, 2, 3, 4, 5, 6, 7]

>>> sorted(['IronMan', 'Batman', 'Thor', 'CaptainAmerica', 'DoctorStrange'], reverse=False)
['Batman', 'CaptainAmerica', 'DoctorStrange', 'IronMan', 'Thor']

sorted() performs sorting in ascending order by default and also when the reverse argument is set to False.

If you sorting complex data types, you might want to add a function which allows custom sorting rules:

>>> animal_list = [
...    {'type': 'bear', 'name': 'Stephan', 'age': 9},
...    {'type': 'elephant', 'name': 'Devory', 'age': 5},
...    {'type': 'jaguar', 'name': 'Moana', 'age': 7},
... ]
>>> sorted(animal_list, key=lambda animal: animal['age'])
[
{'type': 'elephant', 'name': 'Devory', 'age': 5},
{'type': 'jaguar', 'name': 'Moana', 'age': 7},
{'type': 'bear, 'name': 'Stephan, 'age': 9},
]

You can easily sort a list of dictionaries using the lambda keyword. In the example above, the lambda returns each element’s age and the dictionary is sorted in ascending order by age.

## Effective Use of Data Structures

Data Structures are one of the most important concepts you should know before getting into an interview and if you choose the perfect data structure during an interviewing context, it will certainly impact your performance.

Python’s standard data structure implementations are incredibly powerful and give a lot of default functionalities which will surely be helpful in coding interviews.

### Storing Values with Sets

Make use of sets instead of lists whenever you want to remove duplicate elements from an existing dataset.

Consider a function random_word that always returns a random word from a set of words:

>>> import random
>>> words = "all the words in the world".split()
>>> def random_word():
return random.choice(words)

In the example above, you need to call random_word repeatedly to get 1000 random selections and then return a data structure that will contain every unique word.

Let us look at three approaches to execute this – two suboptimal approaches and one good approach.

An example to store values in a list and then convert into a set:

>>> def unique_words():
words = []
for _ in range(1000):
words.append(random_word())
return set(words)
>>> unique_words()
{'planet', 'earth', 'to', 'words'}

In this example, creating a list and then converting it into a set is an unnecessary approach. Interviewers notice this type of design and questions about it generally.

Worse Approach

You can store values into a list to avoid the conversion from list to a set. You can then check for the uniqueness by comparing new values with all current elements in the list:

>>> def unique_words():
words = []
for _ in range(1000):
word = unique_words()
if word not in words:
words.append(word)
return words
>>> unique_words()
{'planet', 'earth', 'to', 'words'}

This approach is much worse than the previous one since you have to compare every word to every other word already present in the list. In simple terms, the time complexity is much greater in this case than the earlier example.

Good Approach

In this example, you can skip the lists and use sets altogether from the beginning:

>>> def unique_words():
words = set()
for _ in range(1000):
return words
>>> unique_words()
{'planet', 'earth', 'to', 'words'}

This approach differs from the second approach as the storing of elements in this approach allows near-constant-time-checks whether a value is present in the set or not whereas linear time-lookups were required when lists were used. The time complexity for this approach is O(N) which is much better than the second approach whose time complexity grew at the rate of O(N²).

### Saving Memory with Generators

Though lists comprehensions are convenient tools, it may lead to excessive use of memory.

Consider a situation where you need to find the sum of the first 1000 squares starting with 1 using list comprehensions:

>>> sum([z * z for z in range(1, 1001)])
333833500

Your solution returns the correct answer by making a list of every perfect square and then sums the values. However, the interviewer asks you to increase the number of perfect squares.

Initially, your program might work well but it will gradually slow down and the process will be changed completely.

However, you can resolve this memory issue just by replacing the brackets with parentheses:

>>> sum((z * z for z in range(1, 1001)))
333833500

When you make the change from brackets to parentheses, the list comprehension changes to generator expressions. It returns a generator object. The object calculates the next value only when asked.

Generators are mainly used on massive sequences of data and in situations when you want to retrieve data from a sequence but don’t want to access all of it at the same time.

### Defining Default Values in Dictionaries with .get() and .setdefault()

Adding, modifying or retrieving an item from a dictionary is one of the most primitive tasks of programming and it is easy to perform with Python functionalities. However, developers often check explicitly for values even its not necessary.

Consider a situation where a dictionary named shepherd exists and you want to get that cowboy’s name by explicitly checking for the key with a conditional:

>>> shepherd = {'age': 20, 'sheep': 'yorkie', 'size_of_hat': 'large'}
>>> if 'name' in shepherd:
name = shepherd['name']
else:
name = 'The Man with No Name'

>>> name

In this example, the key name is searched in the dictionary and the corresponding value is returned otherwise a default value is returned.

You can use .get() in a single line instead of checking keys explicitly:

>>> name = shepherd.get('name', 'The Man with No Name')

The get() performs the same operation as the first approach does, but they are now handled automatically.

However, .get() function does not help in situations where you need to update the dictionary with a default value while still accessing the same key. In such a case, you again need to use explicit checking:

>>> if 'name' not in shepherd:
shepherd['name'] = 'The Man with No Name'

>>> name = shepherd['name']

However, Python still offers a more elegant way of performing this approach using .setdefault():

>>> name = shepherd.setdefault('name', 'The Man with No Name')

The .setdefault() function performs the same operation as the previous approach did. If name exists in shepherd, it returns a value otherwise it sets shepherd[‘name’]  to The Man with No Name and returns a new value.

## Taking Advantage of the Python Standard Library

Python’s functionalities are powerful on its own and all the things can be accessed just by using the import statement. If you know how to make good use of the standard library, it will boost your coding interview skills.

### How to handle missing dictionaries?

You can use .get() and .setdefault() when you want to set a default for a single key. However, there will be situations where you will need to set a default value for all possible unset keys, especially during the context of a coding interview.

Consider you have a  group of students and your task is to keep track of their grades on assignments. The input value is a tuple with student_name and grade. You want to look upon all the grades for a single student without iterating over the whole list.

An example to store grade data using a dictionary:

>>> grades_of_students = {}
('alex', 89),
('bob', 95),
('charles', 81),
('alex', 94),
]

>>> student_grades
{'alex': [89, 94], 'bob': [95], 'charles': [81]}

In the example above, you iterate over the list and check if the names are already present in the dictionary or not. If it isn’t, then you add them to the dictionary with an empty list and then append their actual grades to the student’s list of grades.

However, the previous approach is good but there is a cleaner approach for such cases using the defaultdict:

>>> from collections import defaultdict
student_grades[name].append(grade)

In this approach, a defaultdict is created that uses the list() with no arguments. The list()returns an empty list. defaultdict calls the list() if the name does not exist and then appends the grade.

Using the defaultdict, you can handle all the common default values at once and need not worry about default values at the key level. Moreover, it generates a much cleaner application code.

### How to Count Hashable Objects?

Pretend you have a long string of words with no punctuation or capital letters and you are asked to count the number of the appearance of each word. In this case, you can use collections.Counter that uses 0 as the default value for any missing element and makes it easier and cleaner to count the occurrence of different objects:

>>> from collections import Counter
>>> words = "if I am there but if \
... he was not there then I was not".split()
>>> counts = Counter(words)
>>> counts
Counter({'if': 2, 'there': 2, 'was': 1, 'not': 2, 'but': 1, ‘I’: 2, ‘am’: 1, }

When the list is passed to Counter, it stores each word and also the number of occurrences of that word in the list.

If you want to know the two most common words in a list of strings like above, you can use .most_common() which simply returns the n most frequently inputs by count:

>>> counts.most_common(2)
[('if': 2), ('there': 2), ('not': 2), (‘I’: 2)]
How to Access Common String Groups?

If you want to check whether ‘A’ > ‘a’ or not, you have to do it using the ASCII chart. The answer will be false since the ASCII value for A is 65 and a is 97, which is clearly greater.

However, it would be a difficult task to remember the ASCII code when it comes to lowercase and uppercase ASCII characters and also this method is a bit clumsy. You can use the much easier and convenient constants which are a part of the string module

An example to check whether all the characters in a string are uppercase or not:

>>> import string
>>> def check_if_upper(word):
for letter in word:
if letter not in string.ascii_uppercase:
return False
return True

>>> check_if_upper('Thanks Alex')
False
>>> check_if_upper('ROFL')
True

The function check_if_upper iterates over the letters in words, and checks whether the letters are part of string.ascii_uppercase. It is set to the literal ‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’.

There are a number of string constants that are frequently used for referencing string values that are easy to read and use. Some of which are as follows:

• string.ascii_letters
• string.ascii_upercase
• string.ascii_lowercase
• string.ascii_digits
• string.ascii_hexdigits
• string.ascii_octdigits
• string.ascii_punctuation
• string.ascii_printable
• string.ascii_whitespace

### Conclusion

Clearing interview with confidence and panache is a skill. You might be a good programmer but it’s only a small part of the picture. You might fail to clear a few interviews, but if you follow a good process, it will certainly help you in the long run. Being enthusiastic is an important factor that will have a huge impact on your interview results. In addition to that is practice. Practice always helps. Brush up on all the common interview concepts and then head off to practicing different interview questions. Interviewers also help during interviews if you can communicate properly and interact. Ask questions and always talk through a brute-force and optimized solution.

Let us now sum up what we have learned in this article so far:

• To use enumerate() to iterate over both indices and values.
• To debug problematic code with breakpoint().
• To format strings effectively with f-strings.
• To sort lists with custom arguments.
• To use generators instead of list comprehensions to save memory.
• To define default values when looking up dictionary keys.
• To count hashable objects with collections.Counter class.

Hope you have learned about most of the powerful Python’s built-in functions, data structures, and standard library packages that will help you in writing better, faster and cleaner code. Though there are a lot of other things to learn about the language, join our Python certification course to gain more skills and knowledge.

### Priyankur Sarkar

Data Science Enthusiast

Priyankur Sarkar loves to play with data and get insightful results out of it, then turn those data insights and results in business growth. He is an electronics engineer with a versatile experience as an individual contributor and leading teams, and has actively worked towards building Machine Learning capabilities for organizations.

## How to Build a Python GUI Application With wxPython

A Graphical User Interface or GUI is a user interface that includes graphical elements that enable a person to communicate with electronic devices like computers, hand-held devices, and other appliances. It displays information using icons, menus, and graphics. They are handled with the help of a pointing device such as a mouse, trackball or a stylus.A GUI is basically an application that has windows, buttons and lots of other widgets that allows a user to interact with your application. A web browser is a common example of a GUI that has buttons, tabs, and the main window and where the content is displayed.It was developed by the Xerox Palo Alto research laboratory in the late 1970s. Today, every OS has its own GUI. Software applications make use of these and develop their own GUIs.Python contains many GUI toolkits, out which Tkinter, wxPython, and PyQt are the important ones. All these toolkits have the ability to work with Windows, macOS, and Linux with the additional quality of working on mobile phones.How to get started with wxPython?wxPython was first released in the year 1998. It is an open-source cross-platform Python GUI toolkit used as a wrapper class around a C++ library called wxWidgets. The main feature of wxPython which distinguishes itself from other toolkits like PyQt and Tkinter is that it uses actual widgets on the native platform where required. This allows the wxPython applications to look native to the operating system in which it is running.The wxPython toolkit contains a lot of core widgets along with many custom widgets which you can download from the Extra Files section of the wxPython official page.Here, there is a download of the wxPython demo package which is an application demonstrating the robustness of the widgets included with wxPython. The main advantage of this demo is that you can view it one tab and run it in another and it also allows to edit and re-run the code to observe the changes.Installing wxPythonYou will be using the latest wxPython release, wxPython 4, which is also called the wxPython’s Project Phoenix. It is a new implementation of wxPython that aims at improving the speed, maintainability, and extensibility of wxPython. The wxPython 3 and wxPython 2 were built only for Python 2. The maintainer of wxPython rejected a lot of aliases and cleaned up a lot of code to make wxPython more easy and Pythonic.If you are migrating from an older version of wxPython to wxPython 4, take a look at the following references:Classic version vs project PhoenixPhoenix Migration GuideThe Phoenix version is compatible with both Python 2.7 and Python 3. You can use pip to install wxPython 4:$pip install wxpythonYou will get a prerequisites section on the Github page of wxPython which will provide information to install wxPython on Linux systems.You can also look into the Extras Linux section to learn about the Python wheels for both GTK2 and GTK3 versions. To install one of the wheels, use the command below:$ pip install -U -f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-18.04/ wxPythonRemember to modify the command to match with the version of Linux.Components of GUIAs mentioned earlier, GUI is nothing but an interface that allows user interaction.Common components of the user interfaces:Main Window.Menu.Toolbar.Buttons.Text Entry.Labels.These items are generally known as widgets. wxPython supports many other common widgets and many custom widgets that are arranged in a logical manner by a developer to allow user interaction.Event LoopsA GUI works by waiting for the user to perform an action. This is known as an event. An event occurs when something is typed by the user or when the user uses their mouse to press a button or some widget while the application is in focus.The GUI toolkit runs an infinite loop called an event loop underneath the covers. The task of the event loop is to act on occurred events on the basis of what the developer has coded the application to do. The application ignores the event when it is not able to catch it.When you are programming a graphical user interface, make sure to attach the widgets to event handlers in order to make your application do something.You can also block an event loop to make the GUI unresponsive which will appear to freeze to the user. This is a special consideration for you to keep in mind while working with event loops. Launch a special thread or process whenever a GUI takes longer than a quarter of a second to launch a process.The frameworks of wxPython contain special thread-safe methods that you can use to communicate back to your application. This informs the thread is finished or given an update.How to create a Skeleton Application?An application skeleton is basically used for prototyping. It is a user interface comprising of widgets that do not contain event handlers. You just need to create the GUI and show it to the stakeholders for signing off and avoid spending time on the backend logic.An example of creating a Hello World application with Python:import wx   application = wx.App() framework = wx.Frame(parent=None, title='Hello World') framework.Show() app.MainLoop()In the example above, there are two parts of the program – wx.App and wx.Frame. The former one is wxPython’s application object which is basically required for running the GUI. It initiates the .MainLoop() which is the event loop you have learned earlier.The latter part creates a window for user interaction. It informs wxPython that the frame has no parent and its title is Hello World. If you run the code above, this is how it will look like:The application will look different if you execute it in Mac or Linux.Note: Mac users may get the following message: This program needs access to the screen. Please run with a Framework build of Python, and only when you are logged in on the main display of your Mac. If you see this message and you are not running in a virtualenv, then you need to run your application with pythonw instead of python. If you are running wxPython from within a virtualenv, then see the wxPython wiki for the solution.The minimize, maximize and exit will be included in the wx.Frame by default. However, most wxPython code will require you to make the wx.Frame as a subclass and other widgets in order to grab the full power of the toolkit.Let us rewrite the code using class:import wx   class MyFramework(wx.Frame):     def frame(self):         super().frame(parent=None, title='Hello World') self.Show()   if __name__ == '__main__':     application = wx.App()     framework = MyFramework() application.MainLoop()This code can be used as a template for your application.Widgets in wxPythonThe wxPython toolkit allows you to create rich applications from more than one hundred widgets. But it can be very daunting to choose the perfect widget from such a large number, so wxPython has included a wxPython Demo which contains a search filter which will help you to find the right widget from the list.Now, let us add a button and allow the user to enter some text by adding a text field:import wx   class MyFramework(wx.Frame):     def frame(self):         super().frame(parent=None, title='Hello World')         panel = wx.Panel(self)   self.text_ctrl = wx.TextCtrl(panel, pos=(5, 5)) my_button = wx.Button(panel, label='Press Me', pos=(5, 55))   self.Show()   if __name__ == '__main__':     application = wx.App()     framework = MyFramework() application.MainLoop()When you run the code, the application will look like this:The first widget that is recommended on Windows is wx.Panel. It makes the background color of the frame as the right shade of gray. Tab traversal is disabled without a Panel on Windows.If the panel is the sole child of the frame, it will be expanded automatically to fill the frame with itself. The next thing you need to do is to add a wx.TextCtrl to the panel. The first argument is always that which parent the widget should go to for almost all widgets. So if you are willing to keep the text control and the button on the top of the panel, it is the parent you need to specify.You also need to inform wxPython about the position of the widget. You can do it using the pos parameter. The default location is (0,0) which is actually at the upper left corner of the parent. So to change the text control, you can change the position of the frame, you can shift its left corner 5 pixels from the left(x) and 5 pixels from the top(y). Finally, you can add your button to the panel and label it. You can also set the y-coordinate to 55 to prevent the overlapping of widgets.Absolute PositioningAbsolute positioning is the technique found in most GUI toolkits by which you can provide the exact coordinates for your widget’s position.There might be situations when you need to keep track of all your widgets and relocate the widgets in case of a complex application. This can be a really difficult thing to do. However, most modern-day toolkits provide a solution for this, which we’ll study next.Sizers (Dynamic Sizing)Sizers are methods to define the control layout in dialogs in wxPython. They have the ability to create dialogs that are not dependent on the platform. They manage the positioning of the widgets and adjust them when the user resizes the application window.Some of the primary types of sizers that are commonly used are:wx.BoxSizerwx.GridSizerwx.FlexGridSizerAn example code to add wx.BoxSizer to the previous code:import wx   class MyFramework(wx.Frame):     def frame(self):         super().frame(parent=None, title='Hello World')         panel = wx.Panel(self)         my_sizer = wx.BoxSizer(wx.VERTICAL)         self.text_ctrl = wx.TextCtrl(panel) my_sizer.Add(self.text_ctrl, 0, wx.ALL | wx.EXPAND, 5)         my_button = wx.Button(panel, label='Press Me') my_sizer.Add(my_btn, 0, wx.ALL | wx.CENTER, 5)         panel.SetSizer(my_sizer)         self.Show()   if __name__ == '__main__':     application = wx.App()     framework = MyFramework() application.MainLoop() In the example above, an instance of wx.BoxSixer is created and passed to wx.VERTICAL which is actually the orientation that widgets are included in the sizer. The widgets will be added in a vertical manner from top to bottom. You can also set the BoxSizer’s orientation to wx.HORIZONTAL. In this case, the widgets are added from left to right.  You can use .Add() to a widget to a sizer which takes maximum five arguments as follows: window ( the widget )- This is the widget that is added to the sizer. proportion - It sets how much space corresponding to other widgets in the sizer will the widget should take. By default, the proportion is zero which leaves the wxPython to its original proportion. flag - It allows you to pass in multiple flags by separating them with a pipe character: |. The text control is added using wx.ALL and wx.EXPAND flags. The wx.ALL flag adds a border on all sides of the widget. On the other hand, wx.EXPAND expands the widgets as much as the sizer can be expanded. border - This parameter informs wxPython about the number of pixels of border needed around the widget.  userData - It is a rare argument that is used for resizing in case of complex applications. However, in this example, the wx.EXPAND flag is replaced with wx.CENTER to display the button in the center on-screen. When you run the code, your application will look something like this:Adding an event using wxPython Though your application looks cool, but it really does nothing. The button you have created does nothing on pressing it. Let us give the button a job:import wx   class MyFramework(wx.Frame):     def frame(self):         super().frame(parent=None, title='Hello World')         panel = wx.Panel(self)         my_sizer = wx.BoxSizer(wx.VERTICAL)         self.text_ctrl = wx.TextCtrl(panel) my_sizer.Add(self.text_ctrl, 0, wx.ALL | wx.EXPAND, 5)         my_button = wx.Button(panel, label='Press Me') my_button.Bind(wx.EVT_BUTTON, self.on_press) my_sizer.Add(my_btn, 0, wx.ALL | wx.CENTER, 5)         panel.SetSizer(my_sizer)         self.Show()   def button_press(self, event):         value = self.text_ctrl.GetValue()         if not value:             print("You didn't enter anything!")        else:             print(f'You typed: "{value}"')   if __name__ == '__main__':     application = wx.App()     framework = MyFramework() application.MainLoop() You can attach event bindings to the widgets in wxPython. This allows them to respond to certain types of events.If you want the button to do something, you can do it using the button’s .Bind() method. It takes the events you want to bind to, the handler to call an event, an optional source, and a number of optional ids. In the example above, the button object is binded to wx.EVT_BUTTON and told to call button_press when the event gets fired..button_press also accepts a second argument by convention that is called event. The event parameter suggests that the second argument should be an event object.You can get the text control’s contents with the help of GetValue() method within .button_press.How to create a Working Application?Consider a situation where you are asked to create an MP3 tag editor. The foremost thing you need to do is to look out for the required packages.Consider a situation where you are asked to create an MP3 tag editor. The foremost thing you need to do is to look out for the required packages.If you make a Google search for Python mp3 tag editor, you will find several options as below:mp3 -taggereyeD3mutagenOut of these, eyeD3 is a better choice than the other two since it has a pretty nice API that can be used without getting bogged down with MP3’s ID3 specification.You can install eyeD3 using pip from your terminal:pip install eyed3If you want to install eyeD3 in macOS, you have to install libmagic using brew. Linux and Windows users can easily install using the command mentioned above.Designing the User Interface using wxPythonThe very first thing you must do before designing an interface is to sketch out how you think the interface should look.The user interface should perform the following tasks:Open up one or more MP3 files.Display the current MP3 tags.Edit an MP3 tag.If you want to open a file or a folder, you need to have a menu or a button in your user interface. You can do that with a File menu. You will also need a widget to see the tags for multiple MP3 files. A tabular structure consisting of columns and rows would be perfect for this case since you can have labeled columns for the MP3 tags. wxPython toolkit consists of afew widgets to perform this task:wx.grid.Gridwx.ListCtrlwx.ListCtrl would be a better option of these two since the Grid widget is overkill and complex in nature. Finally, you can use a button to perform the editing tasks.Below is an illustration of what the application should look like:Creating the User Interface You can refer to a lot of approaches when you are creating a user interface. You can follow the Model-View-Controller design pattern that is used for developing user interfaces which divides the program logic into three interconnected elements. You should know how to split up classes and how many classes should be included in a single file and so on.However, in this case, you need only two classes which are as follows:wx.Panel classwx.Frame class Let’s start with imports and the panel class:import eyed3 import glob import wx   class Mp3Panel(wx.Panel):     def frame(self, parent):         super().__init__(parent) main_sizer = wx.BoxSizer(wx.VERTICAL) self.row_obj_dict = {}   self.list_ctrl = wx.ListCtrl(             self, size=(-1, 100),               style=wx.LC_REPORT | wx.BORDER_SUNKEN         ) self.list_ctrl.InsertColumn(0, 'Artist', width=140) self.list_ctrl.InsertColumn(1, 'Album', width=140) self.list_ctrl.InsertColumn(2, 'Title', width=200) main_sizer.Add(self.list_ctrl, 0, wx.ALL | wx.EXPAND, 0)         edit_button = wx.Button(self, label='Edit') edit_button.Bind(wx.EVT_BUTTON, self.on_edit) main_sizer.Add(edit_button, 0, wx.ALL | wx.CENTER, 5)         self.SetSizer(main_sizer)   def on_edit(self, event):         print('in on_edit')   def update_mp3_listing(self, folder_path):         print(folder_path)In this example above, the eyed3 package, glob package, and the wx package are imported. Then, the user interface is created by making wx.Panel a subclass. A dictionary row_obj_dict is created for storing data about the MP3s. The next thing you do is create a wx.ListCtrl and set it to report mode, i.e. wx.LC_REPORT. This report flag is the most popular among all but you can also choose your own depending upon the style flag that you pass in. Now you need to call .InsertColumn() to make the ListCtrl have the correct headers and then provide the index of the column, its label and the width of the column pixels. Finally, you need to add your Edit button, an event handler, and a method. The code for the frame is as follows:class Mp3Frame(wx.Frame):     def__init__(self):         super().__init__(parent=None,                          title='Mp3 Tag Editor') self.panel = Mp3Panel(self) self.Show()   if __name__ == '__main__':     app = wx.App(False)     frame = Mp3Frame() app.MainLoop()This class function is a better and simpler approach than the previous one because you just need to set the title of the frame and instantiate the panel class, MP3Panel. The user interface will look like this after all the implementations:The next thing we will do is add a File menu to add MP3s to the application and also edit their tags.Make a Functioning ApplicationThe very first thing you need to do to make your application work is to update the wx.Frame class to include the File menu which will allow you to add MP3 files.Code to add a menu bar to our application:class Mp3Frame(wx.Frame):   def__init__(self):         wx.Frame.__init__(self, parent=None,                             title='Mp3 Tag Editor') self.panel = Mp3Panel(self) self.create_menu() self.Show()   def create_menu(self): menu_bar = wx.MenuBar() file_menu = wx.Menu() open_folder_menu_item = file_menu.Append( wx.ID_ANY, 'Open Folder',   'Open a folder with MP3s'         ) menu_bar.Append(file_menu, '&File') self.Bind(             event=wx.EVT_MENU,               handler=self.on_open_folder,             source=open_folder_menu_item,         ) self.SetMenuBar(menu_bar)   def on_open_folder(self, event):         title = "Choose a directory:" dlg = wx.DirDialog(self, title,                              style=wx.DD_DEFAULT_STYLE) if dlg.ShowModal() == wx.ID_OK:             self.panel.update_mp3_listing(dlg.GetPath()) dlg.Destroy() In the example code above, .create_menu() is called within the class’s constructor and then two instances – wx.MenuBar and wx.Menu are created.Now, if you’re willing to add an item to the menu, you need to call the menu instance’s .Append() and pass the following things:A unique identifierLabelA help stringAfter that call the menubar’s .Append() to add the menu to the menubar. It will take the menu instance and the label for menu. The label is called as &File so that a keyboard shortcut is created to open the File menu using just the keyboard.Now self.Bind() is called to bind the frame to wx.EVT_MENU. This informs wxPython about which handler should be used and which source to bind the handler to. Lastly, call the frame’s .SetMenuBar and pass it the menubar instance. Your menu is now added to the frame.Now let’s come back to the menu item’s event handler:def on_open_folder(self, event):     title = "Choose a directory:" dlg = wx.DirDialog(self, title, style=wx.DD_DEFAULT_STYLE) if dlg.ShowModal() == wx.ID_OK:         self.panel.update_mp3_listing(dlg.GetPath()) dlg.Destroy()You can use wxPython’s wx.DirDialog to choose the directories of the correct MP3 folder. To display the dialog, use .ShowModal(). This will display the dialog modally but will disallow the user to interact with the main application.  You can get to the user’s choice of path using .GetPath() whenever the user presses the OK button. This path has to be added to the panel class and this can be done by the panel’s .update_mp3_listing().Finally, you will have to close the dialog and the best method is using .Destroy().  There are methods to close the dialog like .Close() which will just dialog but will not destroy it, so .Destroy() is the most effective option to prevent such situation.Now let’s update the MP3Panel class starting with .update_mp3_listing():def update_mp3_listing(self, folder_path): self.current_folder_path = folder_path self.list_ctrl.ClearAll()   self.list_ctrl.InsertColumn(0, 'Artist', width=140) self.list_ctrl.InsertColumn(1, 'Album', width=140) self.list_ctrl.InsertColumn(2, 'Title', width=200) self.list_ctrl.InsertColumn(3, 'Year', width=200)       mp3s = glob.glob(folder_path + '/*.mp3')     mp3_objects = []     index = 0 for mp3 in mp3s:         mp3_object = eyed3.load(mp3) self.list_ctrl.InsertItem(index,               mp3_object.tag.artist) self.list_ctrl.SetItem(index, 1,               mp3_object.tag.album) self.list_ctrl.SetItem(index, 2,               mp3_object.tag.title)         mp3_objects.append(mp3_object) self.row_obj_dict[index] = mp3_object         index += 1In the example above, the current directory is set to the specified folder and the list control is cleared. The list controls stay fresh and shows the MP3s you’re currently working with. Next, the folder is taken and Python’s globmoduleis used to search for the MP3 files. Then, the MP3s are looped over and converted into eyed3 objects. This is done by calling the .load() of eyed3. After that, you can add the artist, album, and the title of the Mp3 to the control list given that the MP3s have the appropriate tags..InsertItem() is used to add a new row to a list control for the first time and SetItem()  is used to add rows to the subsequent columns. The last step is to save your MP3 object to your Python dictionary row_obj_dict.Now to edit an MP3’s tags, you need to update the .on_edit() event handler:def on_edit(self, event):     selection = self.list_ctrl.GetFocusedItem() if selection >= 0:         mp3 = self.row_obj_dict[selection] dlg = EditDialog(mp3) dlg.ShowModal()         self.update_mp3_listing(self.current_folder_path) dlg.Destroy()The user’s selection is taken by calling the list control’s .GetFocusedItem(). It will return -1 if the user will not select anything in the list control. However, if you want to extract the MP3 obj3ct from the dictionary, the user have to select something. You can then open the MP3 tag editor dialog which will be a custom dialog. As before, the dialog is shown modally, then the last two lines in .on_edit() will execute what will eventually display the current MP3 tag information. SummaryLet us sum up what we have learned in this article so far – Installing wxPython and Working with wxPython’s widgets Working of events in wxPython Comparing absolute positioning with sizers Creating a skeleton application and a working application The main feature of the wxPython Graphical User Interface is its robustness and a large collection of widgets that you can use to build cross-platform applications. Since you have now learned how to create a working application, that is an MP3 tag editor, you can try your hand to enhance this application to a more beautiful one with lots of new features or you can perhaps create your own wonderful application. To gain more knowledge about Python tips and tricks, check our Python tutorial and get a good hold over coding in Python by joining the Python certification course.
Rated 4.5/5 based on 2 customer reviews
5961
How to Build a Python GUI Application With wxPytho...

A Graphical User Interface or GUI is a user interf... Read More

## How To Run Your Python Scripts

Rated 4.5/5 based on 19 customer reviews
5977
How To Run Your Python Scripts

If you are planning to enter the world of Python p... Read More