CHAPTER 1: GETTING STARTED WITH PYTHON FOR AUTOMATION
Python shines as a beacon of versatility and simplicity, a testament to the vision of its creator, Guido van Rossum, who embarked on a mission in the late 1980s to design a language that emphasized the importance of programmer effort over computational effort. This guiding principle led to the birth of Python, officially introduced in 1991 as a highlevel, interpreted language that championed readability and efficiency.
Van Rossum's journey began over a Christmas holiday, a period of creative isolation where he decided to tackle the limitations he perceived in the ABC programming language. His goal was audacious yet clear: to develop a language that could encapsulate the capabilities of ABC, UNIX/C, and sed/awk, while being accessible to users of all skill levels. The result was Python, named in homage to the British comedy group Monty Python, a choice that reflected van Rossum's desire for the language to be fun and engaging.
Python's development was a harbinger of an open, collaborative approach that would later define its community. It was initially released on the alt.sources newsgroup, inviting programmers worldwide to contribute to its evolution. This openness laid the groundwork for Python's expansive library, a hallmark of the language that enables it to cater to a diverse range of programming needs, from web development to data analysis.
Python's journey through the years is marked by significant milestones, predominantly encapsulated in its version history. The transition from Python 1.0 to Python 2.0 heralded new functionalities and a shift towards Unicode support, reflecting the language's growing global user base. However, it was the leap to Python 3.0 that epitomized the language's commitment to progress, even when faced with the daunting task of making backward-incompatible changes. This bold step ensured Python's relevance in the modern programming landscape, emphasizing cleaner syntax and removing deprecated features.
The evolution of Python is not just a tale of technical enhancements but also a reflection of the community's resilience and dedication to maintaining the language's core philosophy. With each version, Python has become more robust, secure, and efficient, firmly establishing itself as a cornerstone of software development, scientific research, and education.
Central to Python's ethos is its vibrant and inclusive community. From local user groups and meetups to global conferences such as PyCon, the Python community thrives on collaboration, knowledge sharing, and mutual support. The Python Software Foundation (PSF), a non-profit organization dedicated to the language's advancement, embodies this spirit by overseeing Python's development, supporting community events, and ensuring the language remains accessible and free to use.
The community's strength lies in its diversity, with programmers, educators, scientists, and hobbyists from different backgrounds contributing to Python's growth. This collective effort has led to the creation of an extensive range of libraries and frameworks, making Python a versatile tool for various applications, including web development, data science, artificial intelligence, and more.
Moreover, the community's commitment to education and outreach has made Python a language of choice for introducing programming to beginners. Its readable syntax and extensive resources lower the barrier to entry, enabling a new generation of programmers to contribute their voices to the ongoing narrative of Python's evolution.
understanding Python requires more than a grasp of its syntax or the ability to write efficient code. It involves appreciating the history that shaped it, navigating its versioning strategy, and, most importantly, engaging with the community that breathes life into the language. As Python continues to evolve, it remains a testament to the power of communal efforts in paving the way for innovation and advancement in the tech world.
Brief History of Python and Its Creator
The genesis of Python is a tale of innovation born out of frustration with the status quo. During his time at the Centrum Wiskunde & Informatica (CWI) in the Netherlands, Guido van Rossum found himself grappling with the limitations of ABC, a programming language designed for teaching yet lacking in practical applicability. It was this dissatisfaction that kindled the spark for Python.
Python's conception over the Christmas break of 1989 wasn't a grandiose epiphany but rather a modest ambition to create a scripting language that amalgamated the best features of ABC with the capabilities of systems programming languages like C. Van Rossum's aim was deceptively simple: to design a language that was as readable as English and as powerful as C, a language that prioritized developer productivity and code readability above all else.
Guido van Rossum, born in 1956 in the Netherlands, embarked on his programming odyssey with a Commodore Amiga. He was a visionary who saw programming not just as a mechanical act of telling a computer what to do, but as a craft that involved elegance, foresight, and collaboration. His early experiences with computers in his university days, where he contributed to the development of ABC, laid the groundwork for his future endeavors.
Van Rossum's approach to the development of Python was revolutionary. He envisioned a community-driven model of software development, where the language would be shaped not just by its creator but by its users. This model was not just about writing code; it was about nurturing a culture of open collaboration and innovation.
Python was officially released to the public in February 1991 as version .0. This first release already included exceptional features such as exception handling, functions, and the core data types that characterized Python's approach to solving programming problems: simplicity and elegance. The response from the programming community was overwhelmingly positive, and Python began its journey towards becoming a staple in software development.
As Python evolved, so did its applications, stretching from simple scripting to web development, data analysis, artificial intelligence, and more. With each new version, from Python 1.0 in January 1994, introducing modularity, to the more recent Python 3.0 in December 2008, which broke backward compatibility to clean up the language, Python's growth mirrored the expanding landscape of technology.
Guido van Rossum's legacy is not merely Python itself but the philosophy it embodies. Python's ethos, encapsulated in "The Zen of Python" by Tim Peters, emphasizes simplicity, beauty, readability, and the importance of community. Van Rossum's leadership fostered a global community that actively contributes to Python's development, ensuring the language remains by and for programmers.
In July 2018, van Rossum announced his "permanent vacation" from the role of BDFL, marking the end of an era. However, the governance of Python transitioned smoothly to a five-person steering council, reflecting the robustness of the community and governance structures van Rossum helped establish.
The history of Python and Guido van Rossum is a testament to the power of visionary leadership and community collaboration. From its humble beginnings as a holiday project to its status as one of the world's most popular programming languages, Python's journey is a beacon for opensource development, illustrating how technology can be democratized and how a community can thrive under the banner of innovation and shared purpose.
Differences between Python 2.x and 3.x
The evolution of Python from 2.x to 3.x marks a significant milestone in its history, underscoring a deliberate move towards modernizing the language and making it more robust and intuitive for future generations of developers. This transition, while essential, was not without its challenges and controversies, given the breaking changes introduced. Herein, we explore the core distinctions between Python 2.x and 3.x, shedding light on the rationale behind the shift and its implications for the programming community.
One of the most notable differences between Python 2.x and Python 3.x lies in the treatment of strings and the syntax used for print statements. In Python 2, print is treated as a statement rather than a function, allowing for syntax without parentheses. Conversely, Python 3 enforces a more consistent approach by treating print as a function, requiring parentheses.
```python
# Python 2 syntax
print "Hello, Python 2!"
# Python 3 syntax
print("Hello, Python 3!")
Furthermore, Python 3 took significant strides in handling Unicode and binary data types. While Python 2 allowed for an ambiguous interpretation of string types—either as ASCII or Unicode—Python 3 introduced a clear distinction: strings are Unicode by default, and byte data must be explicitly specified.
Python 3 rectified a subtle but impactful difference in the division of integers. In Python 2, dividing two integers results in floor division, meaning the quotient is rounded down to the nearest whole number. To achieve true division, one of the operands had to be explicitly made a float.
Python 3 streamlined this behavior by introducing true division as the default for dividing two integers, with floor division requiring an explicit double slash operator.
```python
# Python 2 division (floor division)
result = 5 / 2 # Results in 2
# Python 3 division (true division)
result = 5 / 2 # Results in 2.5
Another pivotal change was the reimagining of range() in Python 3 to return a range object instead of a list, as was the case in Python 2’s xrange(). This modification was aimed at optimizing memory usage and performance for large ranges, embodying Python 3’s forward-thinking adjustments for efficiency.
Python 3 introduced a new syntax for exception handling, enforcing a clearer distinction between the error being caught and the exception instance. This change aimed to enhance readability and maintainability of exception handling blocks.
```python # Python 2 syntax
try: # attempt some code except Exception, e:
# handle exception
# Python 3 syntax
try:
# attempt some code
except Exception as e:
# handle exception
Among Python 3's innovations, function annotations stand out as a forwardthinking feature, allowing developers to attach metadata to the parameters and return values of functions. Although these annotations have no impact on the runtime behavior, they offer a powerful tool for documentation and type hinting, enhancing code readability and maintainability.
The journey from Python 2 to Python 3 was marked by an extended period of coexistence, during which the Python Software Foundation and the broader community provided support for both versions. However, as of January 1, 2020, Python 2 officially reached its end of life, ceasing to receive updates, security patches, or fixes. This milestone underscored the community's commitment to moving forward with Python 3, embracing its advancements and the promise of a more unified Python ecosystem.
The transition between Python 2.x and 3.x encapsulates a pivotal moment in Python's history, characterized by both the challenges of change and the enduring commitment of the community to evolve. Python 3's changes, while requiring adaptation, ultimately serve to refine and advance the language, ensuring its relevance and utility for generations of developers to come.
Overview of the Python Community and Resources
Python's success is its global community, a diverse and inclusive network of enthusiasts, professional developers, educators, and researchers. This community thrives through a culture of open collaboration and mutual assistance, characterized by an array of conferences, meet-ups, and online forums. Key among these are the Python Software Foundation (PSF) and its associated PyCon conferences held worldwide, offering platforms for knowledge sharing, networking, and collaboration on Python projects.
For those new to Python or looking to enhance their skills, the community offers an abundance of learning resources. Interactive platforms like Codecademy, Coursera, and edX provide courses ranging from beginner to advanced levels, often developed or vetted by Python experts. Furthermore, websites such as Real Python and PyBites offer tutorials, code challenges, and articles that cater to continuous learning and skill enhancement in Python programming.
The Python community flourishes online, with forums and support groups providing a backbone for collaboration and assistance. Platforms such as Stack Overflow, Reddit’s r/Python, and the Python Community on Discord serve as vital hubs where programmers can ask questions, share insights, and discuss the latest developments in Python. These platforms, known for their welcoming and supportive ethos, are instrumental in troubleshooting, idea exchange, and fostering connections within the Python ecosystem.
Python's open-source philosophy encourages the sharing and collaborative improvement of code. GitHub and GitLab host a myriad of Python projects, ranging from web development frameworks like Django and Flask to scientific computing libraries such as NumPy and SciPy. Contributing to these projects not only aids personal growth and understanding but also enriches the Python ecosystem at large.
Python’s extensive standard library, dubbed the "batteries included" philosophy, is complemented by detailed documentation that is both accessible and comprehensive. The official Python website (python.org) serves as the gateway to this wealth of resources, including the Python Enhancement Proposals (PEPs), which detail the development and governance of Python. Additionally, platforms like Read the Docs host
documentation for thousands of Python libraries and tools, ensuring developers have access to the information they need.
Catering to the diverse interests within the Python community, several Special Interest Groups (SIGs) and local user groups (LUGs) have emerged. These groups focus on specific areas within Python, such as data analysis, web development, and machine learning, providing specialized forums for discussion and collaboration. Moreover, local Python meet-ups and user groups offer opportunities for networking and learning within regional communities.
The Python community, with its rich array of resources and unwavering support among members, stands as a testament to the language's enduring appeal. From comprehensive documentation and online courses to vibrant forums and open-source projects, the ecosystem provides a fertile ground for growth, innovation, and collaboration. For anyone embarking on their Python journey, these resources offer a roadmap to mastering the language and contributing to its vibrant community.
Setting Up Your Python Environment: Tools, Editors, and IDEs
The Python ecosystem is rich with tools designed to suit a variety of development needs, from simple script writing to complex application development. The first step in setting up your environment is to install Python itself. The official Python website offers binaries for all major operating systems, ensuring a smooth installation process. Following Python's installation, it's crucial to familiarize yourself with the Python Package Index (PyPI), a repository of software for the Python programming language. PyPI is an invaluable resource for finding libraries that can be easily installed using pip, Python’s package installer, enhancing your projects with minimal effort.
The choice between a text editor and an Integrated Development Environment (IDE) hinges on your project's complexity, your comfort level, and personal preference. Text editors like Sublime Text, Atom, and Visual Studio Code offer simplicity, speed, and flexibility, with extensive plugin ecosystems to add functionality as needed. These editors, while lightweight,
can be configured to closely mimic an IDE's capabilities through the integration of linters, debuggers, and version control systems.
For those seeking a more comprehensive solution, IDEs such as PyCharm or the Python extension for Visual Studio Code provide an allencompassing environment tailored for Python development. These IDEs come with advanced features like code completion, intelligent navigation, and integrated testing environments, streamlining the development process and enhancing productivity. PyCharm, for instance, offers a robust platform for web development, scientific computing, and data visualization, catering to a wide range of Python applications.
One of Python's best practices is the use of virtual environments—a cornerstone concept for any development setup. Virtual environments allow you to manage dependencies for different projects by creating isolated spaces, preventing potential conflicts between library versions. Tools like venv (built into Python 3) and virtualenv provide straightforward commands to create, activate, and manage these environments. Incorporating virtual environments into your workflow ensures that each project has access to the packages it needs, without affecting others or the system-wide Python installation.
Version control is an essential aspect of software development, enabling you to track changes, revert to previous states, and collaborate with others. Git, coupled with platforms like GitHub, Bitbucket, or GitLab, forms the backbone of modern version control strategies. These platforms not only host your code but also facilitate collaboration through features like pull requests and issue tracking. Understanding and integrating Git into your development environment empowers you to manage your projects efficiently and engage with the open-source community effectively.
Installing Python and Essential Packages
Python's appeal partly lies in its cross-platform nature, allowing it to run seamlessly on Windows, macOS, and Linux. Here's how to ensure a smooth installation across these environments:
Windows:
1. Navigate to the [official Python website](https://www.python.org/) and download the latest version of Python for Windows.
2. Execute the downloaded file. During installation, check the box that says "Add Python X.X to PATH" to ensure that the Python interpreter is accessible from the command line.
3. To verify the installation, open Command Prompt and type `python -version`. If installed correctly, Python will display its current version.
macOS:
1. macOS typically comes with Python installed, but it might not be the latest version. To install the latest version, one can use Homebrew, a package manager for macOS. If not already installed, install Homebrew by executing `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"` in the terminal.
2. Once Homebrew is installed, install Python by typing `brew install python`.
3. Confirm the installation by typing `python3 --version` in the terminal.
Linux:
1. Most Linux distributions come with Python pre-installed. To check, open a terminal and type `python3 --version`.
2. If Python is not installed or you wish to install a different version, you can use your distribution's package manager. For Ubuntu and Debian-based systems, use `sudo apt-get update` followed by `sudo apt-get install python3`.
Once Python is installed, the next step is to enrich your environment with packages that support automation. These packages can be installed using Python's package manager, pip, which comes installed with Python versions 3.4 and above.
- Requests: Simplifies making HTTP requests, allowing you to interact with web applications and services programmatically. Install via `pip install requests`.
- Beautiful Soup: A library designed for web scraping. It makes it easy to scrape information from web pages, which can be invaluable in automation projects. Install with `pip install beautifulsoup4`.
- Selenium: An essential tool for automating web browsers. It allows you to control a web browser from your Python code, enabling tasks like testing web applications or automating repetitive web tasks. Install using `pip install selenium`.
- Pandas: A powerful data manipulation and analysis library. It offers data structures and operations for manipulating numerical tables and time series, making it perfect for data-heavy automation tasks. Install via `pip install pandas`.
- PyAutoGUI: Allows you to control the mouse and keyboard to automate interactions with other applications. Install with `pip install pyautogui`.
Before diving into installing numerous packages, it's wise to create a virtual environment for each of your projects. Virtual environments allow you to manage separate package installations for different projects, avoiding conflicts between package versions. To create a virtual environment, navigate to your project's directory in the command line and type:
- On Windows: `python -m venv myprojectenv`
- On macOS and Linux: `python3 -m venv myprojectenv`
Activate the virtual environment by running:
- On Windows: `myprojectenv\Scripts\activate`
- On macOS and Linux: `source myprojectenv/bin/activate`
With the virtual environment activated, any Python or pip commands will operate in the context of the virtual environment, keeping your global installation clean and your project dependencies well managed.
By following these steps, you've now set up a Python environment equipped with the latest version of Python, essential packages for automation, and a system for managing project-specific dependencies through virtual environments. This setup forms the backbone of your automation journey, providing a flexible and powerful base from which to explore the vast potential of Python automation. With your environment tailored and ready, the next step is to dive into the practical aspects of Python automation, starting with writing simple scripts and gradually tackling more complex automation challenges.
Comparison of Text Editors and IDEs for Python Development
Text editors are lightweight programs that allow you to write and edit code. They are fast, highly customizable, and can be enhanced with plugins to support Python development.
Sublime Text: Sublime Text is renowned for its speed, user-friendly interface, and extensive customization options through plugins. Its "Goto Anything" feature enables quick navigation to files, symbols, or lines, and when coupled with the Python Enhancement Proposal (PEP) 8 plugins, it becomes a powerful editor for writing clean Python code.
Atom: Developed by GitHub, Atom is a free, open-source editor that supports cross-platform editing. Atom stands out for its collaborative editing feature, Teletype, which allows developers to write code together in real time. Its package manager supports numerous Python-specific packages for linting, auto-completion, and virtual environment management.
Visual Studio Code (VS Code): VS Code is a free, open-source editor that has gained immense popularity among developers for its robust functionality. It offers built-in Git control, syntax highlighting, intelligent code completion, snippets, and code refactoring. The Python extension for VS Code, developed by Microsoft, provides rich support for Python development, including debugging, testing, and virtual environments.
IDEs offer comprehensive facilities to computer programmers for software development. They typically include a source code editor, build automation tools, and a debugger, all within a single application.
PyCharm: PyCharm is a widely used IDE for Python developed by JetBrains. It offers a rich set of features including smart code navigation, fast error checking, and quick-fixes, making it an excellent choice for professional development. PyCharm integrates with major Python frameworks, supports web development, and offers tools for data science. While it has a paid Professional version, the Community version is free and open-source.
Spyder: Spyder is an open-source IDE designed specifically for scientists, engineers, and data analysts. It features powerful editing, interactive testing, debugging, and introspection functions. Spyder comes with Anaconda, a popular Python distribution for data science and scientific computing. Its Variable Explorer, which allows direct interaction with data, is highly beneficial for data analysis.
Jupyter Notebook: Jupyter Notebook is an open-source web application that allows you to create and share documents containing live code, equations, visualizations, and narrative text. While not a traditional IDE, Jupyter is an invaluable tool for data exploration, visualization, machine learning, and explanatory programming.
The decision between using a text editor or an IDE for Python development hinges on the nature of your projects, your workflow preferences, and the level of functionality you require.
- For lightweight scripting or when working on simple automation tasks, a text editor like Sublime Text or VS Code might be preferable due to its simplicity and speed.
- For complex projects, particularly those involving web development, data analysis, or scientific computing, an IDE like PyCharm or Spyder would offer more integrated tools and features designed to streamline your workflow.
The choice of development tools is highly personal and varies from one developer to another. Whether you opt for the minimalist approach offered by text editors or the comprehensive feature set of an IDE, the key is to select a tool that best aligns with your project requirements and personal productivity preferences. Experimenting with different editors and IDEs can provide valuable insights into which environment makes you the most efficient and comfortable as you embark on your Python automation projects.
Setting Up a Virtual Environment
Before we plunge into the technicalities of setting up a virtual environment, understanding its benefits can significantly underscore its importance. Virtual environments:
1. Prevent Dependency Conflicts: Each project can have its dependencies installed in its environment, without affecting other projects.
2. Facilitate Reproducibility: By encapsulating the project’s environment, you ensure that it can be replicated on any other machine without hitches.
3. Enhance Project Organization: Keeps your global site-packages directory clean and only installs the packages you need for each project.
Setting up a virtual environment in Python is achieved through a few simple commands. Here, we’ll cover the process using the native `venv` module available in Python 3.3 and later, which provides support for creating lightweight “virtual environments” with their own site directories.
Step 1: Installing Python
Ensure you have Python installed on your system. Python’s installation varies depending on your operating system (OS). Most modern Linux distributions and MacOS come with Python pre-installed. Windows users can download Python from the Python Software Foundation website and follow the installation instructions.
Step 2: Creating a Virtual Environment
Navigate to your project’s directory using the command line or terminal. Once inside the directory, execute the following command to create a virtual environment named 'env':
```bash
python3 -m venv env ```
This command creates a directory named `env` within your project directory. This directory contains the Python executable files, and a copy of the `pip` library, which you can use to install other packages.
Step 3: Activating the Virtual Environment
To activate the virtual environment and start using it, you must execute the activation script which is platform-dependent.
- On Windows:
```cmd
env\Scripts\activate.bat
- On MacOS and Linux:
```bash source env/bin/activate
Upon activation, your command line will usually show the name of your virtual environment, in this case, `(env)`, indicating that any Python or pip commands you run will now be confined to this environment.
Step 4: Installing Packages
With your environment activated, you can use pip to install packages. For example, to install a package named `requests`, you would use:
```bash pip install requests
This command downloads the `requests` package and installs it within your `env` environment, isolated from the global Python installation.
Step 5: Deactivating the Virtual Environment
To exit your virtual environment and stop using its isolated space, simply run:
```bash deactivate
This returns you to your system’s global Python environment, where actions do not affect the virtual environment you set up.
Mastering the setup and management of virtual environments is a cornerstone of Python development, especially in projects where precise control over dependencies is paramount. By isolating project environments, you not only mitigate the risk of dependency conflicts but also bolster the reproducibility and organization of your projects. Whether you’re developing a small script or a large-scale application, the principles of virtual environment management remain an indispensable part of your Python toolkit.
Python Basics for Automation: Syntax, Data Structures, Control Flow
Python is lauded for its readable syntax, which closely resembles the English language, making it an ideal language for beginners and seasoned programmers alike. The cornerstone of Python's syntax lies in its emphasis on indentation and simplicity, eliminating the need for verbose code blocks marked by braces or keywords. Here’s a glimpse:
def greet(name):
print(f"Hello, {name}! Welcome to Python automation.")
In this snippet, the function `greet` exemplifies Python's clean syntax with its use of indentation to define the scope—a hallmark of Python's design philosophy.
Python offers a versatile set of built-in data structures, each with its unique capabilities, to store and manage data efficiently. Understanding these structures is crucial for manipulating data in automation scripts.
- Lists: Ordered collections of items that can be of mixed types. Lists are mutable, allowing modification.
```python
tasks = ["email", "backup", "cleanup"]
```
- Tuples: Similar to lists, but immutable. Excellent for fixed data sets.
```python credentials = ("admin", "password123")
```
- Dictionaries: Key-value pairs offering a fast way to retrieve data without knowing its index. Invaluable for configurations and mappings in automation tasks.
```python
config = {"threshold": 90, "mode": "silent"}
```
The power of automation lies in making decisions and repeating tasks without manual input. Python’s control flow statements are the navigational commands guiding your script through its execution path.
- If Statements: Python evaluates conditions to decide which block of code to execute. It's essential for scripts that require decision-making.
```python
if file_size > threshold:
print("File size exceeds the threshold.")
- Looping: For tasks that require repetition, such as iterating over files in a directory, Python provides `for` and `while` loops.
```python for file in files: if file.endswith('.tmp'): cleanup(file)
```
- Iterators: Python’s iterator protocol is a way to traverse through a collection, making it straightforward to iterate over data structures.
```python
iter_files = iter(files) next(iter_files) ```
Combining these elements, let's craft a basic Python script that automates the task of greeting a list of users:
```python def greet_users(users):
for user in users:
print(f"Hello, {user}! Welcome to Python automation.")
users = ["Alice", "Bob", "Charlie"]
greet_users(users)
This script encapsulates the essence of automation with Python—using a simple, readable syntax, iterating over a data structure, and controlling the flow of execution based on conditions or sequences.
As we transition from these basics to more sophisticated automation techniques, remember that the power of Python lies in its simplicity and elegance—qualities that make it an unparalleled tool for automating the mundane and unlocking new efficiencies in your workflows.
Basic Syntax and Indentation: The Foundation of Python Scripting
Python's design philosophy lies a commitment to code readability and a syntax that allows programmers to express concepts in fewer lines of code than might be required in other languages. The simplicity of Python's syntax is not merely aesthetic; it is instrumental in reducing the cognitive load on the programmer, making it easier to learn, understand, and remember.
Consider the Python way to print "Hello, World!":
print("Hello, World!")
This single line of code exemplifies Python's straightforward syntax—no semicolons, no curly braces, just a clear expression of intent.
Unlike many programming languages that use braces `{}` to define blocks of code, Python uses indentation. Indentation refers to the spaces at the beginning of a code line. In Python, the amount of indentation is significant; it defines the grouping of statements.
Here's a simple if-else block to demonstrate: ```python if condition:
print("Condition is true.") else:
print("Condition is false.")
The indentation makes the code easy to read at a glance, understanding which statements belong to the if condition and which do not. It's a fundamental part of Python's syntax that enforces code readability.
1. Consistency is Key: Python does not mandate the use of a specific number of spaces for indentation, but whatever number you choose must be consistent throughout the block. The Python community recommends using 4 spaces per indentation level.
2. Tabs vs. Spaces: While Python 3 disallows mixing tabs and spaces for indentation, the choice between them is yours. However, the convention is