Python Caleb Lawson CSC 415: Programming Languages Dr. Lyle November 4, 2014 Python – Lawson

History

Development For Guido van Rossum, the weeks around Christmas were slow. Being the tinkerer he was, Guido van Rossum, could not keep himself from coding. During the Christmas holidays of

1989, he began developing the Python scripting language. Of course, Guido van Rossum did not build his language without a purpose in mind. Guido van Rossum worked at the National

Research Institute for Mathematics and Computer Science in the Netherlands, known as CWI.

There, he was on the development team for the Amoeba distributed operating system. System administration was difficult, with C programs and Bourne shell scripts being the only options.

Amoeba had a custom system call interface which was not easily accessible with Bourne scripts.

(“General Python FAQ”)

Guido van Rossum's prior experiences developing the ABC computer language proved valuable. ABC was designed to be understood by intelligent computer users who lacked programming experience—and a replacement for BASIC. ABC did not take off, because of the prevalence of BASIC and the lack of efficient distribution mechanisms. Guido van Rossum realized that a scripting language with the syntax of ABC and access to Amoeba system calls was exactly what the Amoeba project needed—a language to “bridge the gap between shell and C.”

Realizing that designing a case-specific language would prove to be less useful, Guido van

Rossum made sure that Python would be extensible (Venners, “ABC's Influence on Python”).

By February of 1991, he decided to post his work to USENET (“General Python FAQ”).

Arguably accelerating its growth. By March 6th, 2001, the Python Software Foundation, a non-

2 Python – Lawson profit organization devoted to the Python , was formed.

The features of Python grew along with its multiple releases. Features of Python 1.0

(released in 1994) include the addition of functional programming tools, courtesy of a Lisp (Van Rossum, “The Fate of Reduce() in Python 3000”). Additional features include name-mangling (a form of data hiding) and support for complex numbers. Python 2.0 added a garbage collection system, list comprehensions, support for nested scopes, and the unification of the types hierarchy (Kuchling and Zadka). Python 3.0, the most recent release, removed old syntax, converted print into a function, and unified string types (Van Rossum, “What's New In

Python 3.0”).

Design Philosophy Python, unlike ABC, was initially designed with the seasoned developer in mind. The initial goal of the project was to create a second language for familiar with C and

C++, where writing a C program was not effective. Many of the design principles came from

Guido van Rossum's experience in developing ABC, with his own improvements baked in

(Venners, “Python's Original Design Goals”). Eventually, as Python became a community-based project in the late 90's, the notion of Pythonic Zen came about. This was distilled into design aphorisms, called “The Zen of Python,” by none other than long-time Pythoneer Tim Peters.

Python is designed to be beautiful, explicit, practical, simple, and readable (Peters).

3 Python – Lawson

Overview of Language Design, Syntax, and Semantics

Names, Bindings, and Scopes Python is a case-sensitive language; language reserved words are in lower case. Like

Java, variable names can contain alphanumeric characters and underscores but cannot begin with a digit. Variables are essentially references to data objects that exist in memory (Sebesta, 260).

They are typeless and are implicitly declared when they are the target of an assignment statement. An object in memory can be referred to by several different variables (Hetland, 14).

Variables can be used to refer to functions (Hetland, 17). Python is dynamically typed, meaning that the object to which a variable is referring can be changed by the programmer at any point.

That variable can refer to an object of any type, since the variable name is not bound to a type.

Python is also a strongly typed language, meaning that a programmer cannot mix incompatible data types in operations. Python allows for global and local variables. Local variables exist inside of Python functions and methods. An interesting thing to note about Python is that a local variable with the same name as a preexisting global variable will not affect the value of the global variable (Hetland, 131). Defining a function creates a local scope. In Python, you can define functions within functions—called “nesting.” When this is done, the inner function can reference the variables of the outer function though static scoping (Hetland, 133) (Sebasta, 230).

Data Types Python supports many data types right out of the box. Integers, floats, complex numbers, strings, lists, dictionaries, and tuples are built-in data types—all of which are memory objects.

Since Python is both dynamically and strongly typed, Python implicitly converts only compatible

4 Python – Lawson types. Numeric types are implicitly cast, so mathematical operations can be performed without explicitly casting. Numeric types and string types are not compatible, and therefore, need to be cast or parsed before mathematical or stringwise operations can occur. (“Why Is Python a

Dynamic Language and Also a Strongly Typed Language”)

Integers are supported in Python. In versions prior to three, when an integer is divided by a floating point value, the results in floor division. When regular integers grow too large, Python implicitly converts the large value into a long integer. Long integers can have 'unlimited' length, but are not directly supported by Python. One can explicitly make a long integer like so: x =

12345678987650432L (Sebesta, 246). When a period is used in a number literal, a floating point number is created (ex. x= 3.14). This also happens when integers are divided by floating point numbers. Complex numbers are also supported, they are declared thusly: x = (8 + 9j) (Sebesta,

248).

Container types in Python include strings, lists, maps, and tuples. Python supports strings as a primitive type, and behave as is traditional: an array of characters. Python encodes strings in unicode characters. Characters are not a separate data type in Python, but the same affect can be achieved through creating a string of length 1. Python has built-in string operations for substrings, concatenation, indexing, search and replace, and membership. Strings are immutable, meaning that strings are not directly modified—new strings are returned as a result of string operations.

Python's arrays are called lists. Unlike arrays in most languages, Python lists are dynamic and can hold objects of any type. Consider this list: list = [ 1, 2.0, (6 + 2j), 'healthy

5 Python – Lawson tomatoes', 42 ]. Python lists are mutable; elements can be inserted, appended, modified, deleted, and sorted. Lists can also be concatenated (Sebesta, 266). The default lower-bound index for collection types accessed by index is 0. Sublists are referred to as slices and can be defined like this: a_list [100:200] or a_list [0:100:5] (Sebesta, 268). In the second example, every fifth element is taken. Dictionaries are another mutable collection type, they are unordered and are accessed in key-value pairs, e.g. telNum = { 'Janeway' : 5022056432, 'Papa Johns' :

2709088097 } (Sebesta, 272). Tuples are yet another container type, and they are immutable.

Tuples contain an n-length number of values of mixed data types, seperated by commas. A tuple is declared thusly: tuple = 'Hank Hill', 54, 286.2. Tuples can be nested: tuple = tuple2, 4, tuple3

(Sebesta, 280). Sets are another container type, they are unordered and contain no duplicate values. Sets support set theory through union, intersection, difference and symmetric difference operations.

Expressions and Assignment Structures In Python, standard mathematical operators +, -, *, /, %, and ** are in the usual order of precedence. The // operator in Python represents floor division. Compound assignment operators += and -= exist in Python (Sebesta, 337). Mixed-mode assignment does not exist in

Python, because data types are associated with objects and not variable names. Multiple-target assignment is legal in Python (e.g. chris, dana, paul = “super special winners”) (Sebesta, 339).

Multiple assignment statements can also be reduced into one by seperating the values with commas (e.g. or chris, paul = 'atkins', 'seaworthy'). All logical operators are short-circuit evaluated (Sebesta, 336). Comparison operators maintain a roughly mathematical meaning, a >

6 Python – Lawson b > c == a > b and b > c. However, when functions are used with comparison operators (e.g. a

> function() > c), the function is only evaluated once which may yield unexpected results.

Boolean operators treat non-boolean data object as True if they are non-empty and False if they are (i.e “”, 0, 0.0, [], {}). Python operators may be overloaded, for instance: def

__subtract__(self, second): return self – (self * second).

Statement-Level Control Structures Python contains the standard set of control statements that are familiar in other languages, like Java and C++. Python supports if, else if, and else statements. Python also supports for and while loops. The body of a control statement is indented to show that code belongs inside the control structure, instead of the curly braces seen in C-based languages (Sebesta, 351). The header of an if statement looks like this: if condition: print 'if executed'. To test additional conditions, an elif (else if) clause can be added: elif condition: print 'more stuff'. Additionally, if an else clause can be added: else: 'the else clause has been executed'. A complete if block can consist of only one initial if statement, and zero to many elif statements, and zero or one else statement. (“More Control Flow Tools”)

While loops are one of the looping control structures included in Python. They are used to repeat a set of instructions while a condition is true. To make a while statement that repeats until j reaches ten: while j <= 11: print j (“An Informal Introduction to Python”). For loops are another control structure, but behave differently than for loops of most other languages. For loops in Python iterate through the items of any list, string, or dictionary in the order that they appear. The range() function can be used in tandem with a for loop to iterate over a specific

7 Python – Lawson section or on a specific interval. Continue and break statements like those found in Java and C+

+ exist. Break statements terminate the innermost for or while loop; continue statements terminate the current iteration of the innermost for or while loop and allows the next to be started

(Sebesta, 370). Both while and for loops in Python may have an else clause, containing code that is executed when a break does not occur. (“More Control Flow Tools”)

Subprograms Python makes heavy use of functions. Functions in Python are supposed to be minimalist and atomized, meaning they should have one and only one purpose. Functions are defined like this:

def max(a,b): 'Finds the maximum of two values and returns it.' if a > b: return a else: return b In the function definition, max is the name of the function and serves as a pointer to that function. The function could be renamed by simply stating: maximum = max. Programmers familiar with Java and C++ will notice that function parameters in Python do not have a type. In

Python, data objects have type, but variable names do not. Parameters, because they are merely variable names, are not type checked. The first line of the function defined above is a string literal, called a documentation string. The rest contains a set of statements to be executed and the value to be returned, which can be of any type—as a consequence, a general polymorphism is

8 Python – Lawson supplied (Sebesta, 422 & 429). Functions without a return statement are technically still functions, because they return the value None. Function definitions can be executed, and are allowed to be nested within other functions (Sebesta, 390 & 399). Each function has its own, local scope. Inside a function, local variables referenced before global variables. Nested functions can also reference variables local to their enclosing function. Global variables cannot be directly modified within a function, unless a global statement is used (Sebesta, 408). In python, function parameters can be listed in any order, as long as the variable to which the value belongs is specified. For instance: addNewCustomer(firstName = 'BigMac', age = 122, lastName = 'McDolan', netWorthInCheeseburgers = 5,020) (Sebesta, 392). Parameters can also have default values, they are assigned in the function definition: def primeLister(start = 0, end =

100). Functions can return multiple values by returning them in either a tuple or a list (Sebesta,

281).

Support for Object-Oriented Programming Python uses object-orientation for data abstraction and encapsulation, so it has been rolled into this section. Objects are central to the inner-workings of Python. If one was to sarcastically proclaim, “Everything is an object in Python,” they would not be far from the truth.

Data abstraction and encapsulation is accomplished through classes. Classes describe real-life objects, and just like their real life counterparts, classes have attributes, properties, and methods.

Class headers look like this: class ClassName(object): pass. Class variables are by default public, and can be accessed from inside and outside the class. Making class variables protected or private is achieved through name-mangling. Protected variables begin with a single

9 Python – Lawson underscore, and act much like public variables (Fast). Private variables begin with two underscores, are usable inside the class, and cannot be seen or accessed from the outside without calling them directly. This protected and private variables in Python are only a simulation, as

Python does not prevent users from accessing private data members outside of their context, merely hiding variable names when called outside their context. A user could easily circumvent private and protected members by using the full name of the variable. Static data members, data objects that all instances of an object share, are created when variables are first defined inside the class definition but outside a class method (“Static Class Variables in Python”). Instance variables are defined within a class definition's methods. Within methods, instance variables are accessed by the keyword self. For example, self.debitAmount = 13.99. (Klein, "Python Tutorial:

Object Oriented Programming")

Methods are functions tied to classes, this is done by defining the function within a class.

The first parameter of the function must be a reference to the class; this is done with the keyword self. As stated earlier, by virtue of data-typed objects and typeless variables, Python methods provide a general kind of polymorphism—able to react to any type passed to a parameter. Class methods can be made private or protected by using either one or two underscores. On a related note, Python does not have explicit constructors. The __init__() method serves a similar purpose, but it is not technically a constructor because the instance has been created before

__init__() is called. Nevertheless, __init__() is the first method called, and is used to initialize instance variables. Likewise, no destructor (technically) exists in Python, instead __del__() is called just before an object is to be destroyed. For parent classes that have a __del__() method,

10 Python – Lawson child classes must explicitly call the parent's __del__() method within their own. (Klein, "Python

Tutorial: Object Oriented Programming")

Just like in Java, Python classes can inherit from other classes. Earlier the class definition, class ClassName(object): pass, was given. The class ClassName inherits from the object class. To create a ChildClassName that inherits from ClassName, ClassName would appear in the parentheses. The child class ChildClassName inherits from ClassName, which inherits the object class. Unlike Java, Python supports multiple inheritance. This can be achieved by appending to the inheritance list and separating with commas. For example, class

ClassName(Parent1,Parent2,Parent3,Parent4) (Klein, "Python Tutorial: Object Oriented

Programming").

To collect classes and function definitions, Python provides modules. Much like .java files, .py files hold collections of code for later reuse. Vast libraries can be accessed by importing .py files. Python is all about modularity and 'not reinventing the wheel.' To import a module into the current namespace, an import statement is used: import module. The statement, from module import *, imports all publicly defined objects in the module and creates a reference in the current namespace. These are the two most commonly used import statements.

(“Modules”)

Concurrency Concurrency in Python is a mixed subject. The design implementation of standard

Python prevents certain kinds of concurrency. The Global Interpreter Lock, which was included as a coarse approach to thread safety was--and in part still is--a point of contention in the Python

11 Python – Lawson community. There have been attempts to remove the GIL in standard Python, including Google

Code Project: Unladen Swallow. The main motivation for this is the fact that the GIL eliminates the benefits of multi-threaded programs, namely performance. Before a better implementation of the GIL was introduced (in Python 3.2 and backported to previous versions), the GIL effectively doubled the CPU time of a multi-threaded program compared to an equivalent single-threaded program performing the same task. The reason being that individual threads in multi-threaded programs would compete for obtaining the GIL repeatedly. The problem had an exponential growth with the number of CPU cores until a better implementation of the GIL was introduced.

Now, multi-threaded programs have performance approaching the effectiveness of a single- threaded program. (Beazley)

A way to enjoy true concurrency in Python is by using the multiprocessing module. By relying on subprocesses instead of threads, the GIL is sidestepped. The creation of a process is heavier than that of a thread, and processes require a separate memory space where a thread would share memory with others. Inter-process communication is also an issue, which is solved by using thread-safe Queues and semi-safe Pipes. A Pipe() is a duplex (by default) inter-process communicator, where one process communicates to the other through their respective end of the

Pipe(). A scenario where a Pipe() could get corrupted is when two processes try to write to the same end of a pipe at the same time. The multiprocessing module also includes locking mechanisms of its own, when necessary. (“Multiprocessing”)

Exception Handling and Event Handling For exception handling, Python has try-catch blocks—rather, try-except blocks. The

12 Python – Lawson portion of code that has a risk of being error goes within a try block, the code to be executed when an exception occurs goes within except blocks. To specify an exception, the name of the exception is included in the header of the except block, to catch all, an exception is not specified.

When an exception occurs and the scenario applies to more than one, only the code in the first exception block triggered will be executed. Other clauses pertaining to try blocks are finally and else clauses. Finally clauses are clean-up or termination clauses, they should be listed as the last clause in a try block, and are executed every time a try block is executed, regardless of whether an exception was raised. Else clauses are also used at the end of a try block and they are executed only if an exception is not raised. Users are able to define their own exceptions, with the accepted method being the creation of a custom exception class. Python does not have built- in event handling, and it is handled either through external modules such as py-notify,

PyDispatcher, and Tkinter. A custom event handler is usually created by implementation of the

Observer Pattern. (Klein, “Python3 Tutorial: Exception Handling)

Aa,b = 27,0 Ttry: print a/b except ZeroDivisionError: print “Division by zero was attempted.” print “The answer is zero, if you needed to know.” except: print “In this example, I should not get executed.” finally: print “But I'll get executed no matter what happens”

13 Python – Lawson

Evaluation

Readability The Python community prides itself on readability, and is included in the Zen of Python.

The most notable of features intended to increase readability is the lack of using braces to offset sections of code, and the replacement of this with indentation. This feature definitely increases the aesthetic value of Python, reducing the clutter caused by braces and forcing correct formatting. In languages that use braces to offset code, indentations are optional—even if they are conventional. Forcing adoption leads to better-formatted code. In addition, Python does not use the semicolon to separate statements, only newline characters—another feature that removes clutter. Another feature for readability is the use of keywords instead of symbols for boolean operators: and, or, not. Unfortunately, Python does have features that it may be able to improve upon. Because Python is not as verbose as other languages when it comes to class headers, it can be difficult to discern the relationship between classes. Ternary operators are also problematic, due to the unconventional way they are defined: 'returned because true' if condition else

'returned because false' (“Does Python Have a Ternary Conditional Operator”). Of course, this could be said about all other Python structures that differ from common programming languages.

Dynamic typing is another crucial design decision that affects readability. Since variable identifiers are merely pointers to a data object and are not tied to a type, it can be difficult to understand what data type is being used in a given section of code. The effect of this design decision is magnified by both tuples and lists. Though tuples are immutable, and the type in a given position in the tuple is arbitrary and up to the author to decide. Tuples are accessed by

14 Python – Lawson index, so it is difficult to know what data types is in what slot. Lists are doubly problematic, because they are mutable and can contain multiple mixed types. If used incorrectly, a list could easily become the data equivalent of a junk drawer.

Another issue is that not all who program in Python do so in a Pythonic way, often accomplishing their needs in unique ways. The Python community have taken great steps to ensure that the Zen of Python is honored, though not everyone agrees on the “one, obvious way to do things.” Though this is mostly a problem with humans and not the language, it is important to note that the same problems in other programming languages also remain unsolved in Python.

Writeability As was mentioned in the section on readability, forced indention and lack of parentheses are troublesome for writeability. The programmer needs to be extremely conscious of whether they use a space or a tab character to indent lines, because they cannot be mixed. In addition, the programmer has to be especially attentive to how much they indent, as a simple mistake can change the flow of the program. Though it is important to note that Python's exclusion of brackets and semicolons reduce the amount of characters to be typed. The exclusion of semicolons also removes the possibility of the missing semicolon compiler complaints with which new and old programmers struggle alike. Another potential issue for programmers more familiar with other programming languages is the lack of increment and decrement shortcuts - - and ++. Though they do not exist in Python, the compiler does not complain.

Another is an issue with dynamic typing. As a consequence, variables are not declared a particular type and are created when an assignment is made. A programmer can easily mistype

15 Python – Lawson the name of an existing variable and inadvertently create a new variable. Also, it is possible that a programmer could reuse a variable by accident and affect the outcome of a program in an unexpected way. This can also be done with functions, since they are pointed to by a variable and can be assigned a new name.

Python also has its own set of rules that are not apparent to the new user, ones that must be learned from the community. In addition, what is Pythonic is not completely agreed upon in the community. As a result of having developed a community, being open source, and extremely modular, Python has a plethora of third-party modules and variations. Choosing the correct flavor of Python or the correct set of modules presents a challenge to those unfamiliar with them.

Many modules may go unused because of sheer ignorance of their existence, resulting in redundancy. Granted, this large library of options is also a benefit, for finding just the right module or Python implementation to suit one's needs.

Reliability Python prides itself on being a reliable language, and it is. Though Python, by nature of being interpreted, is slower than compiled languages. This makes it poorly suited for real-time processing and performance-oriented tasks. In addition, standard Python's concurrency issues still exist, though they can be sidestepped by using subprocesses and the multiprocessing module. Python is also poorly suited for situations where data type must be known and cannot change, because it is dynamically typed. For instance, Python should be discouraged in a medical or avionic setting. On a related note, Python has no real notion of access modifiers, so making variables truly private is not an option. Python has a built-in automatic garbage

16 Python – Lawson collector, so that allocation and deallocation of resources do not have to be managed by the user.

However, for many applications, Python is a perfectly viable option.

Cost Python is a low-cost language to implement, mostly because is is both open source and free. Training and code maintenance are the two major costs associated with developing and maintaining Python. Python has many modules and implementations, lending to ease, reuse, and the ability to choose the best tools for a particular situation.

Overall Python is a free, open source language that is suited for use in a wide number of applications, It is compatible with several programming paradigms: object oriented, procedural, functional, and imperative. It is easy enough for beginners to understand quickly, but advanced enough to be used by seasoned experts. Python has a well-developed community for language development and support. As a result, Python has many user-created libraries and implementations.

17 Python – Lawson

Works Cited

Beazley, David. "Dabeaz." Dabeaz. N.p., 5 Jan. 2010. Web. 03 Nov. 2014.

"Design and History FAQ." Design and History FAQ — Python 2.7.8 Documentation. N.p., n.d. Web. 03 Nov. 2014.

"Does Python Have a Ternary Conditional Operator?" Stack Overflow. N.p., n.d. Web. 03 Nov. 2014.

Fast, Karl. "What Is "pythonic"?" Python.org. N.p., 24 Oct. 2003. Web. 03 Nov. 2014.

"General Python FAQ." General Python FAQ — Python 2.7.8 Documentation. N.p., n.d. Web. 03 Nov. 2014.

Hetland, Magnus Lie. Beginning Python: From Novice to Professional. Berkeley, Calif: Apress, 2008. Print.

"An Informal Introduction to Python." Python.org. N.p., n.d. Web. 03 Nov. 2014.

Klein, Bernd. "Python Course." Python Tutorial: Object Oriented Programming. N.p., n.d. Web. 03 Nov. 2014.

Klein, Bernd. "Python Course." Python3 Tutorial: Exception Handling. N.p., n.d. Web. 03 Nov. 2014.

Kuchling, A. M., and Moshe Zadka. "What's New in Python 2.0." What's New in Python 2.0. N.p., n.d. Web. 03 Nov. 2014.

"Modules." 6. Modules — Python 2.7.8 Documentation. Python.org, n.d. Web. 03 Nov. 2014.

"More Control Flow Tools." Python.org. N.p., n.d. Web. 03 Nov. 2014.

"Multiprocessing — Process-based “threading” Interface." 16.6. Multiprocessing. N.p., n.d. Web. 03 Nov. 2014.

Peters, Tim. "PEP 20 -- The Zen of Python." PEP 20 -- The Zen of Python. N.p., 19 Aug. 2004. Web. 03 Nov. 2014.

Sebesta, Robert W. Concepts of Programming Languages. Boston: Pearson, 2007. Print.

18 Python – Lawson

"Static Class Variables in Python." Stack Overflow. N.p., n.d. Web. 03 Nov. 2014.

Van Rossum, Guido. "The Fate of Reduce() in Python 3000." Artima. N.p., 10 Mar. 2005. Web. 03 Nov. 2014.

Van Rossum, Guido. "What’s New In Python 3.0." What's New In Python 3.0 — Python V3.0.1 Documentation. Python Foundation, 14 Feb. 2009. Web. 03 Nov. 2014.

Venners, Bill. "ABC's Influence on Python." The Making of Python. N.p., 13 Jan. 2003. Web. 03 Nov. 2014.

Venners, Bill. "Python's Original Design Goals." Python's Design Goals. N.p., 20 Jan. 2003. Web. 03 Nov. 2014.

"Why Is Python a Dynamic Language and Also a Strongly Typed Language." N.p., 24 Feb. 2012. Web. 03 Nov. 2014.

19