A Beginner’s Guide to Learning the Basics of Python Programming

Python allows for multiple programming paradigms, such as object-oriented, functional, and imperative programming. There is also an automatic memory management and a substantial, comprehensive, standard library. Python interpreters may be downloaded and installed on many operating systems, which makes the resulting code executable for different platforms as well. Using third-party tools like Pyinstaller, the code can be repackaged into standalone and executable programs for some of the most popular operating systems. This allows one to distribute software based on the language to different environments—without having to install a Python interpreter.

127 downloads 5K Views 699KB Size

Recommend Stories

Empty story

Idea Transcript




Python A Beginner’s Guide to Learning the Basics of Python Programming By James Patterson

TABLE OF CONTENTS INTRODUCTION: What is Python? CHAPTER 1: Python’s History CHAPTER 2: Advantages and Disadvantages CHAPTER 3: When To Use Python CHAPTER 4: Installing Python CHAPTER 5: Python Basics CHAPTER 6: Python Versions CHAPTER 7: Learning How to Count – Python Integers CHAPTER 8: Python Strings CHAPTER 9: Python Lists CHAPTER 10: Tuples CHAPTER 11: IF Statement CHAPTER 12: While Statement CHAPTER 13: For Statement CHAPTER 14: Try Statement CHAPTER 15: With Statement CHAPTER 16: Other Statements CHAPTER 17: Functions CHAPTER 18: Classes CHAPTER 19: Modules CHAPTER 20: Python Idioms CHAPTER 21: Performance Tips CHAPTER 22: Implementations Galore CONCLUSION

INTRODUCTION: What is Python? Every programmer, programmer-wannabe, or person with just the slimmest brush with programming principles has heard of Python. It is a “dynamic” programming language, which has become one of the most popular of its kind, with Perl, PHP, and Ruby also contending for the roost. Just like any of these or other programming languages, Python is a unique and powerful language. Nowadays, it appears virtually anywhere—from scalable web servers that run uninterrupted ‘round the clock, to throw-away scripts that only see a few seconds of “daylight”. It can be used for both database and GUI programming, as well as both server-side and client-side programming. It can be used by first-time coders just stepping away from the basics, as well as by skilled developers in mission-critical settings. It is certainly one of the most versatile of its lot. Python allows for multiple programming paradigms, such as object-oriented, functional, and imperative programming. There is also an automatic memory management and a substantial, comprehensive, standard library. Python interpreters may be downloaded and installed on many operating systems, which makes the resulting code executable for different platforms as well. Using third-party tools like Pyinstaller, the code can be repackaged into standalone and executable programs for some of the most popular operating systems. This allows one to distribute software based on the language to different environments—without having to install a Python interpreter. For those looking for open-source, there is CPython—a reference implementation of Python in the FOSS environment. It has a community-based model of development, like its alternative implementations. CPython is being managed by the Python Software Foundation, a non-profit outfit. First Impressions Python usually gives off two similar first impressions depending on who is viewing it. For the experienced programmer, it looks strikingly similar to some of the more “conventional” programming languages like Pascal or C. This is easy to explain, as Python does borrow a lot from C. They even share many keywords, such as “if”, “else”, “while”, and more. The rules are also shared between Python identifiers and their C counterparts, with standard operators mostly having the same meaning. This is, of course, not to say that Python is the same as C. There are several key

differences, such as the use of indentations instead of braces. This makes code essentially easier to type, and more “user friendly”. This brings us to the second set of first impressions, when Python is viewed by a complete beginner—it looks easy. Consider, for example, the way that the standard “Hello, World!” line is printed in Python: Print “Hello World!” Now, check how this is written in regular JavaScript: Alert(‘Hello, World!’) Of course, a JavaScript code such as the one above needs to be embedded in an HTML document to be effective. This is just a demonstration of how easy it is (comparatively) to use Python for your programming needs. Python puts emphasis on code readability, with a syntax that allows users to code in fewer lines than what others would allow. Programs are optimized for clarity in both large and small scales. Another way that Python differs from C is the fact that it uses dynamic typing. In C, the variables should always be explicitly declared and then given a specific type (like “double” or “int”). This data will then be used to do static compile-time checks and for allocating memory locations for storing the variable’s value. In the Python framework, variables are only names referring to the objects. The variables do not have to be declares before they are assigned, and they can also change type at any time in the program. Like most other dynamic languages, the type-checking will be performed in the run-time, using an interpreter. This is in contrast with the separate compilation step used by some other languages. The reason Python seems so simple is because of its development path, carved in its history.

CHAPTER 1: Python’s History Many Python fans say that Python has quite a lot in common with the alphabet—most commonly the fact that both start with ABC. Of course, in programming terms, ABD refers to a general-purpose programming environment and programming language, first developed in the Netherlands. The language was born at the Centrum Wiskunde & Informatica (CWI). And while rarely talked-about today, it has as one of its greatest achievements the merit of influencing Python’s design. Python was first conceptualized by Guido van Rossum, back in the late 1980s. At this time, van Rossum was working at a CWI project called “Amoeba” — this was supposed to be a distributed operating system. He also worked on the ABC language, and he used everything learned in this project to come up with Python. Part of Python’s design grew with van Rossum’s frustrations with ABC. Like any good innovator, he decided that he wanted a product with the same set of strengths, but without any of ABC’s weaknesses. The first product of this endeavor was a simple set of virtual machine, parser, and runtime. Van Rossum adapted the parts he liked about ABC, creating syntax and data types such as a hash table, strings a list, and numbers along the way. Rather than making a language with everything built into the core, Python was meant to be a highly extensible language. It can also be embedded into existing apps that are in need of a programmable interface. What’s in the name? As the project developed, its creator knew it had to have a name. Most people nowadays believe that the name was derived from the world of snakes (as shown in the Python logo). However, the name was actually derived from the famous British television sketch comedy program, Monty Python’s Flying Circus. At the risk of upsetting theorists, there is no real deep meaning to the name (as van Rossum himself wrote in 1996). Apparently the name sprang forth during a particularly irreverent mood as he looked for a name to describe his Christmas week project. He also wanted a name that would appeal to the subset of Unix/C hackers. And of course, he was also a fan of the said comedy. The Python philosophy has been summarized in the neologism “pythonic”—a word that

can have many meanings related to this programming style. A pythonic code is essentially something that uses the Python idioms well, and that shows minimalism and fluency. It is also something that emphasizes readability. An “unpythonic” code, on the other hand, is something that is difficult to understand or something that seems to be a rough translation from another language. Admirers, users, and adherents to the Python philosophy are hence called “Pythonists”, “Pythoneers”, or “Pythonistas”.

The Python Philosophy There is a set of rules that describe the Python philosophy, which has since then been known as “The Zen of Python”. This was documented late into Python’s lifespan (in 2004) by a programmer named Tim Peters. This set of 19 aphorisms aptly describe the way Pythons works as a programming language, and has been initially created as an entry (the 20th) in the Python Enhancement Proposals. Any person into Python programming can access this—the Zen appears as an Easter egg when entering “import this” into the interpreter. Below are the 19 aphorisms: 1. Beautiful is better than ugly. 2. Explicit is better than implicit. 3. Simple is better than complex. 4. Complex is better than complicated. 5. Flat is better than nested. 6. Sparse is better than dense. 7. Readability counts. 8. Special cases aren’t enough to break the rules. 9. Although practicality beats purity. 10. Errors should never pass silently. 11. Unless explicitly silenced. 12. In the face of ambiguity, refuse the temptation to guess. 13. There should be one—and preferable only one—obvious way to do it. 14. Although that way may not be obvious at first unless you’re Dutch. 15. Now is better than never. 16. Although never is often better than right now. 17. If the implementation is hard to explain, it’s a bad idea. 18. If the implementation is easy to explain, it may be a good idea. 19. Namespaces are one honking great idea—let’s do more of those! This philosophy puts Python and fellow programming language Perl “at odds” with each other, as the latter steers clear of the sparse and uncluttered grammar implemented by the former. Perl explicitly aspires for the “there is more than one way to do it” philosophy, which Python users claim invite unnecessary confusion into the coding. Part of the Python philosophy is the dislike for premature optimization. Python’s developers reject patches to the non-critical parts of the language if it means the marginal increase in speed is offset by the loss of clarity. When speed is desired, a programmer can

instead move the time-critical functions to different extension modules written in other languages (like C). There is also a “just in time” compiler (PyPy) available. And of course, there is another goal that Python’s developers have is to make the language as fun to use as possible. This is also reflected in how the language was named. Even tutorial and reference materials are approached with a playful outlook. For example, some exercises refer to Monty Python-inspired spam and eggs instead of the standard foo and bar.

Python’s Development The first version of the Python code was published at alt.sources (version 0.9.0 was its number) back in February of 1991. This was quite remarkable as a first release since it already handled exception handling, some core data types, and functions. It had a module system, and was object-oriented. In January of 1994, Python’s version 1.0 was released. This included some major improvements such as new functional programming tools map, filter, reduce, and lambda. After six and a half years, in October 2000, Python 2.0 was born, which in turn included a full garbage collector and new list comprehensions. The new release was also supporting Unicode. In the next 8 years that followed, Python version 2.x grew leaps and bounds in popularity. Each of these releases was backwards compatible with the previous Python release. This continued until the introduction of Python 3.0 (also known as Python 3000 or Py3k). Aside from not being backwards compatible, Py3k emphasized removing duplicate programming modules and constructs. This is in fulfillment (or, at least, close fulfillment) of the 13th Zen—“There should be one—and preferably only one—obvious way to do it”. Here are some of the prominent changes in Py3k: Print has now been turned into a function.



The system now uses views and iterators instead of lists.



The rules for ordering the comparisons are simplified. For example, a heterogeneous list may not be sorted, since all the elements of the list should be comparable to each other.

There is just a single integer type left.



When two integers are divided, a float is returned instead of an integer. However, one can use “//” to have the old behavior.

Instead of Unicode vs. 8-Bit, there is now a difference between Text vs. Data



The development process throughout all these years is conducted through the PEP or Python Enhancement Proposal process. This is a mechanism that the developers use to propose for new features, as well as for collecting community input on any issues. This is also used to document the design decisions that have been built into Python. Any outstanding PEPs are in turn reviews, commented upon, and subsequently worked on by

the community and by van Rossum himself (Python’s Benevolent Dictator For Life). The language enhancement goes along with CPython development and its reference implementation. The “python-dev” mailing list is considered the primary forum for discussion about development. Any specific issues are to be discussed in a “roundup bug tracker” that is maintained at the project’s website (python.org). There is also development taking place on a self-hosted repository of source code, which runs Mercurial (a distributed revision control tool). There are three types of public releases from CPython, distinguished by the part of the version number which is incremented. First are the backward-incompatible versions which happen when the code is expected to break (hence demanding manual porting). Here, the first part of the version number will be incremented. These releases are fairly infrequent. Version 3.0, for example, was released a full 8 years after the preceding version. The next one is categorized as “feature” or “major” releases. These are largely compatible, even though they introduce new features. The second part of its version number will then be implemented. These are scheduled to go out about every 18 months, and are then supported by bugfixes for the next several years after its release. Lastly, there are the bugfix releases, which do not have any new features. However, they fix known bugs, providing more stability to the users. In this release, the last part of the version number is instead incremented. The releases are made when there is enough number of bugs fixed upstream ever since the last release (coinciding with roughly every quarter). Any security vulnerability will also be patched in a bugfix release. There are also some alpha, beta, and release-candidates that are sent out as previews for testing before a final release is announced. There is, however, a rough schedule that is followed for the releases, even though this can be pushed back if an issue renders the code not ready. The developers will monitor the code’s state by running large-scale tests during development. This is usually done through the BuildBot continuous integration tool which helps in automating the compile/test cycles needed to validate any change to Python’s code base. As of January 2016, the Python development community has contributed more than 72,000 software modules to the PyPI, the Python Package Index. This is the official repository of third-party Python libraries. Major academic conferences are also held, such as PyCon (currently the largest of its kind). There are also mentoring programs available, like Pyladies, which is an international mentorship group meant for women who desire to actively contribute to the Python development community.



Development Environments and Implementations Most of the Python implementations, like CPython, function as command line interpreters for which users enter statements in sequence. In return, results are immediately shown. Basically, Python acts as a shell. To add capabilities, other shells beyond those provided by the basic interpreter may be used. These include IDLE and IPython. While following the Python shell’s visual style, they also implement other features such as auto-completion, session state retention, and syntax highlighting. There are also other standard Python IDEs for the desktop, just as well as there are IDEs for the browser. Other options include Sage (meant for creating math and science-related Python programs) and PythonAnywhere (a browser-based Integrated Development Environment which doubles as a hosting environment. Python Implementations CPython, which is the main Python implementation, meets the C89 standard and is written in C. It is used to compile the Python programs to intermediate bytecode, which can then be executed by a virtual machine. It has a large standard library written both in C and Python. It is also available for multiple platforms including Microsoft Windows (XP support had been dropped, however) and most Unix-like systems. This proves the crossplatform philosophy that was present since Python’s inception. As previously mentioned, there is also PyPy, an interpreter for Python 2.7 and 3.2 which has gained reputation for speed (over CPython) and compliance. There is also a version in the pipelines that aims to increase speed by using software transactional memory to take advantage of multi-core processors. Stackless Python is another implementation, coming as a significant port of CPython. It does not utilize the C memory stack, instead implementing microthreads. This allows hugely concurrent programs. It is to be noted that PyPy also comes in a stackless version. Aside from these, there are other just-in-time compilers that have since fallen into hard times (i.e., lack of developmental support). One comes from software giant Google, which launched the Unladen Swallow project back in 2009. This had the original aim of increasing the speed of the interpreter by at least 5 times through the LLVM (Low Level Virtual Machine) infrastructure. This improves the ability to multi-thread, allowing scaling for up to thousands of cores.

There is also the “specialising just in time compiler” called Psyco, which integrates with CPython. This transforms the bytecode into machine code at the runtime. This produces a code that is specialized for specific data types which can also run faster than standard Python codes. Google is far from being the only big name to dabble in Python compilations. Back in 2005, mobile phone company Nokia also released its own Python interpreter for its Series 60 mobile phones. This was called Psy60, which included a lot of the modules from CPython along with added modules for Symbian OS integration. This project, unlike the Google counterpart, has been kept mostly up to date with many third-party modules available. The Nokia N900 even supports the language with its GTK widget libraries, allowing programs to be written and run on the phone itself. There are also different compilers available to high-level object languages using as its source language unrestricted Python, its restricted subset, or a language similar to it. Examples are: Jython, which compiles the language into Java byte code. This can then be executed by any implementation of the Java virtual machine. This will also enable the use of Java library functions from the program in Python.

IronPython, which follows an approach similar to Jython except that it runs programs on the .NET CLR (Common Language Runtime).

RPython, which can be compiled into Java bytecode, C, or Common Intermediate Language. It is also used to build the PyPy interpreter.

Pyjamas, which is used to compile into JavaScript.



Shed Skin, which can be used to compile to C++.



Pyrex and Cython, which can be used to compile to C.



Discussion on different Python implementations can be very lengthy, and we will be reserving that as the final chapter of this book.

CHAPTER 2: Advantages and Disadvantages Of course, Python is far from being the only programming language you can use for your coding needs. But why should you choose it? Here are some of the most common reasons Python is recommended: Easy-to-learn Syntax. It doesn’t matter if you have been acquainted with other programming languages before — both programmers and non-programmers can use Python easily because of its syntax. Readability. If ever you need to take apart a code that someone else wrote (either for study or troubleshooting), you can easily do it due to the clear readability of the programming language. In fact, there are some who refer to Python as an “executable pseudo-code” due to its syntax following natural language used by real humans. This gets rid of the verbosity and formality used by other languages, and also goes as close as possible to the way programmers habitually outline their ideas. This bring Python inherently close to the very simple “pseudo-code” programmers use to outline their thoughts and solutions to other programmers. Even programmers who write in other languages are given to using Python as a testing ground wherein they can test their code before implementing it in a different language. High-level Usage. Unlike the inscrutable low-level languages, Python allows you to code a lot faster. Object-Oriented. In a nutshell, object-oriented programming lets a user create data structures which can then be re-used. This reduces the amount of repeated work that needs to be done. Languages often define objects with namespaces, which can then edit themselves using certain keywords. Python shares this distinction along with other languages such as Java, C#, and C++. Object-oriented languages can also be used to design almost any type of non-trivial software, which can in turn be implemented in any scripting or programming language. A good example lies in a number of Linux kernel features, which feature objects. These implement their own encapsulation of data structure and behavior through pointers to functions in C. New programmers benefit greatly from Python’s support for object-oriented programming since the same concepts and terminology used in its study will invariably appear in the work environment. In case the new programmer decides to learn a new language, the same object-oriented concepts can still be used. Free of Charge. Being a Free and Open-Source Software (FOSS), Python is accessible to

anyone. The pre-made binaries are distributed by the Python Software Foundation, and the code can also be modified and re-distributed as allows by the CPython license. Cross Platform. As has been mentioned before, Python is available on all major operating systems—MS Windows, Mac OS X, and different flavors of Linux. Wide Support. Like any good open-source project, Python has an active community that is complete with different forums, websites, mailing lists, and news groups that also attract knowledgeable contributors from different tech scenes. Safety First. Unlike other languages based in C, Python does not have any pointers. This makes the language much more reliable. Errors also never silently pass unless this is explicitly ordered. This will allow the user to read and see why the resulting program crashed, allowing efficient error correction. All In. In the language of many coders, Python has been known as the “batteries included” language. This means that there are more than 300 different standard library modules that contain both classes and modules for a large subset of programming scenarios. Some of these include creating temp files, mapping the files into memory (through anonymous and shared memory mappings), spawning sub-processes and controlling them, decompressing and recompressing files, accessing indexed database files, and a lot more. These libraries can also offer interface to various GUI, as well as send emails, and parse web pages. With less than a dozen code lines, a person can create a custom web server using the Python language—powered by one of these standard libraries. Greatly Extensible. Aside from the standard libraries, there are also extensive collections of add-on modules that are freely available. There are also frameworks and libraries, as well as toolkits that all conform to conventions and standards. As an example, nearly all the database adapters (used in talking to any client-server engine like Oracle, MySQL, Posrgres, etc.) conform to Python DBAPI, thus allowing users to access them using the same code. This makes it easy to modify Python programs to support any type of database engine. Disadvantages Then of course, like with any programming language, not everything is a rosy walk in the park. There are a couple of disadvantages in it that one should still watch out for as he learns:

Speed. Unlike languages that need to be separately compiled and then executed, Python is executed by an interpreter. This causes it to be slower. For most applications, this will not pose a problem. However, there are certain instances when an increase in speed is desirable. This brings up one idiom coined by Python users: “Speed is not a problem until it is a problem”. Simple Rules. Python is a very easy programming language. However, when one has mastered it, one can be too accustomed to its features especially its late-binding dynamic models and its extensive libraries. Thus, when shifting to a new language that does not have these, the user may run into difficulties adjusting. In other languages, one typically has to declare the types of variables first and then cast values from this type to another. There are also requirements for adding curly braces and semi-colons (as well as other syntactic differences) in other languages that a Python user may take for granted.

CHAPTER 3: When To Use Python Each programmer has his preferred language, and decisions on which to use often come subjectively based on experience and preference. In fact, this sometimes doesn’t matter, as most of the modern languages can perform the majority of the programming tasks. They also mostly include the needed libraries that might be useful for day-to-day tasks. There are other times when concerns about interoperability can dictate one language over another (as well as a platform over another), but in modern times this is commonly solved by shared SQL databases, XML interchange, and web services. Therefore, when choosing whether to use which language for your programming needs, it is important to look at the way that the language is designed—what makes it easy to use for your purpose and what impediments it may present. If the performance and features are moot points of argument, then other more intangible items such as elegance and “feel” should be more carefully considered. That said, Python is often praised for being one of the languages that can make programmers feel more productive. It can “glue” together different applications quickly, too, and its more minor details have attracted legions of fans—and haters—from all over. Sometimes, all the opinion around Python can distract potential users from the careful consideration of when to use it—this chapter is meant to address this. For many developers around the world, Python has evolved into the default scripting language choice. Some consider it rare that a programmer starts in Python and then suddenly discovers that the language is inappropriate—but it can happen, even if Python is scalable both in performance and project size. The general degree of freedom that the simplicity of the language allows would also mean that sometimes programmers would have to be more disciplines in the way the code is structured. On the Desktop A programmer can write applications on the desktop using Python. This can be accomplished through frameworks like PyGTK or WxPython. Take note, however, that most desktop applications are still coded in compiled languages like C, C#, or C++. These languages have frameworks that commonly have more sophisticated tools for development. Thus, the resulting programs are usually easier to distribute, without requiring the user to install Python first.

Python has been blessed with good tools for graphical development, including Eclipse PyDev and Wing IDE extensions. However, in reality, most of the Python developers work in a style reminiscent of the UNIX operating systems — through terminals and standalone text editors. On other platforms like .NET or Java, the environments like the MS Visual Studio will always have a tighter integration with the language. Whether this is a good or bad thing, however, will depend on individual experiences. Python on the Web Much clamor has surrounded the alleged movement of Java programmers to Ruby-onRails, allegedly due to them getting tired of Java’s overhead and enterprise frameworks. While this may be true, this may also be the fruit of good marketing from the Rails proponents. In fact, Python also boasts of the same benefits as it has. There are several rapid and successful web app frameworks available for the Python language, each of them with their own slant. There are also those that even share the same components. Some of the most popular include Pylons, Django, CherryPy, TurboGears, Grok, and Zope (from which Grok is based). These can all be used for serious Python applications. For example, Zope was conceived as an open-source app server, pioneering its field and proving that Python is viable even in enterprise environments. This is despite many Python proponents claiming that the idea has recently become “unPythonic”. Another popular open-source implementation is Plone, a content management system running on Zope and implemented in organizations like Oxfam and Novell. Pylons is the stuff that runs high-traffic Reddit.com, and Django sits under the hood of Revver.com. Deploying web applications in Python is mostly a straightforward affair, even though it is not quite as simple as PHP application deployment in Apache. Object/relational mappers like SQLAlchemy cater to database connectivity very well. However, most of the web frameworks of Python have yet to catch up to Java or .NET when it comes to enterprisegrade app servers — the latter two offer better support for failover, high-availability clustering, and server management. .In Enterprise Settings Most large companies and organizations have a standard development scheme on either .NET or Java—the two platforms seen by many to be best suited for enterprise applications. There is a general belief that using these will help improve the interoperability of the deployments while also lowering the maintenance costs. While Python usually does not operate in the same level of scale or ubiquity, it stands as a very useful complement. It even stands as a solid alternative when the platforms mentioned above prove inappropriate.

The common enterprise platforms are usually—and by necessity—very large and very complex. They usually depend on more elaborate tools to allow programmers to manage the code, deployments, and subsequent builds. In many applications, this may be overkill. Ideally, programmers should be able to take any language that captures their fancy when the inspiration to code hits them. Python’s immediacy allows it to be perfect for such common automation tasks, quick prototyping, and similar purposes. There are also many developers who feel that Python can give one the leeway to move beyond mere prototypes, without having to scratch all of their previous work. This considered, Python can prove to be useful for large and complex systems. For example, YouTube runs mainly on the Python language. It is also a preferred language at many organizations, like NASA, Google, and Industrial Light and Magic. There are specialized frameworks and Python libraries for scientific work, web services, data manipulation, XML interchange, and lots of other things. All is not sunshine and rainbows, however—the main disadvantage of Python in such enterprise settings is that programmers are usually scarcer than in other languages like Java. While Python is very easy to pick up for a seasoned programmer, the wealth of specialized training courses, books, and even certifications available in Java are yet to be matched by the language. On top of this, the sheer expressivity and power that is offered by Python would mean that it takes a seasoned developer to create a sterling product. By design, C# or Java are more restrictive. This forces the programmer to stick to stricter rules, commonly revolving around interface compliance and type safety. For others, this can hinder productivity. Still for some, this is ideal in reducing the mistakes and accidents of design. Lastly, concerns regarding application integration can dictate the prevalence of a specific platform or language. In the service-oriented and heterogenous landscape today’s systems live, it is usually possible to write a Web service using Python while allowing it to plug into a service bus from Java. In the end, this can be consumed by a program in Visual Basic—and we are just scratching the surface. Internal Compatibility Python has had a long history, as we had covered. However, compatibility has not been a real concern—at least until the branching of Python 2.x and 3.x. In fact, programs that were written for Python 1.0 can still run smoothly on at least up to Python 2.5. Python has been very committed to supporting existing users of its language, with a community large

enough to withstand the pressure of diverging paths. Use Python when… Python should be primarily considered when the following conditions present themselves: When you need a proven, reliable, and general-purpose scripting language complete with an extensive standard library.

When you need a language that can be useful across different programmingrelated tasks, from web apps to shell automation.

If you are familiar with and like the syntax and philosophy of Python



And of course, if you find the language fun aside from being productive.



On the other hand, consider the following as red flags for choosing Python—or at least as reasons to consider using a different language: When you are building a massively parallel or embedded system, which would not benefit from a scripting language (mainly due to the latter’s concerns about execution speed).

When you are primarily building desktop apps, especially if it will be deployed on Windows. Usually, other platforms (specifically .NET) offer more robust tools as well as easier distribution paths for the final software.

If you are working with a team of less-experienced programmers. They may be better off benefiting from the plethora of training for other languages like Java. Also, they are a lot less likely to commit mistakes when using type-checked, compile-time languages.

If you have needs that may be better served by a specific language aside from Python. For example, if you know Perl and you have to do a lot of text processing, then that might be more ideal.



CHAPTER 4: Installing Python In the first chapter, we went into detail about the different implementations of the Python programming language. Before one can successfully code, one has to make sure he has the necessary tools—that means getting Python into your device. If you are lucky (read: if you have the right operating system), you might not even need to download it as it might have come pre-installed. If you wish to check if you already have Python, simply open up your system’s Command Line Interface (CLI) and type “python” (minus the quotes). If you see a response—typically comprised of the word “Python” and some build information with the version number—then you are good to go. For example, here is an example of the response that would show up when using a 32-bit Windows XP: Python 2.7.2 (v3.4.2:ab3c023a9432, Jan9 2016, 10:11:04 [MSC v.1600 32 bit (Intel)] on win32 Type “help”, “copyright”,”credits” or “license” for more information. >>> Or if you are using Win 7 64-bit, then you will see the following response: Python 2.7.2 (v3.4.2:ab3c023a9432, Jan9 2016, 10:11:04 [MSC v.1600 64 bit (AMD64)] on win32 Type “help”, “copyright”,”credits” or “license” for more information. >>> In case you get an error as a response, then you will need to download Python first. Downloading Python Fortunately, downloading Python is a breeze. It is recommended that you get the latest version, if possible in the 3.X series (since it is the one that gets the most active developments). If you prefer, you can still get the 2.X branch. Be reminded, however, that no future development of this branch is planned (with the most recent release being way back in 2010). The major implementation (CPython) is available on www.python.org/downloads/ Windows and Mac OSX users can easily download an installer which will do all the work

that is needed to get Python to your system. If you instead use Linux (or another Unix-like operating system), then you can build the binaries from the source code itself. There are some distros in the Linux world that allow Python to be installed more easily, coming in the form of pre-made binaries. For many of the most popular Linux distros, documentation should be available on the website. Also, do not skip ahead to this step without trying out the previous one—checking your device for any pre-installed versions of Python. Note that most Linux and Mac machines already come with a form of Python installed—almost always the 2.X branch. Remember that this is not compatible with 3.X, so if you wish to upgrade you can still download. Python Online In case you are working from a different device, or if you decide that downloads may pose a security risk, or in case you just want to work online for any reason — you’re in luck. An interactive shell for the language is offered by the Python Software Foundation. This comes by the name PythonAnywhere, and is available on their website. This has more implementations than vanilla CPython, and as a plus no download or reinstallation is required. On the other hand, you will not be able to execute scripts and files from this shell, hindering the more advanced Python learners.

CHAPTER 5: Python Basics The Shell There are many ways to call it—command prompt, shell, prompt, command line, CLI— but they all pertain to the same entity. This is one of the mediums of communication between the user and the Python interpreter. For a good part of this book, most of the Python codes seen in the examples will be done in the shell. When starting up the shell, do the same thing you did for testing whether or not your machine has Python on it—namely, pull up the CLI and enter “python”. You will see the details we laid out above—the version number, date of build, compiler used for the build, the computer architecture, as well as the operating system. The information will be useful for debugging, as well as for checking which version you have on hand. From the initial text display, one of the things you will need to pay attention to is the set of three greater than signs (“>>>”). This will tell you that a prompt is present, asking for input. This prompt will always be shown in the examples we will be using, so it is not something you will have to type out. For example, here is a code with the prompt displayed: >>>print(“Hello, world!”) Hello, world! As with the information above, the new line that appears without the prompt is the output. You will also notice that the prompt will change into an ellipsis (“…”) when you enter a command that has indentations. You will have to be careful not to see this as part of the actual code: >>>if True: … Print(“Hello, world!” … Hello, world!

The Script Once you have got the hang of Python programming, you will find that you find it tedious to repeatedly type the same programs into the shell. Like all its sibling interpreted programming languages, you will be able to store and execute the Python code directly from a file. There are two different types of Python files—plain text and bytecode files. “Plain text” files are so-called since they are simple files that are created and edited using any simple text editor. This may be the Windows-standard Notepad, or a downloaded utility such as Notepad++, Sublime, Kate, or even Python’s very own IDLE or IDE. The bytecode file, o the other hand, is a compiled CPython file. We will go into more detail about these files later on in the book. Then, there is the third type of file—the Python script. This is usually suffixed with the extension “.py”. It is as executable as anything you type in the Python shell when it is executed by itself—this goes for most operating systems (Windows, Mac, and major Linux distributions included). Here is an example of a very simple script that we can title “greeting.py”: Print(“Hi there! I am a Python script!”) Input(“Press enter to continue…”) Take note that things may be a little different depending on whether you are using Linux, Mac, or Windows. For users of Linux, Mac, and other operating systems derived from UNIX, you will need to include a “shebang” at the beginning of the script. For Python, you will need to include the following line: #!/usr/bin/env python This line tells the shell where the interpreter lies. One good thing about this is that it starts with the hash tag (#). This is ignored as a comment on other operating systems whose scripts do not require the use of a shebang. This means that you can take any code written in Mac or Linux and execute it in Windows without worrying about the Windows interpreter misinterpreting the shebang! For Windows users, you will have to remember that Python files have to be executed with py.exe. This will start by default with the Python 2.X branch, if installed on your computer. Executing “py” should tell you which version you have running. If you

currently have 2.X but are in need of the 3.X branch, you will need to us a switch—“-3”. In order to make Python 3.X as the default version, you will need to open up the control panel, then create an environment variable “PY_PYTHON”. Set the value of this variable to 3. Rolling back to 2.X is as simple as deleting PY_PYTHON and changing the value to 2. Running the Python script can be done either by clicking on it or by running it from the system’s shell, regardless of which operating system you are using. The script sample above, for example, should give you the lines “Hi there, I am a Python script!” and “Press enter to continue…”. The script will then pause up until you actually press the Enter key. If you tried this, then congratulations! You have just built your very first Python script! Another note on saving Python scripts in Windows, there are some users who might not be allowed to save directly to a “.py” extension. In this case, you can create a text file then just save it with .py afterwards. Or, you can also change the “Hide extensions for known file types” toggle in your Control Panel. This can be found under the Folder Options. Other more advanced options are available, but these should suffice for our current purpose. IDLE Earlier, we talked about IDLE, or the Integrated Development Environment. This is the default IDE that is installed when one gets CPython. On the Windows OS, this may be accessed by right-clicking any Python scrips, then selecting “Edit with IDLE” on the context menu. You can also open up IDLE directly from the CLI by typing “python -m idlelib”. When using IDLE, a couple of things will be noticeable. First, you will find that the code is colored—strings are green, comments are in red, functions (built-in) are purple, and so forth. This will allow you to have a visual cue of certain parts of the code, a significant advantage over mono-colored text. Second, you will also find that IDLE would make automatic indentations where needed. It will also modify the function of the Tab key— inserting four spaces when pressed. For those just starting out, these default settings are perfect for learning the ropes. However, your preferences may change when you have reached the intermediate to advanced stages. To meet these changing requirements, the creators of IDLE made it into a

very customizable module. For example, the red-and-green distinction may not work too well for a color-blind person, so the colors can be swapped out for something else. The default settings can be changed in the Options menu, in the menubar. Basics and Jargon Now that you know the very basics and the tools available to you, it is time to tackle some of the more commonly-mentioned jargons and other stuff. More advanced items will be tackled later on, but pay close attention to these starters: 1. In Python, a “comment” is any text preceded by a hashtag (#). This is meant to be a sentence that is readable by humans (e.g., a note for yourself or for a fellow programmer) but unreadable by Python. For example, writing something that says “# For your eyes only” will appear on the code but will be ignored by Python upon interpretation. 2. Once you start seeing an ellipsis (…) or three greater-than signs (>>>), then this will mean that you are dealing with the Python shell. 3. “Variables” are namespaces such as “somevar” and “var” (or anything you define). It can hold Python data types, such as numbers or strings. More about this will be discussed later. 4. If you are following the steps in this book to the letter but keep on seeing error messages, double-back and check the Python version you are using. Remember that the exercises here are meant to work on Python 3.X. 5. Don’t confuse the term “Python script” with the actual programming we are about to do. Essentially, the Python script is just a plain text file that has a Python code in it.

CHAPTER 6: Python Versions Before we proceed with all the coding, there is another thing that we have to clear up—the different versions of Python. Throughout this book, you will be seeing examples and suggestions that will only be effective for a specific Python version. This is especially true when we get to the optimization section towards the end. You will inevitably ask: “Which Python version should I be using?” Here’s the (extremely) short version of things: Python 3.X is the present and the future of Python, while 2.X is the legacy. What’s the difference? As mentioned, the last version of the Python 2.X branch—2.7—was released back in 2010. There will be major releases after. However, Python 3.X is still being developed (very) actively, and is currently in 3.5. All of the most recent standard improvements for the library, for example, will be available only in 3.X. However, despite the improvements of 3.X (better Unicode, turning print and exec into statements to scratch the surface), the broader ecosystem of the programming language has already amassed a huge amount of add-on quality software through its years of growth. The downside of being in bleeding-edge 3.X is the lack of backwards compatibility, therefore losing you the ability to use some of these fine software (especially those done in-house in companies). So which version should I try to use? For starters, you should best stick with what is on your PC—what you get with the previous chapter would be it. This will allow you to just explore the basics of Python, since you can always upgrade later. For most of you, that would probably mean starting with Python 2.7. Now, what if you’ve already progressed beyond the basics? How do you choose whether you wish to continue with the 2.X or the 3.X branches? As is common, the version you want to choose will greatly depend on what you want to do. You may first try getting Python 3.X and see if you can do everything with it. There

will be a few downsides, which will include a slightly worse support for libraries. If you are creating software for mass distribution, be mindful that you will also need to have your users install Python 3.X. The bleeding-edge Python will also suffice if you will be writing things which will use none of the Python 2.X modules. On the upside, Python 3.X has been known to correct some quirks that are usually blockers towards learning Python. However, there are also certain scenarios where it will be better for you to stick to legacy Python. This is primarily if you will be developing for an environment that you have no control over. These environments will usually impose their own specific versions, which will not allow you a free selection from the currently available ones. Also, you might come across the need to use a third-party utility or package which has not yet been ported to the latest branch. Sometimes, you may be able to painlessly port these packages, but this is not always the case. In these times, you should stick to Python 2.X to retain full access. A popular module that has not yet been ported to Python 3.X (as of time of this writing) is Twisted—useful for networking application. Most of the other libraries—so long as they are actively maintained—already have people working to make them available for bleeding-edge support. However, some other libraries have other priorities—for example, Twisted focuses more on its production servers where the older Python support is more important. Supporting a brand-new version with major changes is put far back on the back burner, since the porting process is far from trivial. Other more common modules that have already been ported to Python 3.X include Tkinter (for the creation of GUI applications), PyQt, PySide, and PyGObject (for the creation of GTK+ GUIs). Here are other packages already ported to Python 3.X: Numpy. This is useful for number-crunching. Django, CherryPy, Flask, and Pyramid. These are useful for web sites. PIL (now Pillow). PIL was an image processing module which has been replaced by the Pillow fork for Python 3.X support. Cx_Freeze. This is useful for packaging the applications complete with their dependencies. Py2exe. This is great for packaging the application for Windows OS users. If you find Python 3.X fun to use but are afraid of possible dependency issues, then it will be a good to do some extensive research. Note that much of the modern code written using Python 2.X should not be largely changed in Python 3.X. A sterling example will be any code written to inter-operate with GUI and web frameworks that will force aps to distinguish text and binary data.

Note as well that if you will be using an alternative Python implementation like Jython, Pyston, IronPython, and the like, you might find that there is a relative scarcity of support for Python 3.X. This might be a good consideration if you wish to choose such implementations, since you will have to think twice about performance and/or integration with other systems. Python 2.X makes its case As a simple Internet search will tell you, those who wish to stick around to Python 2.X are in the minority. A greater chunk of the Python community believes that the future of Python lies in its latest release. After all, it was the one that took out all the mistakes of its predecessors. However, this is not 100% true. In fact, some of the improvements (notably the lessdestructive ones) have been backported from 3.0 and 3.1 to 2.6 and 2.7 respectively. Only the following features are available exclusively on the 3.X fork (note that this is a nonexhaustive list): ● Default Unicode strings ● Clean separation between Unicode and bytes ● Function annotations ● Exception chaining ● Keyword-only arguments syntax ● Non-local variable declarations ● Extended tuple unpacking All this considered, any well-written code in 2.X can still be much like 3.X. This can be many different things. A good example is the use of the xrange function for an optimized Python 2.X code. The xrange has disappeared in Python 3.X, but is has formed the basis for the new range implementation. You will see how this is applied towards the end of this book.. Bottomline? As a programmer, the best way to optimize the code is still not to pore over the strengths and weaknesses of each branch. Especially for those new to the language, the emphasis should be on the writing of good code. The tools with which you write it will only be useful if the code itself is clean.

I use Python 3.X, but there’s this library available only on 2.X. Do I change to 2.X, or should I quit on the package? If you do not have other packages that may serve as alternatives, then you will have a few other options: ● Port the entire library to Python 3.X. ● If that is too hard, you can instead start off with 2.X. Then you can switch to 3.X painlessly so long as the code is good and every needed dependency has been ported. ● Decide if that feature which requires the library is integral to your program. If not, then perhaps you could drop it. The best resort is, of course, the first. Oftentimes, you might even find that someone is already undertaking the process of porting the library to 3.X. If that is not the case, then you can start it. While porting is not always easy, it is still a lot easier than having to write everything from scratch. I had written code in 3.X, and now it has to be used by someone with only 2.X For those who wish to convert code from 2.X to 3.X, a tool called 2to3 exists. Fortunately, a tool that converts the other way—3to2—also exists. Whereas the former is not always successful, converting from 3.X to 2.X is theoretically easier since the former does not have too many tough instances that the converter needs to handle. However, it is possible for code conversion to fail, especially when the source makes heavy use of features available only in the 3.X branch—such as extended tuple unpacking or function annotations. Common code base support for Python 2.X and 3.X Despite backward incompatibility, there is a fairly large common subset between versions 2.6+ and 3.3+. In Python 3.3, the u prefix support for the Unicode literals has been restored—this means that semantically correct code written in 2.6+ can now be sourcecompatible while still remaining largely “idiomatic”—a concept that will be explained later on. Handling the different names in versions 2 and 3, however, would mean that some of the things would not be imported from the same place. In summary…

Bottom line is that while Python 3.X is more consistent, it lacks the complete support of third-party modules that 2.X enjoys. This can go on for some time, despite the great efforts of programmers. And while the 2.X family is effectively at a dead end when it comes to development, all major frameworks will still run on it. Like in 3.X, this is seen to continue for a significant amount of time. There’s also a great wealth of documentation already in place for Python 2.X, while those for 3.X are still cropping up continuously as older documents are being updated. Some of all that talk might be confusing for you if you are a beginner to programming. Hopefully all that will be clear when you finish the book. But then again, that is the point we are trying to make here—there are subtleties that will surely differentiate between the two branches of the same language. If you know what you’re doing, you can make an informed decision on which to use, based on all we have laid out here. But if you are just starting off, you should stick to whatever you have on your computer as you read this—there will be time to mull over versions later. Speaking of starting off, the next chapter should send you on your merry way!

CHAPTER 7: Learning How to Count—Python Integers In the first chapter, we compared Python to ABC. Here, let us consider how Python does numbers—123. There are two types of numbers in Python—integers and floats. Integers (“int”)here follow the same conventions we have learned in school mathematics . They are whole numbers— 5, 9, -75, 5000 are all examples. Numbers with decimal points—such as 3.1416—are not integers. Instead, they are floats. As if the distinction wasn’t easy enough to figure out, Python has a nifty tool to figure out whether a number is an integer or not. Simply use the built-in “isinstance” function to check if an item is an integer or nor: >>> isinstance (54, int) True Note that all you have to do is to place the number and the term “int” inside a parenthesis after the “isinstance” function. The “int” provides the condition “isinstance” will compare against. If you get a True. Then the number is an integer. A False would mean the number is a float. If you fancy something just a wee-bit more challenging, you can exploit the concept of integers in order to turn the shell into a calculator. Simple mathematical operations can be performed on integers—addition, subtraction, multiplication, and division (+, -, *, / respectively). For example: >>> 10+10/2 15.0 If you have noticed in this line, Python followed the order of operations—multiplication and division first, then addition and subtraction. This is why the answer did not turn out to be 10. You will also notice that the output is a float, despite the decimal section being a 0. In Python, a float always comes out when you try to divide. Lastly, a minus sign in front of any number inverts its sign into negative.

But what if you want to divide and get a whole number as an answer? This can also be done through “floor division”. To use this feature, simply use two slashes (“//”) when typing out the problem. For example: >>>700//7 100 Floor division works by rounding off the resulting quotient, therefore giving you a whole number—an integer—all the time. You may also wish to get just the remainder of a division process by using the modulo feature. This can be accessed through the percent sign: >>>1%52 1 For those wanting to solve the power of a number, two asterisks (“**”) can be used: >>>2**5 32 Non-Decimal Integers The numerical system that we are accustomed to using—as well as most numeral systems in the world—is ten-based. While this is a very useful way to go about our daily tasks, this isn’t often the most useful way of communicating with computers. This is why programmers commonly employ other forms of numerical systems—binary, hexadecimal, octal, etc. These numeral systems will have to be partially covered in this section, in order to gain a deeper understanding of Python’s numbers. Let’s start with binary. This is something that most people have already heard, and yet is something that is not all too commonly understood. While it has always been inextricably linked to computer language, binary as we know it has been in use way before electricity even came into widespread use. As the word suggests, “binary” is based on the numeral 2. This means that only two numbers are used—1 and 0. This makes 1+1=10 instead of the common sense 1+1=2.

In order to use binary notations in Python, you will need to add the code “0B” or “0b” at the start of the number. For example: >>>0B11 3 The output line gives you the decimal conversion of the binary notation that was entered. Of course, you can also do mathematical notations in binary, but the output will always be in standard decimal. Octal numbers, on the other hand, are numbers that aren’t in as much use as the binary system. One of the biggest reasons is that the numeral system has been surpassed by the hexadecimal in computer use. Back in the time, octal made perfect sense because it can fit perfectly into three bits. However, it fails to fit into the standard 8-bit style. In case you ever need to use octals, however, it is a relief to know that Python still supports them. Octal numbers are made up of digits 0-7. In order to use the system in a line of Python code, simply add “0O” or “0o” at the beginning. The octal system behaves in just the same way that binary behaves. >>>0o100 64 Then, there is the hexadecimal system which has been deeply ingrained in computer usage. It is especially useful since it can fit into a “nibble” (Yes, it’s an actual measure—4 bits.). Of course, two nibbles make a byte, where hexadecimal still works. The only tricky part is that hexadecimal has to use 16 characters as “digits”—and we only naturally count from 0-9. This means we are using 0-9, and adding in A-Fin order to complete a hexadecimal notation. And yes, we are using letters as numbers. In order to work with hex numbers in Python, you will need to add the “0X” or “0x” prefix to the line of code. >>>0xE 14 Note that you do not have to necessarily use capital letters when working with hexadecimals—the extra pinky finger movement may prove tiring. If you are more

comfortable, lowercase letters would also work. This topic of non-decimal integers might not come into play until you are in the intermediate to advanced stages of Python programming—however, it will be important to understand how to tap them now that we are in one of the most basic of Python lessons. Python Floats Integers may be great for many situations, but the fact that they are whole numbers can pose quite a limit on them. First of all, they are not necessarily real numbers. In mathematics, a real number is any value that will represent a quantity along one continuous line—a definition that puts fractions (in decimal forms) within its folds. This means that 3.1416 and 1.75 are both real numbers. In the field of computer science, these numbers are called “floats”. In order to test if a number is a float (despite the easy distinction), we can do similar tests to what we did for integers. >>>isintsance (4.5, float) True >>>isinstance (0, float) False Like before, the word “True” will appear for positive matches with the “float” condition and a “false” will appear otherwise. As a rule of thumb in Python, floats are those that have a decimal point while integers are those that do not. That the two have the exact same value is not considered—as in the case of 77.0 (float) and 77 (integer). When it comes to the arithmetic operations, the same ones we saw for integers will be applicable for floats. Before you start playing with floats on your own, there is one other thing you need to know—floats are limited to only a certain degree of precision. This is due to Python’s (and computers’) architecture. Consider for example the following piece of code: >>> 2+0.00000000000000000000099 2.0

As you see, the answer is still a float—however, the sum cut off all the other decimals and displayed only 2.0. This is technically fine for simple everyday computing, since the two 9s on the end are basically insignificant numbers. Check out this other example: >>>1.13-1.1 0.029999999999999805 This is another demonstration of how floats lose precision. Of course, the answer would be a simple 0.03. However, quirks of computer memory architecture brought out a different answer. You will notice, however, that as the minuend (the first number in a subtraction equation) increases in value, so does the answer regain precision. Hence, when working with Python, it is important to know that there may be a margin of error when dealing with decimals. Booleans Students of logic will remember this. In Python as in many programming languages, a Boolean is either a True or False value. This is essentially a special data type, and is considered a subclass of integers. A Boolean has two distinct states, and only one of those states may be there at a time. Think about it—there are many different Boolean values that we work with everyday—hot or cold, on or off, light or dark. Aside from the True or False of Booleans, there is the Boolean expression—which can take such a statement such as 1=0 and 1=1 and churn out a valuation of False and True respectively. Any empty number or data type will be judged as False, and all other will be judged as True. The “bool()” method can be used to demonstrate this: >>>bool(“Python”) True >>>bool(785) True

>>>bool(0) False >>>bool(“”) False >>>bool() False >>>bool(0.0000000) True Note that both True and False are case-sensitive—this means that you have to type them exactly as they are shown, otherwise Python will prompt you a syntax error. Just like in logic, Python’s Boolean statements can also use operators—and, or, not. The “and” operator produces a True answer if you have all the Booleans as True—otherwise, it is False. The “or” statement will allow a True answer as long as one (or more) of the Booleans is True. If all of them are False, then a False answer will be given. Finally, “not” will reverse the Boolean partnered with it. To see it in action, here are a few examples: >>>not True False >>>False and False False >>>False or True True >>> not (True and False) True

>>>not (False or True) False Complex Numbers In mathematics, complex numbers are represented as a+bi—where both a and b are real numbers, while the i is an imaginary number (where, in turn, i2=-1). Within the world of computers—and particularly in Python—the i is denoted as j. This makes the equation a+bj. One should also note that both a and b are being treated as floats. This will be further discussed later. >>>1+5j (1+5j) >>>0+2.5j 2.5j If you will be experimenting with this, note that j is not case sensitive and so you can use the uppercase letter. You can also try extracting the real and imaginary numbers from the complex number: >>>(2+7j).real 2.0 >>>(5+24j).imag 24.0 Note that you will either have to put the entries inside parentheses, or else you will need to store them inside a variable. If not, then you will start getting weird results. Number Conversions Since floats and integers cannot always be mixed together, you will have to be able to convert one to another. Thankfully, Python provides for a very easy way to do this.

Let’s start off by converting floats to integers, using the “int()” method. >>>int(7.3) 7 >>>int(False) 0 >>>int(True) 1 You can also convert strings, though this will be discussed in better detail later. In order to convert integers to floats instead, it’s pretty much the same—use the “float()” method. >>>float(452) 452.0 >>>float(False) 0.0 >>>float(True) 1.0 Note that these two previously-mentioned methods cannot be used on complex numbers, or else Python will throw errors. You can get around this by extracting the real or imaginary parts of the number, through the “.real” and “.imag” methods. You can also use a built-in Python method in order to convert data into a complex number —however, this is a bit trickier since it takes two parameters. The first one is the real number (required), and the second is an imaginary number. This is then linked by the “complex()” method.

Here are some examples: >>>complex(True) (1+0j) >>>complex(1,75) (1+75j) >>>complex(“8”) (8+0j) >>>complex(“25j”) 25j One thing that the astute reader would notice is that Python provides a code-based (method-based) way to ascertain, identify, convert, or operate on even the simplest numbers—case in point is the process of converting an integer into a float. Remember, however, that the simplest of the operations we have discussed were not meant to be used as is—they were all meant to play a part in a longer chain of codes that in turn will comprise a program.

CHAPTER 8: Python Strings Aside from numbers, strings are some of the simplest data types not only in Python but in most other programming languages. Strings can be created simply by putting single or double quotations around things. Here is an example of a string using single quotes: >>>’Hello world!’ ‘Hello world!’ Strings with double quotes do not affect the string, as can be shown in the following example: >>>”Hello world!” ‘Hello world!’ There is also a way to perform a “mathematical” operation on strings even though they are not numbers—for example, you can join two different strings together by using the plus sign: >>>”Hello,”+”world!” ‘Hello, world!’ If the strings are not held by variables, you can also concatenate them: >>>”Hello” “world” “no” “spaces” ‘Helloworldnospaces’ Note that this last example puts spaces in between the literal strings — but this was only done for demonstrative clarity. In practice, you will not need to put spaces in between them in order for concatenation to work. The following will work the same: “Hello””world””no””spaces”. Now, imagine that you have to type some very long string, which repeats itself. This can be done by using the asterisk (*).

>>>print(“hello”*3) Hellohellohello Escape Characters There are a few characters which cannot be expressed easily through a string. These are the “escape characters”, which can be integrated easily within a string through two or more characters. In the Python language, we can denote escape characters using a backslash “\” at the start. To start another line in the string, for example, a line feed could be added: >>>”Hello world!\n” ‘Hello world!\n’ This is not really impressive, if you look at it this way. However, let’s try using “print()” on this line: >>>print(“Hello world!\n”) Hello world! You might not have seen something new… but there is that extra line right under the string, ready to receive a new string. For your reference, here is a table of the other escape characters. Don’t worry about memorizing them, though, since the most important one you have to use is \n \’’ – Double quote \* – Single quote (‘) \ – Backslash \a – ASCII Bell \b – ASCII Backspace \f – ASCII Form-feed

\n – ASCII Linefeed \r – ASCII Carriage Return \t – ASCII Horizontal Tab \v – ASCII Vertical Tab \ooo – A character with the octal value ooo \xhh – A character with the hex value hh \N{name} – A character with the name “name” in Unicode database \uxxx – A character with the 16-bit hex value xxxx. \uxxxxxxxx – A character with the 32-bit hex value xxxxxxxx For the astute reader, the usage of the backslash might pose an entry into a problem with the string. For example, here is a line of code where the programmer needs to print a directory name for Windows. >>>print(“C:\newfolder”) C: ewfolder This is an example of where the “\n” escape character kicks in, creating a new line and picking up with the “ewfolder” part. In order to correct this, one could then use the “backslash” escape character — “\”. Hence, we have: >>>print(“C:\newforlder”) C:\newfolder This might grow tiresome, however, when you have very long directory strings. This calls for a simple way than using two backslashes all the time. In this case, we can simply use the prefix “R”. Like most instances, one can use the lowercase version as well. Once you place this prefix before your string quotations, Python interprets the string as a literal or raw one. In fact, “R” stands for “raw string”. This will tell Python to ignore the escape characters within the entire string. Here is an example: >>>print(r”C:\newfolder”) C:\newfolder

You may also assign the strings as variables. Here is how it’s done: >>>spam=r”C:\newfolder” >>>print(spam) C:\newfolder Newlines Now, say for example that you want to print text in multiple lines. You can do it this way: >>>print(“Hi!\nHello!\nHeya!”) Such a string can turn into a very long (and confusing) line, but there is a trick that you can use to allow you to span the text into multiple lines. This can be done with three quotations (“””) in order to start and end the string. >>>print(“”” …Hi! …Hello! …Heya! …”””) Hi! Hello! Heya! As you see, this can make things a lot easier and a lot less confusing. However, you will also notice that there is a linefeed that appears at the very start. This can be improved by adding a backslash at the start: >>>print(“””\ …Hi!

…Hello! …Heya!”””) Heya! Hi! Hello! Welcome! As shown, this fixes the issue and puts out the errant linefeed. Speaking of errant linefeeds, trying these exercises in your Python interpreter would alert you to the fact that the language automatically places another linefeed on the end of print(). If you wish to bypass this, it can be done this way: >>>print(“Welcome to Python!”, end=””) Welcome to Python! You can also string multiple lines without having to deal with automatic linefeeds. This can be done by using parentheses: >>>spam=(“Hello …world!”) >>>print (spam) Hello world! Formatting Much like in the C language, the strings in Python can also be subject to special formatting. This serves a specific purpose by easing the way for a better-formatted output. You will be able to format a string using the percent sign (%). You can also use the curly brackets ({}) formatting. Here is an example: >>>print(“The number five (%d).” %5) The number five (5).

The example code used the special format character %d, which has been replaced by a decimal-based integer. We used the percent sign (%) right after the string—this is the item that replaces the format characters. Below is another demonstration of formatting strings: >>>name=”Python” >>>date=2016 >>>print(“Copyright (c) %s %d” % (name, date)) Copyright (c) Python 2016 Notice the usage of the comma and the parenthesis. If these are not added around the format arguments, then an error will appear. Here is a table of all the most commonly used formats in Python: s. This is a string format, which is the default for formatting. b. This is the binary format. c. This converts the integer into a Unicode character, before being formatted. d. This is the decimal format. o. This is the octal format. x. This is the hexadecimal format. Use the lowercase “x” for a-h, and the uppercase “X” for A-H. n. This is the number format. This is almost the same as “d”, but this instead uses the current locale setting in order to insert the needed number separators. e. This is the exponent notation. This will print the scientific notation of the number. There is a default precision level (6). You can also use the uppercase version, which will print an “E” in the notation. f. This is the fix point. This will display a “fixed-point”number, with the default precision of 6. You can also use the uppercase version, which will convert “inf” to “INF” and “nan” to “NAN”. g. This is the general format. You can also use the uppercase version, which will automatically switch to “E” once the numbers become too large. Indexing

The strings in Python will support indexing, which will allow the programmer to retrieve just a part of the string. The following is a demonstration so that you can easily grasp this concept: >>>”Hi there!”[1] ‘i’ >>>spam=”Hi there!” >>>spam[1] ‘i’ As can be seen in the example, there is a number in the square brackets ([])—this is the index number. Using this, you will be able to extract a character from the string partnered with the index number. Remember that in Python, indexing starts from 0—so the maximum possible index of the specified string is one less than the number of all characters in it. Punctuation marks and spaces also count as characters. In case you choose a number that is beyond the string’s length, you will be flashed with a “string index out of range” error. Now, consider the following piece of code: >>>spam=”Hi there!” >>>spam[len(eggs)-1] “!” What you just read is a piece of code that was meant to extract the last character in the string—no matter how long it is. The formula is the string length (len) minus 1. The function “len()” is built in, and can be used to automatically count the length of the string. Typing “len()” will return 9, and 9-1=8—this makes 8 the index number, which then corresponds to “!”. The astute reader may see a disconnect here—why did it pull up the “!” instead of “e”, if we are counting one from the end? This is because the string length count does not start from zero, although the index number does. Thus, the string has 9 characters in total (string length), but “!” is indexed as 8 since “H” comes in at 0. Another important thing to consider is the immutability of strings—meaning their contents cannot be manipulated. These immutable types have values that are fixed and cannot

change. If you wish to change the value, you will need to reassign the complete variable. Consider the following example: >>>spam=”Hi” >>>spam=spam+” there!” >>>spam ‘Hi there!’ This piece of code demonstrates how the variable “spam” is assigned to a different value. How is this then related to indexing? The same rules will apply to indexing—all indexes cannot be manipulated nor can they be assigned new values. In order to reassign string variables while replacing a part of the substring, one will have to work a bit more in slicing the string. This will be taught in the next section, but we will give you an example of how it looks like here: >>>spam=”Hi there!” >>>spam=spam[:2]+”x”+spam[3:] >>>spam ‘Hi txhere!’ Slicing In Python, slicing will be one of the more important concepts that you will be learning. This is a feature that will allow you to extract a “substring” from the main string. This substring is in essence a string within the string—so the words “Hi” and “there” are both substrings of the string “Hi there!”. But substrings do not have any boundaries, so you can extract a single character (letter, punctuation mark, or space) out of a very long string of text if you so wish. In slicing, the most important character is the colon (:). Here is an example of the basic application of the colon: >>>spam=”Hi there!” >>>spam[0:1] ‘H’

In this example, you will see how Python builds upon the indexing feature that we had previously discussed. The line “spam[0:1]” uses the slicing feature on the string encased in the spam variable. It is basically read by Python as “get the substring starting from the character with the index 0 until the character with the index of 1”. In essence, the first number spells where the slice will begin, and the second number is where it will end. This form of slicing can be helpful in many situations. However, what if you wish to get just the first 4 characters after the start of the string? The len() function can be useful, but there is an easier method. By removing one of the parameters in our slice function, the language will slice from either the beginning or the end (depending on which side of the colon was omitted). Here is an example: >>>eggs=”Hi there!” >>>eggs[:6] ‘Hi ther” >>>eggs[6:] ‘e!’ As was demonstrated, omitting the first number will start counting from the very top all the way to the specified index number; those after it will be sliced. On the other hand, removing the number after the colon will start slicing from the start of the string all the way to the specified number. Another way to look at it is in terms of subsets—when combined, eggs[:6] and eggs[6:] equate to simply eggs. You will also notice that in slicing, the common “index out of range” error message does not apply, even when the index numbers you specify are really out of range. This error is suppressed, and instead returns the entire string. Encoding Now that we know what a string means and how it works (and is worked), it is time to delve further into its nature. In fact, we have only seen one part of the string’s nature. The true nature of a string may be different things, without the string having to change—it all depends on the encoding.

There are two prominent encoding schemes used for strings—Unicode and ASCII. Of the two, ASCII is the simpler one. It is a simple scheme for some (though not all) Latin characters, and some other things like numbers, money units, and signs. Unicode, on the other hand, is a larger encoding scheme that can include up to thousands of characters. Unicode is used to create one scheme which contains all of the alphabets, scripts, and characters in the world. Python 3.X uses Unicode as its default encoding system. This means that one can put almost anything into the string, and it can be correctly printed out by the interpreter. This is perfect for countries that do not use English as their standard language. ASCII will do them little good, since it does not allow too much characters— only 127 are present in this encoding scheme.

CHAPTER 9: Python Lists In Python, a list is an important data type which allows the user to keep sets of iterable items. A list is a mutable sequence—meaning that you can have a long list of items. You can denote a list using square brackets ([]). For the list to hold actual items, you have to place them within the brackets separated by commas. Here are a few examples of a list: >>>[78,92,56,1491] [78,92,56,1491] >>>[“h”,”i”,”t”,”h”,”e”,”r”,”e”,”!”] [‘h’,i’,’t’,’h’,’e’,’r’,’e’,’!’] You can also convert a non-list into a list, using the built-in Python function “list()”. This will be further discussed later on, but this is how it looks like: >>>list[“Python”] [‘P’,’y’,’t’,’h’,’o’,’n’] A list is also capable of holding different data types, so a programmer can safely mix strings, numbers, and even complexes. You can also nest lists within lists: >>>[[5,4,7,6],[“a”,”x”,”o”].[True, True, False]] [[5,4,7,6],[‘a’,’x’,’o’].[True, True, False]] Obviously, nesting can get pretty complicated as the nests go deeper and deeper. However, it can be leveraged into a powerful tool that will be harnessed at a later segment in this course. List Indexing

Just like how strings can be indexed, so can lists. Indexing can then be used to get a specific item from the list. For example, if you wish to have the letter “o” extracted from [‘P’,’y’,’t’,’h’,’o’,’n’], you will have to types [‘P’,’y’,’t’,’h’,’o’,’n’][4]. For brevity, though, the list can be placed within a variable first. And again, do not forget that indexing always starts at zero, even in indexes. Just like strings, one can index starting from the last item using negative numbers. Note as well that a -0 does not exist, and is just interpreted as 0. You should instead use -1 if you want to start counting from the end. And of course, if you try to index with a number that is out of range, then an index error will return. List Slicing And like strings, lists can also be sliced. When slicing a list, it will return with a newly sliced copy of the main list—meaning, the answer will also be a list. List Manipulation Manipulating lists is also quite basic. The best way to add a new item to a list is to use the built-in Python function “append()”. This can be done easily, as shown below: >>>spam=[5,4,3,2,1] >>>spam.append(7) >>>spam [5,4,3,2,1,7] Unlike strings, however, lists can be changed—they are mutable. The best way that this can be done is through indexing. Below is a demonstration: >>>spam=[1,2,3] >>>spam[0]=50 >>>spam [50,2,3] As you see, we were able to change the first value in the list.

As far as removing items from lists go, there are a few ways for this to be achieved. However, because the 13th Zen so dictates, there should be a path of least resistance that should be most preferable. This is demonstrated below: >>>toast=[1,2,3] >>>del toast[1] >>>toast [1,3] As you noticed, the simplest way is simply to append the “del()” function to the index number of the item that you wish to delete. Note as well that when an item is deleted, the remaining items move to the left (when applicable). If you keep on deleting the item “0”, then the entire list will be deleted soon enough. Instead of this, however, the most efficient way to delete an entire list is as follows: >>>toast=[1,2,3] >>>del toast[:] This kind of function totally removes all the items from the list. Note that this example only deletes the list, however—the variable is still there. If you wanted to delete the variable itself, you should use “del dog”. This will be further explained in a later chapter. As previously mentioned, the list is a mutable type—this means that content may change dynamically. Take, for example, the hypothetical list “spam”. This is not the list, but a variable that points to the location of the list. Another real-world example is an address book—it points to the location of the house, but not the house itself. Also, it does not know what is in the house. The list “spam” has the same traits. This leads us to some questions—foremost is, how would one copy the list “spam” if it only has the address of the list? Since the variable contains the address, giving a different variable this same address will not help. Consider the following: >>>spam=[1,2,3] >>>toast=spam >>>spam [1,2,3]

>>>toast [1,2,3] >>>spam[1]=5 >>>spam [1,5,3] >>>toast [1,5,3] As we saw from this example, the variables “spam” and “toast” both point to exactly the same list—any change that will point to any of these variables will change the other one as well. This is like having two separate addresses point to the same house. In Python, this is called “shallow copy”. For those who want to have two completely different lists (think of two identical but physically different houses, on separate addresses), you will need to do what is called a “deep copy”. The language always creates a deep copy for slice operations, so a simple slice can create a new list for “toast”: >>>spam=[1,2,3] >>>toast=spam[:] >>>spam [1,2,3] >>>toast [1,2,3] >>>spam[1]=5 >>>spam [1,5,3] >>>toast [1,2,3] Remember this, because it is a very important concept. It can save you lots of headaches in the more advance sections. Built-in Functions This section will tackle the different list functions built into Python.

.append() – This adds an item to the end of the list. >>>spam=[1,2,3] >>>spam.append(5) >>>spam [1,2,3,5] .clear() – This removes all of the items from the list .count() – This returns the number of times that a given item appears in the list. >>>spam=[1,2,3,5,5,1,5,4] >>>spam.count(5) 3 >>>spam.count[1] 2 .index() – This will find the index of any given item within the list. There are two optional parameters for the start and end of the index. >>>spam=[1,2,3,5,5,1,5,4] >>>spam.index(5) 3 >>>spam.index(1) 0 >>>spam.index(5,1) 4 >>>spam.index(1,2) 5 .extend() – This appends a list at the end of the list. >>>eggs=[1,2,3]

>>>eggs.extend=[1,2,9] >>>eggs [1,2,3,1,2,9] .insert() – This inserts an item into a certain index position. Again, remember that Python’s indexing begins at zero. >>>bacon=[1,2,3,4,5] >>>bacon.insert(2,”jam”) >>>bacon [1,2,’jam’,3,4,5] .pop() – This will return the content of a specific index, after which it is deleted. >>>spam=[1,2,3,4,5] >>>eggs=spam.pop(2) >>>eggs 3 >>>spam [1,2,4,5] .remove() – Just like .pop(), except that it does not return the item before deleting it. This makes this function slightly faster than .pop(). >>>jam=[1,2,3,4,5] >>>jam.remove(2) >>>jam [1,2,4,5] .reverse() – This will reverse the list’s order. >>>juice=[1,2,3] >>>juice.reverse() >>>juice

[3,2,1] Lists are very useful assets, and they offer a lot of flexibility. However, remember that there are other alternatives—such as tuples, which are four to seven times faster and are a lot more static than lists). Because of lists’ inherent characteristics, very long lists can usually incur a penalty in the program’s performance. This is why most lists are best kept short. In Python’s rule of thumb, lists are best used by those who wish to dynamically hold values and information.

CHAPTER 10: Tuples Towards the end of the previous chapter, we learned that there is a Python data type that can be much faster than lists, though not quite as flexible. These are tuples, which are immutable sequences. In nature, lists and tuples are very similar—except that you will not be able to dynamically modify the tuple in the same way that you do lists. Once a tuple is created, it can no longer be modified or changed. The way that this affects how the tuple is stored in the memory will be an important idea later on. In order to create a tuple, the programmer will create a group of items that are separated by a comma (,). While Python adds parentheses around any item group, it will not be as important, since the result will still be a tuple. This is demonstrated below: >>>spam=1,2,3 >>>spam (1,2,3) >>>”Q”,”W”,”E”,”R” >>>(‘Q,’W’,’E’,’R’) Now, here is a little riddle: what if you only want one item to be stored in your tuple? This can simply be done by leaving an extra comma at the end. In fact, you can choose to leave an excess comma after any tuple, regardless of its size (even though this is not explicitly required for any tuple larger than one). This is one of those little quirks unique to the Python language. Note as well that you can make an empty tuple simply through an empty pair of parentheses. Indexing Tuples Just like lists and strings, tuples follow the standard indexing rules. Staring from the left, indexing begins counting from 0; from the end, it counts from -1. Extend slicing is also supported. You can review this from the previous chapter, since this can be quite tricky. Built-in Functions

Like in lists, there are also some built-in functions for tuples. There are only two of them, though, owing to the relative inflexibility of tuples. .count() – This returns the number of times that a specific item is found. It also works in the same way as .count() for lists. .index() – This locates the first index of the specified item. It also works like .index() for lists. Using Tuples Just like lists, tuples were made for a specific type of usage. They are perfect for holding data you want to be static, and that you don’t plan or changing or modifying. Just like what is said in the previous lesson, a tuple is up to seven times faster than lists. This means that for each item in a list that is manipulated, four to seven tuples could have been manipulated in the same time frame. This generates a huge advantage in speed, especially for scientific work. Though this sounds very good, remember that once a tuple is created it can no longer be changed. The best metaphor for this is that tuples are “read-only”. In order to change the content, tuples have to be changed into dynamic an mutable sequences. Only after manipulation are they converted back into tuples. For this same reason, those intending to add and remove items in sequences should not use tuples.

CHAPTER 11: IF Statement Earlier, we had mentioned in passing about the special place indentation has in the Python language. Unlike other languages such as Java and C++, Python uses the indent to determine a block of code. This pseudocode demonstrates this: This is a line of code. This is another line of code This code, on the other hand, is part of a code block. This is also a part of a code block. Unfortunately, this code is no longer part of a code block. But this code is the start of a new code block. As was seen from the pseudocode, there are multiple areas that form blocks of codes. You can even nest a block of code within another block, as long as it indents. There is technically no limit in indentation, but the programmer has to mind the indentation’s consistency, or else, an error will be generated. Consider this next batch of pseudocode: This is a line of code. This line is part of a code block, which is pretty far away. While not encouraged, this indentation is legal in Python. For consistency, indenting in multiples of four are preferred. This line is no longer a part of a code block, since it does not follow any indentation style. This would get you an error. While the programmer is allowed to use both white spaces and tabs, it is preferable to use white spaces. Be reminded that you will not be able to use both tabs and whitespaces at the same time, or an error may appear. One should know that since the Python interpreter is used in demonstrating the example code, an ellipsis (…) is virtually same as three greater-than signs (>>>). The only difference is that an ellipsis means you are in a code block. The following demonstrates this:

>>>if True: … Print(“Hi there!”) … Hi there! Some programmers may be more comfortable in using curly braces ({}) to determine code blocks and statements, especially those who are just starting Python after learning a different languages. These brackets (also called braces) are some of the most debated-on signs in Python. As of this writing, the core Python developers are continuing to reject the use of braces due to the Python Philosophy. In fact, if you try to opening up the Python interpreter and typing “from_future_import braces”, you will get a little easter egg that will sum up the collective attitude of Python’s core developers (towards braces, at least) —SyntaxError not a chance. Now that this has been gotten out of the way, we can get into the nitty-gritty of the lesson. The If Statement and Code Flow In a majority of programming languages, there are special ways of controlling the code “flow”. Such a control allows specific parts of the code to execute only when the conditions are right. Among the different codes used towards this end, the most commonly used is the if statement. This is meant to first compute whether a statement is true or false —if the statement is true, the code is executed; if it is false, the code is not. Remember that the True and False expressions are Booleans in the Python language. This means that the if statement (as well as other conditional statements) will be using Boolean math in order to compute the evaluation. One should also note the proper way a conditional statement is written—a colon (:) at the end is necessary at the end of “control flow” statements. Here is an example: >>>if 1==1: … Print(“This is gonna print!) … This is gonna print!

>>>if 1==2: … Print(“This won’t ever print.”) … You can also use what was previously discussed about Booleans (and, or, not) in order to mix different conditions together. >>>if 1==1 and 3 ==3: … Print(“True”) … True >>>if 1==2 or 3==3: … Print(“True”) … >>>if 1==2 or 3==4 … Print(“True”) … >>>if not False: … Print(“True”) … True As was previously mentioned, you can nest statements within statements so long as the respective indentations are followed. >>>if 50==50: … Print(“50 equals 50”) … If True: … Print(“True is True”) … 50 equals 50 True is True

While statements can always be nested within each other, it can quickly become hard to manage. It would have been more Pythonic if the statements are kept flat. This would mean that instead of nesting different if statements together, it would be better to use a single if statement with different and operators. >>>if 2==2: … If 4==4: … If 6==6: … Print(“2,4, and 6 are equal) … 2,4, and 6 are equal >>>if 2==2 and 4==4 and 6==6: … Print(2,4, and 6 are equal) … 2,4, and 6 are equal If you found the line being printed to be queer, remember the basic rules in school logic— operators do not care about the final line being true or not in the real-world, so long as the prerequisite conditions are met. Backslashes, Semi-colons, and Parentheses Most likely, you will want to keep several different lines of code in just a single line. This can be done using the semi-colon (;). This acts like a new line, except that the programmer will not see it in this way. Take, for example, the following lines of code: >>>if 1 !=3: … a=1 … b=2 … c=3 … The same code may be condensed into a single line, just like shown here:

>>>if 1 !=3: a=1;b=2;c=3 … The good thing about semi-colons is that they do not need to indent. This takes away the need to carefully count the number of times you have indented. While this is a great thing, remember that semi-colons should not be used excessively. This is just to make sure that you are not writing a large chunk of code all just on one line as that would be more confusing to manage. Take a look at this bad example: >>if 1 !=3 a=1;b=2;c=3;d=4;e=5;f=6;g=7;h=8;i=9;j=10; … Now, let’s tackle another dilemma. Let’s say that you would need to compare six different numbers using an if statement. This statement would become quite long, and nesting them in different statements would make things worse. This can be solved by using a backslash (\). This allows you to break up a long line of code into different parts. >>>if 2==2 and 4==4 and 6==6 and 8==8 and \ … 10==10 and 12==12 and 14==14 … Print(“True”) … True Just like in the case of the semi-colon, the programmer will not need to worry about indentations when dealing with the backslash. This will allow you to keep the code in level with the if statement. However, remember that any character appearing directly after the backslash will cause an error to appear. This extends all the way out to excess whitespaces that may have been mistakenly typed. Remember to be extra-careful when dealing with backslashes. Then again, there is an even more workable solution—using parentheses to include all of the pertinent code. This works just like the backslash, however it allows for extra characters (including whitespaces) appearing at the end. >>>if (2==2 and 4==4 and 6==6 and 8==8 and … 10==10 and 12==12) … Print(“True”)

… True Note that for some Pythoneers, it is considered “unpythonic” to use parentheses instead of backslashes. This is, however, not 100% accurate all the time. The Else Statement There would be a lot of times when you wish to execute a different line of code in case the if statement is not true. This would call in the use of the else statement. The statement accompanying this will be executed when the preceding statement is false. To work, it needs to be on the same level of indentation as the if statement. Here is an example: >>>if 3==3: … Print(“3 equals 3” … Else: … Print(“3 is not equal to 3”) … 3 equals 3 >>>if 3=33: … Print(“3 equals 33”) …else: … Print(“3 is not equal to 33”) … 3 is not equal to 33 While both if and else have to be aligned to each other to work, the indentations of their code blocks can be different as demonstrated by the following example: >>>if 2==2: … Print(“2 equals 2”) …else: … Print(“2 is not equal to 2”)

… 2 equals 2 While there is no requirement for it, it is again recommended that you indent in multiples of four. The Elif Statement As you might have noticed by now, the Python language often provides shortcuts (or at least some kind of reprieve) in case one has to do tedious tasks. For example, the programmer wants to have four if statements together—but you only need one of these to execute. The programmer can always try to write all those four statements, but then again it would be a lot easier to just write one big chunk directly using the elif statement. The term elif stands for “else if”, that acts like both the else and if statements. This would mean that if the first if is not true, the elif will kick in to see if it is true. This can be avery handy feature later on. Check out the following blocks of code: >>>if fraction == 1: … Print(“The fraction is a whole”) …Elif fraction == 3/4: … Print(“The fraction is 3/4”) …elif fraction == 2/4: … Print (:The fraction is a half”) …elif fraction == == 1/4: … Print(“The fraction is 1/4”) …else: … Print(“The fraction is none of the above”) …

CHAPTER 12: While Statement While the if statement we learned in the previous lesson can be applied for different purposes, it does not do quite as well a job at being recursive. This means that this statement is not made to loop multiple times. At this point, the while statement comes into play. This statement will work for as long as it needs to, until the conditions are proven false. This is useful in case something has to be repeated multiple times for a specific amount of time. Below is an example that demonstrates this: >>>spam= 0 >> >while spam !=5: … Spam +=1 … Print (spam) … 1 2 3 4 5 >>>bacon=[2,4,5,6,8] >>>while bacon: … Print(bacon [0]) … Del bacon[0] … 2 4 6 8 >>>while False: … Print(“This will not print”) … >>> juice=10 >>>while juice:

… juice-=1 … print(juice) … 9 8 7 6 5 4 3 2 1 0 The condition of the while statement will always be true or false, just like the if statement. This will mean that Booleans can also be used to force the looping. In the same vein, while False: will not execute—in the opposite end, while True: will loop infinitely. This will be important in more advanced lessons. The Else Statement In Python, unlike in many other languages, the else statement can be legally used in conjunction with the while statement. When the while finishes the loop naturally, the else statement will kick in. If the while statement is prematurely stopped, then the else statement will not execute. Below is an example: >>>jam=0 >>>while jam !=10: … jam+=1 … Print(jam) …else: … Print(“Finished printing jam”) … 1

2 3 4 5 6 7 8 9 10 Finished printing jam >>>while True: … Pass …else: … Print(“This will not be seen on the screen”) … Traceback (most recent call last): File “”, line 2, in KeyboardInterrupt In the second batch of code, the KeyboardInterrupt was generated by a ctrl+c, Like mentioned earlier, the while statement was prematurely stopped and hence the else was not executed. The Break Statement Sometimes, the programmer may wish to intentionally end a while statement prematurely. This is done through the break statement. This statement is nested in the while statement that it will end. This means that only one while statement will be ended, and not all of them. Below is an example: >>>spam=0 >>>while True: … Print(spam) … Spam +=1

… If spam ==10: … Break … 0 1 2 3 4 5 6 7 8 9 This example shows how a while loop is ended, even while it is true. You will also notice that the break statement we demonstrated did not need a colon. This means a new indentation is not needed. Placing the colon will cause an error—meaning this omission is mandatory. Continue Statement Just as the break statement can be useful, so can the continue statement. Unlike the previous statement, continue will stop the current code execution and proceed to the beginning of the while statement. This is used to skip a part of your code without ending the loop. This statement is used just like the break statement. Here is an example: >>>eggs=0 >>>while eggs!=10: … eggs+=1 … If eggs >>for bacon (“A”, “B”, “C”, “D”, “…”): … Print(bacon) … A B C D … As can be seen here, the temporary variable which has the item from a collection or sequence follows the for statement. In this instance, bacon is our temporary variable. After this, the in statement is needed, preceding the collection or sequence. The way that the for statement is used in C-based languages and Python can differ significantly. Since the version used by Python is iterator-based, it comes as a question how the programmer would have a temporary variable hold a specific number which increments on each loop. One solution would have been to make a large tuple to hold every number, but this would unnecessarily take up both time and memory. The built-in range() function is a good tool that can help us in this little puzzle. The range() function can create an iterator list of the numbers, without the need to waste both keystrokes and memory. This is an example of the range() usage: >>>for juice in range (10):

… Print(juice) … 0 1 2 3 4 5 6 7 8 9 >>> for jam in range (2,10): … Print(jam) … 2 3 4 5 6 7 8 9 All things considered, the range() function can be quite complicated. This is why the above example show it in its two most basic forms. When only a single parameter is used, then the new range starts from 0 and ends at the parameter. In the case of range(10), the range is computed from 0 to 9. The next example makes use of two parameters. The first one signifies the start of the range, instead of the previous default (0). Like before, the second parameter is where the numbers should stop. In the example, the range(2,10) counts from 2 to 9. While the range() function begets an iterator list, it is not by itself an iterator. The function

is in reality called a “generator”. This is any object that can create a group of iterators when needed. Since it is the generator that works, the iterators are temporary—they are not meant to stay forever in the computer. The Else Statement Just like the while statement, the else statement of the for is executed when the loop does not prematurely end (for any reason). Any special keyboard keys, errors, and other statements (among others) would render the statement inert. Here is a short example: >>>for eggs in (1,2,3,4,5,6): … Print(egg%2) … else: … Print(“This for loop is successful”) … 1 0 1 0 1 0 This for loop is successful The Break Statement This statement works for the for statement in much the same way that it works for the while statement. It completely ends the loop in a premature manner, which can be useful in some cases. Here is another demonstration: >>>for jam in (1,2,3,4,5,6,7,8,9): … Print(jam%4) … If jam %5 ==0: … Break … Else:

… Print(“This loop did not end prematurely”) … 1 2 3 0 The Continue Statement This statement works in just the same way that it does when in the while statement. It is meant to stop the code’s execution, bringing everything back to the beginning of the loop. Here is another example: >>>for spam in (1,2,3,4,5,6,7,8,9): … if spam%2 == 0: … Continue … Print (spam%2) … 1 1 1 1 1 Just as mentioned in the previous chapter, the continue statement is also used as a means to increase the code’s readability and to reduce unwieldy amounts of indentation.

CHAPTER 14: Try Statement In the perfect programming world, nothing would go wrong. Unfortunately, even the best programmers make mistakes—that’s why debugging and troubleshooting has become a core part of the development process. Aside from manual mistakes, computers may go wonky—crashing, resetting, and shorting out in perfect manifestation of Murphy’s Law. In the even something goes south, the computer will have to act in a flash and recognize that something is going on. At this stage, the computer should also stop and try to fix the problem when it could. Any well-coded software should have at least the basic safeguards in place for such events. In programming, an error is produced when the computer has detected something is off. Take, for example, when you are burning a CD. When you pull out the CD without waiting for it to complete, then the CD will be unavailable to the software you are using. If the software is not equipped to handle this kind of behavior then the computer will throw an “undefined” message. Or, the program could just hang as it tries to burn something onto a non-existent media. These types of behavior aren’t too useful for the user, so one should create a way to handle them. Fortunately, in Python, the programmer can write codes that handle exceptions and errors. This is in contrast to many other programming languages. Errors—Python vs C As you might have noticed when you mistype things in the Python interpreter, the language’s errors are very “loud”. This means that when something is not right, Python will ensure that you know about it in the surest way. Others may balk at having every single mistype scrutinized by an unforgiving system, but as you go on this actually becomes a necessity. Let’s take a step back and look at one of Python’s forebears, the C language. It did not have the built-in error handling that Python now has. Sometimes, the errors just slip by unnoticed by anyone. This is actually good, since that means the error is “tolerable”. However, there are some times when the error causes the computer to crash outright— these are dangerous in many aspects. Because the language does not allow for error handling, the programmer will have to create their own. This still does not make it easy to catch all the errors in their tracks. This is why Python was built with such a sharp eye for errors. Once the language fulfills its goal of notifying you, you have the buck and the control of what else to do from

thereon. If you do not make any specific call for Python, a default message is then displayed which is follows by the program’s termination. Loud Errors Now that we understand the Python errors in a better light, it is clear that handling these errors become just as important as displaying them. Let’s say that you create a large program, which crashes each time you use it. Finding and fixing the issue will become very important. Python’s loud errors will let you know not just what the error is, but what caused it too. This allows for faster development due to the faster fixing of errors. The Try and Except Statement As far as error-handling goes, we can use the try and except statements. Their usage is shown in the following (minimal) example: >>>try: … Print(eggs) … Except: … Print(“eggs has not been defined”) … Eggs has not been defined As you noticed, id a piece of code that has the try statement causes an error, then the code execution will stop. From there, it will jump to the except statement. The code in the except will then be executed, and a different error will appear when the except statement causes another conflict: During handling of the above exception, another exception occured. This is why it is important to mind the except, since you would not want to put another error-causing code there. You might also have found from prior experience, that the third line of the error message will be the one that specified what kind of error happened. In the earlier example, a NameError has occurred. This is the type of issue that erupts when the name of a variable

cannot be found. This is commonly because the variable does not exist in the first place. Since the errors can be quite specific, there has to be a set of different exception names— and there really are! The language has at least 20 well-defined and built-in exceptions to address each kind of known problem. So what will happen if the programmer tries to catch the NameError (or any other specific error for that matter)? In order to do this, one would have the specific error after the except statement as demonstrated in the following example: >>>try: … Print(jam) … Except NameError: … Print(“Jam is not defined”) … Except: … Print(“An unidentified error appeared”) … Jam is not defined As we can see, the except statement acts by itself as the default error handler. It can handle any error that has not been captured by another except statement. This will mean that you can use a multitude of except statements used to catch errors. The Else Statement Again, we can use the else statement in this regard. Just like how it works with the for and while statements, it will execute when the try statement terminates without any premature endings or errors. The statement should also come after the set of except statements, such as demonstrated in the example below: >>>try: … Eggs=6 … Print(“I have %d baskets of eggs” %eggs) … Except: … Print(“An error has occurred”) … Else:

… Print(“Everything is fine”) … I have 6 baskets of eggs Everything is fine The Finally Statement This statement is technically similar to the previously-tackled else statement, except that the finally will always execute when the try statement has failed or when it has prematurely failed. This statement should go after the else statement, such as is shown below: >>>try: … Print(“spam”) … Except: … Print(“There is an error”) … Else: … Print(“Everything is fine”) … Finally: … Print(“Wrapping up”) … Spam Everything is fine Wrapping up >>>try: … Print(“juice”) … Except: … Print(“There is an error”) … Finally: … Print(“Wrapping up”) … Juice Wrapping up



CHAPTER 15: With Statement Just like the try statement, the with statement is meant for error handling. This statement is used to automatically clean up objects. This is helpful in reducing the amount of code that one has to write. It also allows for the omission of the finally statement as well as the manually written cleanup of the object. In using the with statement, one will need to point to the object that one wishes to use. This is followed by the as statement, which will end with the object’s variable name. The code below is an example that uses this statement, assuming that “Hello world!” is a line that appears in the file “hello.txt|”. With open (“hello.txt”, “r”) as file: Print(file.read()) Hello world! Here is another example that uses the except, try, and finally statements. Once more, it assumes that the sentence “Hello world!” appears in the “hello.txt” file. try; File=open(“hello,txt”, “r”) Print(file.read()) except IOError: Print(“An I/O error just occurred”) except: Print(“An unknown error just occurred”) finally: file.close() Hello world! However, if there is an error while the file is still open, in this case it will not close. In other circumstances, one would have to write using a try…finally block to make sure that there is a proper object cleanup. However, this would need quite a lot of additional work while sacrificing readability at the same time.



CHAPTER 16: Other Statements This chapter is meant to cover some of the other statements in Python that haven’t been covered in complete detail yet. Assert Statement This statement is used mostly for debugging. It works by checking a specific condition—if the condition fails, then the statement will prompt an error. This is used to test a set of conditions before there is an actual execution of the program. This may be used, for example, to make sure that a specific variable spam is not zero in number. Below is a demonstration: >>>try: … Spam=0 … Assert spam ==0 … Spam=0/spam … Except: … Print(“spam may be zero” … Else: … Print(“spam is not zero”) … spam may be zero In Statement This might be familiar, as we last saw in when we worked with for statements. While the in statement was used exclusively in conjunction with for in that lesson, it can also be used as a standalone statement. Its primary purpose is to check if something can be found in a particular sequence. The statement then returns a Boolean value to verify (or deny) the existence of the item. Here is an example of the in statement in action:

>>>”and” in (“or”, “nor”, “in”, “at”, “and”, “;”) True >>>”apple” in “(“orange”, “pomelo”, “watermelon”, “kiwi”, “dragon fruit”) False While the in statement can be used on iterators, we can also use it on plain strings since they are also sequences. When using it on strings, the statement will check if the specified item is a substring of the specified string. This will mean that you can check if something is found in something else (e.g., a word within a word). Here is an example: >>>”x” in “exasperate” True >>>”juice” in “jam” False Also, do not forget that using the in statement is one of the fastest ways of comparing two variables. Is Statement This statement is primarily used to check if the two specified variables are unique. This would mean that bot the variables are not the same, or that they do not point to the same set of values. Unlike the “==” notation used for comparing equality, the is statement is used for comparing identity. Below is a demonstration: >>>spam=”bread” >>>eggs=”butter” >>>spam is eggs False In this example, the programmer created two variables—spam and eggs. They have been assigned to different strings. Because these are not the same strings, their variables are likewise different. Now, let us try creating two variables with the exact same text in the strings:

>>>spam=”coffee” >>>eggs=”coffee” >>>spam is eggs False Why false? It’s because the two are still not the same. Although both of them have the same text in the strings, each of the strings are uniquely created and placed in the computer’s memory. The only way to create two exact same valuables will be to have one of them point to the other. Thus: >>>spam = “Hi” >>>eggs=spam >>>spam is eggs True Pass Statement This statement is used primarily as syntactic sugar, while also serving as a “nop”—an instruction that does nothing (contraction of no-op). Plainly put, the pass statement does nothing. This does not mean it is useless, however, as it serves to leave a code block empty: >>>if True … Pass … >>>for spam in range(15): … Pass …

CHAPTER 17: Functions In the Python language, a function is a way to reuse a code block so that it is usable more than once. These functions can give the programmer the ability to minimize the redundancy of his code. It can also help steer away from wasting several hours at unnecessary work. Functions let codes have a centralized structure, where a single change in the function will affect all the other parts that depend upon it. They can also be used to split up tasks that would otherwise be very strenuous to accomplish. Creating functions In order to create a function, it should be defined with the def keyword. This is then followed by the name of the function, along with a blank pair of parentheses. As before, this is punctuated by a colon. A function can be part of a code block, so you will have to indent codes that are within the function. If you fail to follow indentation, you will get an “IndentationError”. Here is an example: Def hi(): Print(“Hello there!”) This code serves to assign and then create the “hi” function. It would act just like the x=1 command — in both instances, a new variable is created (hi and x). Now that a function is created, you might be waiting for something to change—but nothing will happen yet. In order to call or invoke the function, the programmer will need to use the name of the function followed by the parentheses. This is demonstrated in the following lines of code: Def hi(): Print(“Hello there!”) Hello()

This should produce the following output: Hello there! Adding another instance of the command will result in the output coming out twice. This is just a small part of the usefulness of the function. Parameters of Functions Perhaps you might be wondering what is the use of the blank parentheses when calling out functions. True, typing “hello” would be two keystrokes (three, if you count Shift) shorter than “hello()”. However, these parentheses serve as the “conduit” for passing arguments to the function. This will allow the programmer to create a function that can do things that are passed onto their arguments. First off, the argument has to be declared when the function is initially defined. And then, this is called with an argument. Def spam(x): Print(x**2) Spam(2) Spam(3) Spam(4) The output of these lines should be: 4 9 16 The variable x acts within the spam function. You should notice that x will only exist if it is within the function. Let’s take a look at these lines of code: Def eggs(x): Print(x**2)

Eggs(2) Eggs(3) Eggs(4) Print(x) This will return a NameError since the variable x cannot exist by itself, outside the square. Functions are able to take up multiple arguments, separated by commas. This is demonstrated below: Def juice(x,y): Print((x**2)+y) Juice(2,3) Juice(3,2) Notice that this may be a great tool for those studying algebra (or related subjects). The result should be: 7 11 Default Parameters Parameters are great, but they can also get repetitive. Instead of this, the programmer can define default values for parameters. This is done by setting the values when the parameter is first defined. Here is an example script for this: Def bacon(x=0): Print(x) bacon(1) bacon() bacon(23)

This should produce the following output: 1 0 23 Notice that when we called bacon the second time, there was no argument given — and yet, there was a 0 that printed out. This is a default that is assigned automatically in such cases when no arguments are given. Returning Values If a programmer wishes to use the value that the previous spam (or eggs) function, then he could rewrite it so that it makes use of the return command. >>>def spam(x): … Return x**2 … This can be used to do some fun things. Check out the following: >>>print(square(3)) 9 >>>print(square(square(3))) 81 >>>10+square(2) 14 >>>y=square(10) >>>y 100

CHAPTER 18: Classes Object Oriented Programming Object oriented programming (OOP) is an approach to programming where the objects are defines using methods (actions, functions, or events) and properties (characteristics, values). This results in a more readable and more reusable code. Take for example, a scenario where you have to write a program in order to keep track of a group of motorcycles. Each of these vehicles have different characteristics, such as color, mileage, etc. However, all of these perform the same basic actions such as accelerating, braking, and swerving in and out of traffic. So instead of writing a piece of code separately for each of these motorcycles, one can simply create a class for it—this can serve as the “blueprint” for each of the objects. Constructing Classes A “class” is basically anything that can be said to be the generic description of the object in question. In the Python programming language, a class method (an event, function, or action) is defined. This is done using the following structure: Class : Def (self [, ]): Let us discuss this in detail. First, the object is defines using the keyword ‘class’, the name that we want, and the colon as a punctuation. The methods are defined as in a normal function—a single indent with ‘self’ as the first argument. So the following can serve as the example class for our motorcycles: Class Motorcycle: Def brakes(self): Print“Braking” Def accelerates (self): Print “Accelerating”

Note that the first name of the classes should have a capitalized first name. This is quite a common convention, though it is not a technical requirement from the language. Also, the example is a type of “encapsulation”, where the instructions for processing are defined as a part of a different structure for reuse in the future. How is this used? Once the class is created, then one will have to program an object for each of the class’s instances. In the Python language, programmers create new variables for each of these instances. Here is an example: Motorcycle1= Motorcycle() # This is the instance for the motorcycle Motorcycle2 = Motorcycle() #Now, the object method is used like Motorcycle1.brakes() By using the parentheses (also called “calling in” the class), you can tell Python that you wish to create not just a copy of the class definition but an instance. You would have to create a different variable for each motorcycle. However, each of these objects can now take advantage of the different attributes and class methods, so you would not have to write a different accelerate and brake function for each of these vehicles. Properties As of now, all of the motorcycles in the previous sample code look the same. Since that is unacceptable, let us try to give them some properties to make them unique. In Python programming, a property is simple a variable specifically paired to a given object. In order to assign a property, it is written as: Motorcycle1.color=”Blue” Then, this value is retrieved as: Print motorcycle1.color

For purposes of convention, the functions are written to get (retrieve) and set (assign) properties not set to be “read-only”. Here is an example: Class motorcycle: …previous methods… Def set_owner(self,Owner_Name): #This part sets the “owner“ property. Self._owner=Owner_Name Def get_owner(self): # This part will retrieve the same property. Return self._owner You might have noticed the underscore that is before the name of the property. This is a way to hide the name of the variable from users. Starting from Python 2.2, the programmer can also define the example we provided above so that it looks like any normal variable: Class motorcycle: …previous methods… Owner=property(get_owner, set_owner) Then, when you call in a way like mymotorcycle.owner=”John Doe”, the function set_owner is called transparently instead. Class Extension In the event that a programmer will need to place additional functions to the class but is reluctant to change the code (perhaps fearing that this can mess up programs depending on the current version), he can “extend” the class as a solution. When this is done, all the parent methods and properties are inherited while new ones can be added. As an example, one can add a start_motorcycle method to the class. In order to extend classes, the programmer will have to supply the parent’s class name in parentheses right after the new class name. This is shown below:

class new_motorcycle(motorcycle): Def start_motorcycle(self): Self.on=True The new class will extend the parent class. Note that when attributes and methods are passed down in hierarchies to new classes, the process is referred to in Python as “inheritance”. Special Class Methods In the Python language, the special methods’ names begin with double underscores (“__”) and end with the same. For example, a special method __init__ has been used to initialize newly created object states. As an example, the programmer can create not just a new motorcycle model but also set its brand, year, model, and other attributes on a single line. This is opposed to expending additional lines for each of the attributes. Here is a demonstration: Class new_motorcycle(motorcycle): Def __init__ (self,model,brand,year): # This sets all the properties Self.brand=model Self.model=brand Self.year=year Def start_motorcycle(self): “””Start the motorcycle engine””” Print “broooom broooom!” If __name__ == “__main__”: # This creates two separate instances of new_motorcycle, each of which has unique properties Motorcycle1 = new_motorcycle(“Diavel”,”Ducati”,”2016”)

Motorcycle1.start_motorcycle()

CHAPTER 19: Modules In real life, we want all our files to be organized for easy storing and retrieval. Naturally, this instinct would extend to our programming needs. This is primarily why Python implemented modules. A module allows the programmer to organize and logically arrange the code he has typed in. By grouping all related code into a module, one can better read, understand, debug, and use them. Modules in the Python language are objects that have arbitrarily named attributes, which can all be bound and referenced. Put another way, modules are files that consist of Python code. They can define classes, functions, and variables. They can also include codes which can be executed. Below is an example of a module. The code for the module with the name “spam” would normally be in a file named “spam.py”. The example is that of a simple module: Def print_func( par ): Print “Hi:”, par Return Import Statement Any Python source file can be used as a module through the execution of an import statement in another source file. An import statement has the syntax: Import module1[,module2[,…moduleN]] When the Python interpreter encounters import statements, it will import the module in case the module is found in the search path. The search path is a directory list, searched by the interpreter before the module is imported. Let’s say, for example, that you would need to import the module spam.py, the following command would have to be placed atop the script: #!/use/bin./python

Import support Support.print_func(“Python”) Once executed, the following result is shown: Hi : Python Modules have to be loaded only once, despite the number of times that it is imported. This will prevent the execution of the module from occurring repeatedly, in case multiple imports are called. From…import Statement The Python language’s from statement allows a user to import certain attributes from modules and into the present namespace. The statement has the syntax: From modname import name1[,name2[,…nameN]] Let’s say that we need to import the eggs function from the bacon module, then the following statement should be written: From bacon import eggs This statement will not import the whole module bacon to your current namespace — instead, it adds the item eggs to the importing module’s global symbol table. Fromm…import * Statement It will also be possible to import all of the names from the module to your current namespace through this import statement: From modname import *

This will provide an easier way of importing all the items from the specified module into your current namespace. However, make sure not to overuse this statement. Locating Modules In the process of importing modules, the interpreter searches for it in the following order: Your current directory When the module cannot be found, Python tries to look for it within a shell variable— PYTHONPATH When this still fails, the language tries to check the default path. In UNIX systems, this is almost universally /usr/local/lib/python/. The module’s search path is located in the sys system module as the variable sys.path. It contains the present directory, PYTHONPATH, as well as the default (which depends on the installation). PYTHONPATH Variable This is an environment variable, which consists of a list of directories. The PYTHONPATH’s syntax is similar to PATH, a shell variable. Here is an example of a Windows PYTHONPATH: Set PYTHONPATH=c:\pythin20\lib; As well, here is an example of the usual PYTHONPATH from UNIX and UNIX-like systems: Set PYTHONPATH=/usr/local/lib/python Scoping and Namespaces The variables are identifiers (names) that are mapped to objects. Namespaces are dictionaries of names that are variables (keys) as well as their values (corresponding variables).

Python statements are able to access variables in local namepsaces as well as in global namespaces. If local and global variables are equipped with the same name, the local one will shadow the global variable. Every function is given its very own local namespace. The class methods also follow the same rule for scoping just as any ordinary function. The Python language can make educated guesses depending on whether specific variables are global or local. This is done by assuming that variables assigned values in functions are local. Therefore, if you need to assign values to global variables within functions, the global statement will have to be used. Using the statement global VarName should tell Python that VarName is to be considered as a global variable. Then Python stops searching for the variable in local namespaces. As an example, the variable spam is defined within the global namespace. Within the spam function, spam is assigned a value, therefore having Python assume that it is a local variable. However, the programmer accessed the local variable spam’s value before setting it, so a result will appear instead: UnboundLocalError. To fix this, the programmer will have to uncomment the global statement: #!/usr/bin/python Spam=3000 Def AddSpam(): #To fix the code, uncomment the following line: *global Spam Spam = Spam+1 Print Spam AddSpam() Print Spam Dir() Function The dir() function is a built-in one that will return a list of sorted strings, which in turn contain the names defined by a specific module.

The list will contain the names of all the modules, functions, and variables that are defined therein. Here is a simple example we can follow: #!/usr/bin/python #Use the built-in module math for import Import math Content=dir(math) Print content When the code above is executed, it produces a long list as a result. The special string __name__ in the results is the name of the odule, while the __file__ on the result is the filename from which this module has been loaded. Locals() and Globals() Functions These functions can be used by the programmer to return names in local and global namespaces. This depends on the location from which they had been called. If locals() has been called from within a function, it will then return all names that can be locally accessed from this function. On the other hand, if globals() is called from this same function, then it will return the names that can be globally accessed from that function. Reload() Function When a module is imported in a script, the top-level portion code of the module will be executed just once. Therefore, if the programmer wishes to repeat the execution of the toplevel code, the reload() function may be used. What the function does is to import again a module that has already been previously imported. The reload() function’s syntax is as follows: Reload(module_name)

In this syntax, the module_name part is the name of the one that you wish to reload—not the string which contains the module name. For example, in order to reload a module named spam, then simply type reload(spam). Python Packages A Python package is a file directory (hierarchial) which defines one Python application environment consisting of modules, their subpackages, sub-subpackages, and so forth. For example, consider a file entitles Bacon.py found in the directory Eggs. This line of code appears in the file: #!/usr/bin/python Def Bacon(): Print “Bacon and Eggs” In a similar manner, there are two other files which have different functions but with the same name as that given: ● Eggs/Spam.py, which has the function Spam() ● Eggs/Juoce.py, which has the function Juice() Then, let us put a new file named __init__.py inside the Eggs directory — Eggs/__init__.py In order to make all of the functions available once Eggs is imported, then one needs to put the explicit import statements within __init__.py as shown here: From Bacon import Bacon From Spam import Spam From Juice import Juice

After these lines are added to __init__.py, the programmer will have all these classes available when the Eggs package is imported: #!/usr/bin/python #Now, the Eggs package is imported Import Eggs Eggs.Bacon() Eggs.Spam() Eggs.Juice Once the code is executed, then the following is produced as a result: Bacon and Eggs Spam and Eggs Juice and Eggs In this example, we have taken just a single function in each of the files. However, you can always keep multiple functions in the files. Different Python classes can also be defines in these files, then packages can be created out of these classes.

CHAPTER 20: Python Idioms Idioms are not just for the regular language—programming languages have idioms, too. A great example is our Python, which is by nature a strongly idiomatic language. A programming idiom is basically a means of expression of a recurring construct, something that is not already a built-in feature of that language. In order to be “fluent” in “speaking” any chosen programming language, one has to understand the idioms associated with it. This allows the programmer to properly produce codes—“speaking” the language. Because of Python’s philosophy about having a single optimal way to do things, it relies strongly on its idioms for structure. Basic Principles ● Aside from conflicting programming language philosophies, here are a couple of conflicting acronyms: EAFP and LBYL. EAFP stands for [It’s] Easier to Ask Forgiveness than Permission, while the latter means Look Before You Leap. While LBYL may be more useful in real life, it is EAFP that is honored in Python. Specifically, it spears to the programmer to use exceptions for checking errors. Any action that may fail has to be put inside a try…except block. ● For managing resources such as files, use context managers (to be discussed in detail in a later chapter). For ad hoc cleanup, use the finally statement. However, it is preferred to write your context manager to encapsulate it. ● Do not use getter-setter pairs; instead, use properties. ● For dynamic records, it is better to use dictionaries. For static, records, classes are preferred. For even simple classes, collections.namedtuple from the Python library can be a good help. If records have the same field all the time, this is best made explicit in a class. If the presence of the fields may vary, a dictionary is in order. ● For throwaway variables, use the underscore. This can be in instances like discarding return values when tuples are returned, or when indicating that a specific parameter is being igored. You may use *_, **_ in order to discard the keyword or positional arguments being passed to a function. These symbols correspond to the common *args, **kwargs parameters, though they are explicitly discarded. You may also use them on top of named or positional parameters (after the ones you use). This allows you to utilize some while discarding any excess. ● Except when you need to distinguish between “None”, 0, and [] or other falsy values, use implicit True/False. Falsy values like the one given should have an explicit check, such as ==0 or is None. And yes, that was “falsy” as opposed to “false”—falsy refers to a non-Boolean that has an assigned value of false. (In the same vein, nonBooleans with an assigned True value is called a “truthy”.)

● While else is completely optional, it is good practice to use it right after try, while, and for instead of ending things at if. Imports For a good code practice, import only modules and not names (such as classes or functions). Doing the latter gives birth to a new (name) binding, which may not always be in sync with already exsisting binding. For example, for a module m which exists to define a function f, having the function importing using from m import f would mean that m.f and f may differ if either of them is affixed to (creating a new binding). In actuality, this is often ignored especially for smaller-scale code. This is because modifying modules after importing them is relatively rare. Both functions and classes in such instances may be imported from modules in order for them to be referred to without using a prefix. For large-scale robust code, however, this could be an important convention as it can create bugs which can be very hard to find. With low typing, the programmer can utilize a renaming import in order to abbreviate a longer module name. Import this_module_has_a_very_long_name as n1 N1.f() #tthis is a lot easier than a very long name,, which just as robust Take note that using from in order to import subpackages or submodules from a specific package is completely acceptable. Here is an example: From O import sm # completely alright Sm.f() Operations ● In swapping values, simply use b,a=a,b ● In order to access attributes (particularly to call a method) for values that could be an object or possible None, use the following: a and a.x a and a.f() ● For substring checking, you can use in

Data Types You can use enumerate() for keeping track of the different iteration cycles over iterables: For i, x in enumerate(l): #… This is as opposed to the following technique, which is considered an anti-idiom: For i in range(len(l)): X=l[i] #… The second line goes from the list to the numbers and then back to the list, which is unpythonic. Finding the first matching element Python sequences have an index method, which returns the index of a specific value’s first occurrence in the sequence. In order to find this first occurrence which satisfies a condition, simply use next plus a generator expression. This is demonstrated in the following code: Try: X=next(a for a, n in enumerate(l) if n>0) Except StopIteration: Print(‘No positive number’) Else: Print(‘The firs positive number index is”,x) When the value is needed and not its index of occurrence, this can be directly obtained through the following technique:

Try: X=next (a for a in l if >0) Except StopIteration: Print(‘No positive number’) Else: Print(‘The first number is’,x) The reason the code is constructed this way is two-fold. First, the exceptions will let you signal a “no match found”, since they solve the problem of the semipredicate). Since a single value will be returned and not an index, this cannot be returned in the value. Also, generator expressions will let the programmer use an expression even without the need for a lambda (a function which is “anonymous” or not bound down to a name) or for the introduction of new grammar. Truncating In the case of mutable sequences, use the del function instead of reassigning it to a slice: Del l[j:] Del l[:i] The anti-idiom for this is as follows: L = l[:j] L = l[i:] The plain reason for this is that adding del makes your intention of truncating clear. Slicing will create another reference pointing towards the same list since lists are mutable. Unreachable data that is left over can be collected, though this is mostly done later. Instead of this, deleting modifies the lists in-place — a method that is faster than creating slices and then assigning them to existing variables. This also lets Python immediately single out the deleted elements for deallocation, instead of waiting for the garbage collection to do this later. Admittedly, though, there are some cases when you would want the same list in 2 slices. This is, however, rare in basic programming. It is also rare that one would want a slice of

the entire list, then using this slice to replace the original variable without changing the other slice. This improbability is demonstrated in the following code: M = l L = l[i:j] Instead of this, you can just try: m=l[i:j] Sorted list from iterables You may create sorted lists directly from iterables, without having to make a list first and then sort it. These also cover dictionaries and sets: x={l,’a’,…} y=sorted(x) z={‘a’:1,…} y=sorted(x) Tuples When going for constant sequences, always use tuples. While not a complete rule, it helps the code become more Pythonic by making the intention of the programmer clear. Strings When checking for substrings, use the in function. However, do not use the function to check for a single-character match. This will match substrings, returning spurious matches. Instead of this, use a tuple with valid values. Let’s take the following code as an example of what not to imitate: Def valid_sign(sign): Return sign in ‘+-’

This is wrong, since it will return True for the sign == ‘+-’. Instead of that, use a tuple as follows: Def valid_sign(sign): Return sign in (‘+’,’-’) Building Strings If you would need to build a long string in increments, first build a list and then join using ‘ ‘ or new lines if you are building in a text file. Do not forget to use a final new line in this case. This will be both clearer and faster that appending directly to a string, which is oftentimes slow. There are, however, a few optimizations in CPython that can help make simple appending to strings fast. Appending strings in CPython 2.5+ as well as appending bytestrings in CPython 3.0+ are all fast, but building Unicode strings (called unicode in Py2.X and string in Py3.X) ad joining them are even faster. Remember to be aware of this when you are expecting to manipulate a lot of strings — profile your code accordingly. Let’s take the following code as an example of what you shouldn’t do: X=’ ‘ For y in l: X+=y The above code would make a new string for each iteration, since strings are immutable. Instead of that, use the following code: #… #x.append(y) S=’ ‘.join(x) You may also use generator expressions, which may prove to be very efficient:

S = ‘ ‘.join(f(y) for y in l) You can also use StringIO for mutable string-like objects. Dictionaries You can use the following code to iterate over keys: For z in y: … For iterating over values in Python 3: For x in y.values(): … For iterating over values in Python 2 (note that dict.values() returns a copy in Py2.X): For x in y.itervalues(): … For iterating over keys and values in Python 3 For z,x in y.items(): … For iterating over values in Python 2 (note that dict.items() returns a copy in Py2.X): For z, x in y.iteritems() … On the other hand, anti-idioms would be:

● For z, _in y.items(): instead of for z in y: ● For _, x in y.items(): instead of for x in y.values()

CHAPTER 21: Performance Tips We have already mentioned quite a few times that Python is not the fastest of all the programming languages when it comes to the interpreter. But then again, what kind of software would it be if it cannot be modified for performance? In this chapter, we will be discussing the different tips you can use to optimize Python. Ever since about 1996, people have been writing about how to make Python faster. That means there is a large wealth of information that may or may not work for you. This chapter will give you a plethora of tips that will allow you to mix and match whatever suits your style and your system. Then again, nothing’s stopping you from implementing all of these. The Lowdown on Optimizing First off—the Python implementation. We had given you a lot of these at the start. When choosing any of these, make sure that you are choosing based on what you really like to use and on what your job demands—not simply because this book or anyone else told you that this implementation is faster than the rest. Once you have begun using the software and played around with it for a bit, you will be able to find what is making the program slow. Get the program to yield correct results, then run the results so you can check whether or not the correct program is slow. If you find the program to really be slow, then you can use profiling techniques to show you which parts of the program consume the most time. There are comprehensive by snappy suites available for you to use afterwards, which aid in making sure that any future optimization does not affect the correct way that the program runs. In a nutshell, you have to: 1. 2. 3. 4. 5.

Get the program right. Test that it’s really right. Profile if it is slow. Optimize. Repeat from step 2.

There are certain ways to optimize which amount to a better programming style—such as the idioms we had discussed earlier. Make sure that you learn these as you go along with

Python programming. Profiling the Code The first tangible step in trying to speed up your program is analyzing exactly where the bottlenecks may lie. It will hardly make sense to try and optimize a piece of code that will not be executed, or one that already runs at blazing speeds. There are two modules that can be used to help locate any code hotspots you might have—trace and profile. You can also use the timeit module, if you are using Python 2.3 and later. There are actually a number of modules included in Python that will allow for optimization and profiling. One of these can be used to profile a set of functions’ execution. Let’s say that your primary function is called test1, and that it takes no argument. You will then want it to execute under the profile module’s control. This will be the simplest way it is done: Import profile Profile,run(‘main()’) Once the main() is returned, the profile module would then print a table of the function calls with the execution times. This output may then be tweaked through the stats class also included in the module. From Python 2.4 onwards, profile is also allowed to profile the time being consumed by Python’s builtins as well as extension module functions. Hotshot and cProfile Modules The hotshot package has been available since Python 2.2, as a replacement for profile. In spite of this, the cProfile package has been the one more preferred. The module has been written in C, so using either could result in a smaller hit to the overall performance. This will allow you a better idea of how exactly the application is performing. In the Tools/scripts of the distribution, the hotshotdomain.py program can also be found. This will make it better for the programmer to run the code from the command line under hotshot control. Trace Module Being open-source, even Python modules have their spin-offs. One for the profile module we mentioned earlier is the trace module, which was originally written to help perform

test coverage. It has been since modified by the Python community, and can be found in the Tools/script directory in your Python distribution back in Python 2.0’s release. It has been added to the standard library (Lib directory) starting Python 2.3—it can be copied to the local bin directory, and the execute permission can be set from there. It will be easy to run this from the command line, tracing the execution of whole scripts: % trace.py -t eggs.py spam In the 2.4 release, it will be even easier to run—simply type python -m trace. You can also use pydoc trace in order to view the documentation of the trace module. Visualizing the Profiling Results You can use the following to visualize the results of your profiling attempts: RunSnakeRun. This is a GUI tool that will visualize the profile dumps from the cProfile module using square maps. The function and method calls can be sorted by different criteria, and the source code can also be displayed beside the visualization and the call statistics. Gprof2Dot. This is a tool based on Python which allows you to transform the profiling results into a graph. This graph can then be converted into SVG or PNG. PyCallGraph. This is a module which helps you create call graphs for your Python programs. It can generate a file in PNG, which shows the function calls of the modules as well as their links to other function calls. It can also show the amount of times the function is called, as well as the time the program spent within that function. PyProf2CallTree. This is a script that will help you visualize the profiling data you collected through the cProfile module. It uses the kcachegrind calltree analyzer. ProfileEye. This is a front end to Gprof2Dot. It is browser-based, and uses d3.js in order to declutter the visual information. Sorting Sorting the list of the basic Python objects is a pretty efficient process. This method for

lists uses a comparison function (optional) as the argument which is then used to change the behavior of the sorting. This is convenient, even though it can slow down the sorting process itself—as it runs, the comparison function has to be called a lot of times. Back in Python 2.4 and older, you will have to use the built-in sort’s key argument instead—this should have been the fastest way of sorting. If you are indeed using Python 2.4 or any older versions, then the following advice should be applicable—take heed as it comes from Guido van Rossum himself. To speed up the sorting process, create a list of tuples where a sort key is the first element. This key will properly sort through the default comparison. The second element should be the original list element. Also known as the DSU (DecorateSortUndecorate), it is further known to Pythonistas as the Schwartzian Transform. For example, you have are with a list of tuples that you would want to arrange by the nth field of the tuple. This function should look like: Def sortby(alist,n): Xlist=[(xn],x) for x in alist] xlist.sort() Return[val for (key,val) in xlist Another thing you can easily achieve as well is matching the preset list sort method’s behavior (also called sorting in place). Def sortby_inplace(alist,y): Alist[:]=[(x[n],x) for x in alist] Alist.sort() Alist[:]=[valfor(key,val) in alist] return Concatenating Strings This section will be effective based on the type of Python implementation you are running. Concatenation tends to be fairly fast for later versions, but then again you might be using the one which came when you first had your computer a few years back.

Remember that strings are immutable in Python. This is important to remember, since many Python novices overlook this, thus leading to code-fatal programming mistakes. The immutable state of strings can lend itself into both advantages and disadvantages. Among the former is the fact that strings can be used as dictionary keys, and multiple variable bindings can share individual copies. In fact, one- and two-character strings are automatically shared in Python. On the down side, however, a programmer cannot do something like “change all x’s to y’s” in any string. Instead, a new string with all the desired properties will have to be created. This process of continual copying may be a source of inefficiencies in some Python programs. As an illustration, here is something that you would want to avoid: a=” ” For substring in this list: a += substring Instead, use the a=””.join(list) line. The former example is actually a common mistake Python novices have in the process of building large strings. In the same vein, if you generate bits of a string in a sequential manner, avoid the following: a=” ” For b in list: a+=a_function(b) Instead, use: alist=[a_function(elt) for elt in anotherlist] a=” ”.join(alist) Also, avoid the following: Out=””+head+prologue+query+tail+””

Instead of that, use: Out=””%s%s%s%s” % (head, prologue, query, tail) For readability, it is even better to use a dictionary substitution (this, however, will not have anything to do with efficiency aside from your own as a programmer). Out=”%(head)s%(prologue)s%(query)s%(tail)s” % locals() The last couple of examples are both going to be much faster than the first, and even more so when they are piled up over multiple CGI script executions. They are also easier to modify if necessary. On top of this, the addition of the rich comparisons in Python 2.X has made the slow way even slower. If you are using that branch, it will take your virtual machine even more time to figure out how the two strings will be concatenated. Also, do not forget that all the method look-up will be done by Python at runtime. Loops Some looping constructs are supported by Python. Of them, the most commonly used statement is the for. It works by looping over the elements of the sequence, each being assigned to the loop variable. If the loop’s body is simple, then the for loop’s interpreter overhead may be a substantial chunk of the entire overhead. At this point, the map function will be handy. You may visualize the map function as for which has been moved into C. The sole restriction is that the map’s loop body should be a function call. Here is an example—this one loops over the list of words and converts them to the upper case: Thislist=[] For word in thatlist: Thislist.append(word.upper()) You can instead use the map function to have the loop pushed from your interpreter into a compiled C code:

Thislist=map(str.upper,thatlist) It doesn’t even matter if you have plain old Python 2.0, as list comprehensions have been added from this version onwards. These provide a more compact (syntactically) and a more efficient way to write the for loop: Thislist=[s.upper() for s in thatlist: The generator expressions have been added since Python 2.4. These function in about a similar way as map or list comprehensions. However, they avoid the need for additional overhead (i.e., having to generate the entire list all at once). Instead of this, a generator object which can be incrementally iterated is being returned: Iterator=(s.upper() for s in thatlist) Whether the method you are using is appropriate will depend on which version of Python you will be using. Another consideration will be the characteristics of the data that you are manipulating. Avoiding the dots Suppose you will not be able to use a list comprehension or map? Then you may be stuck with using the for loop. This will lend your program to another inefficiency. The word.upper and thislist.append are function references which are being re-evaluated every time through the loop. Instead, you can replace the original loop with the following code: upper=str.upper thislist=[] append=thislist.append for word in thatlist: append(upper(word)) However, use this technique with caution. It will be more difficult to maintain once the loop starts to get larger. Unless you already are, you will first have to be very acquainted with the usage of upper and append.

Local Variables Without the map version, the last speedup available for the for loop will be the use of local variables as long as possible. If the loop above has been cast as a function, upper and append will become local variables. The Python language will access these local variables a lot better than global variables. Take a look at the following example: Def func(): Upper = str,upper Thislist=[] Append=thislist.append For word in thatlist: Append(upper(word)) Return thislist Initializing Dictionary Elements Let’s say that you are building a dictionary containing word frequencies, and that you have already broken up the text into word lists. You may then execute something similar to the following code: Wdict={} For word in words: If word not in wdict: Wdict[word]=0 Wdict[word]+=1 The exception is that for the first time, every time that a word is seen then the test of the if statement will fail. If you will be counting a large amount of words, then many of them will probably be recurring multiple times. In a time where the value’s initialization will only be occurring once and the value’s augmentation will occur multiple times, it will be better to use a try statement. Check out the following code: Wdict={} For word in words:

Try: Wdict[word]+=1 Except KeyError: Wdict[word]=1 It will be important to catch the KeyError exception that you are expecting. At the same time, you should not use a generic except clause in order to avoid attempting to recover from exceptions which cannot really be handled using statements in the try clause. Another alternative is to use the get() method, available since Python 2.0—this means that if you downloaded a fresh Python implementation when you started this book, this is the best thing to use. This method will return a default value when the desired key cannot be found in the dictionary. This will simplify the loop. Wdict={} Get=wdict.get For word in words: Wdict[word]=get(word,0)+1 In addition, if the value that the dictionary stores is a mutable list (object), you may use dict.setdefault: 4 wdict.setdefault(key,[]) .append(new_element) You might be thinking that this will avoid having to look the key up twice, but it doesn’t— not even in Python 3.x. At least, however, the double look up is being performed in C. Another available option is using the defaultdict: From collections import defaultdict Wdict = defaultdict(int) For word in words: Wdict[word]+=1

Overhead for Import Statements The import statement can be used almost anywhere. It will often be useful to place these inside functions in order to restrict the visibility and also to help reduce the start-up time. While the interpreter is optimized to avoid the importation of the module multiple times, the repeated execution of an import statement will affect (sometimes seriously so) the performance of the program in certain circumstances. Check out the next two examples of code: Def dothis1(): Import string #this will import the statement inside function String.lower(‘Spam’) For num in range (100000): Dothis1() Or: Import string # this will import statement outside function Def dothis2(): String.lower(‘Spam’) For num in range(100000): Dothis2() In the above examples, dothis2 will be running significantly faster than dothis1, despite the string module reference being global in dothis2. Then again, string methods (which have been introduced in Python 2.0) can be used, totally avoiding the need for import and making the program run even faster: Def dothis3():

‘Spam’.lower() For num in range (100000): Dothis3() Notice that putting the import within a function may speed up the module’s initial recording, especially when the imported module may not even be required. This is usually seen as a case of “lazy” optimization—avoiding the work (in this case, an expensive case of importing) until it is confirmed that the said work is required. This can only be a significant optimization in case the module would not have been imported in any way, from any module. Once the module is already loaded—like in the case of a lot of standard modules such as re or string—avoiding the import will not save anything. To see the modules that have already been loaded in the system, you can check in sys.modules. You can also use the following method to do a good lazy import: Email=None Def parse_email(): Global email If email is None: Import email … In this example, the email module will only have to be imported once, once parse_email() is invoked. Data Aggregation In Python, the overhead for function calls is quite high. This is especially tru when compared with a builtin function’s execution speed. This suggests that when appropriate, data aggregates should be handled by functions. Here is an example (a contrived one): import time y=0

Def dothis1(s): Global a A=a+i List=range(100000) X=time.time() For s in list: Dothis1(s) Print”%.3f”% (time.time()-x) Compare the above example with the next one: Import time Y=0 Def dothis2(list): Global x For s in list: A=a+i List=range(100000_ X=time.time() Dothis2(list) Print”%.3f”% (time.time()-t) Even if written in Python, the second example will still run at around four times faster. If this is written in the C language, the difference in speed would have been more profound, as this involves using a C for loop instead of a Python one, while also removing many of the code’s function calls. Going Lazy Well, we already talk of going lazy a bit in the last section, so let’s take a break from the technical things and focus on that one. Take note that periodically, Python performs some checks. Specifically, it will decide during such times whether or not it should let another

thread run. It also things of whether or not a pending call should be run (these calls are typically established by signal handlers). Most of the time, these checks do not result in anything for Python to do. That means each pass these checks make around the interpreter loop can cause things to slow down. In such circumstances, we can use the setcheckinterval function within the sys module—this can be called to tell the interpreter exactly how often you would want these periodic checks to be performed. Before the advent of Python 2.3, this has been defaulted to 10. Since then, it had been raised to a hundred. So if you are not expecting to catch many signals (and if you are not running with threads), you can set this to an even larger value to help nudge the interpreter’s performance. Instead of range, use xrange This will not apply if you are using the Python 3.X branch, where the range function will provide an iterator for arbitrarily-sized ranges, and where the xrange function does not exist. However, if you are using other Python versions, this may be useful. Python provides two ways of getting a range of numbers—xrange and range. Most programmers already know range, since the name makes it quite obvious. However, xrange is a lot less known. It is a generator object, which is equivalent to the following code (exhibited in Python 2.3): Def xrange(start,stop=None, step=1): If stop is None: Stop=start Start=0 Else: Stop=int(stop) Start=int(start) Step=int(step) While start

Smile Life

When life gives you a hundred reasons to cry, show life that you have a thousand reasons to smile

Get in touch

© Copyright 2015 - 2024 AZPDF.TIPS - All rights reserved.