• No results found

In general, the data type of an expresion depends on the types of the arguments. This rule meets our expectations for most operators: when we add two integers, the result should be an integer. However, this doesn’t work out well for division because there are two different expectations. Sometimes we expect division to create precise answers, usually the floating-point equivalents of fractions. Other times, we want a rounded-down integer result.

The classical Python definition of ‘/’ followed the pattern for other operators: the results depend entirely on the arguments. ‘685/252’ was 2 because both arguments where integers. However, ‘685./252.’ was 2.7182539682539684 because the arguments were floating point.

This definition often caused problems for applications where data types were used that the author hadn’t expected. For example, a simple program doing Celsius to Fahrenheit conversions will produce different answers depending on the input. If one user provides ‘18’ and another provides ‘18.0’, the answers were different, even though all of the inputs all had the equal numeric values.

>>> 18*9/5+32 64 >>> 18.0*9/5+32 64.400000000000006 >>> 18 == 18.0 True

This unexpected inaccuracy was generally due to the casual use of integers where floating-point numbers were more appropriate. (This can also occur using integers where complex numbers were implictly expected.) An explicit conversion function (likefloat()) can help prevent this. The idea, however, is for Python be a simple and sparse language, without a dense clutter of conversions to cover the rare case of an unexpected data type.

Starting with Python 2.2, a new division operator was added to clarify what is required. There are two division operators: ‘/’ and ‘//’. The ‘/’ operator should return floating-point results; the ‘//’ operator will always return rounded-down results.

In Python 2.5 and 2.6, the ‘/’ operator can either use “classical” or “old” rules (results depend on the values) or it can use the “new” rule (result is floating-point.) In Python 3.x, this transitional meaning of ‘/’ goes away and it always produces a floating-point result.

Important: Python 3

In Python 3, the ‘/’ operator will always produces a floating-point result. The ‘//’ operator will continue to produce an integer result.

To help with the transition, two tools were made available. This gives programmers a way to keep older applications running; it also gives them a way to explicitly declare that their program uses the newer operator definition. There are two parts to this: a program statememt that can be placed in a program, as well as command-line options that can be used when starting the Python interpreter.

Program Statements. To ease the transition from older to newer language features, there is a__future__ module available. This module includes adivisiondefinition that changes the definition of the ‘/’ operator from classical to future. You can include the followingimportstatement to state that your program depends on the future definition of division. We’ll look at theimport statement in depth inComponents, Modules and Packages.

from __future__ import division print 18*9/5+32

print 18*9//5+32

This produces the following output. The first line shows the new use of the ‘/’ operator to produce floating point results, even if both arguments are integers. The second line shows the ‘//’ operator, which produces rounded-down results.

64.4 64

The from __future__ statement will set the expectation that your script uses the new-style floating- point division operator. This allows you to start writing programs with version 2.6 that will work correctly with all future versions. By version 3.0, thisimport statement will no longer be necessary, and these will have to be removed from the few modules that used them.

Command Line Options. Another tool to ease the transition are command-line options used when running the Python interpreter. This can force old-style interpretation of the ‘/’ operator or to warn about old-style use of the ‘/’ operator between integers. It can also force new-style use of the ‘/’ operator and report on all potentially incorrect uses of the ‘/’ operator.

The Python interpreter command-line option of ‘-Q’ will force the ‘/’ operator to be treated classically (“old”), or with the future (“new”) semantics. If you run Python with ‘-Qold’ , the ‘/’ operator’s result depends on the arguments. If you run Python with ‘-Qnew’, the ‘/’ operator’s result will be floating point. In either case, the ‘//’ operator returns a rounded-down integer result.

You can use ‘-Qold’ to force old modules and programs to work with version 2.2 and higher. When Python 3.0 is released, however, this transition will no longer be supported; by that time you should have fixed your programs and modules.

To make fixing easier, the ‘-Q’ command-line option can take two other values: ‘warn’ and ‘warnall’ . If you use ‘-Qwarn’, then the ‘/’ operator applied to integer arguments will generate a run-time warning. This will allow you to find and fix situations where the ‘//’ operator might be more appropriate. If you use ‘-Qwarnall’, then all instances of the ‘/’ operator generate a warning; this will give you a close look at your programs.

You can include the command line option when you run the Python interpreter. For Linux and MacOS users, you can also put this on the ‘#!’ line at the beginning of your script file.

SEVEN

VARIABLES, ASSIGNMENT AND

INPUT

The = , augmented = and del Statements

Variables hold the state of our program. In Variables we’ll introduce variables, then in The Assignment Statement we’ll cover the basicassignment statement for changing the value of a variable. This is followed by an exercise section that refers back to exercises fromSimple Numeric Expressions and Output. InInput Functions we introduce some primitive interactive input functions that are built-in. This is followed by some simple exercises that build on those from sectionThe Assignment Statement. We’ll cover the multiple assignment statement inMultiple Assignment Statement. We’ll round on this section with thedelstatement, for removing variables inThe del Statement.

7.1 Variables

As a procedural program makes progress through the steps from launch to completion, it does so by under- going changes of state. The state of our program as a whole is the state of all of the program’s variables. When one variable changes, the overall state has changed.

Variables are the names your program assigns to the results of an expression. Every variable is created with an initial value. Variables will change to identify new objects and the objects identified by a variable can change their internal state. These three kinds of state changes (variable creation, object assignment, object change) happen as inputs are accepted and our program evaluates expressions. Eventually the state of the variables indicates that we are done, and our program can exit.

A Python variable name must be at least one letter, and can have a string of numbers, letters and ‘_’‘s to any length. Names that start with ‘_’ or ‘__’ have special significance. Names that begin with ‘_’ are typically private to a module or class. We’ll return to this notion of privacy inClassesandModules. Names that begin with ‘__’ are part of the way the Python interpreter is built.

Example variable names: a pi aVeryLongName a_name __str__ _hidden

Tip: Tracing Execution

We can trace the execution of a program by simply following the changes of value of all the variables in the program. For programming newbies, it helps to create a list of variables and write down their changes when studying a program. We’ll show an example in the next section.

Python creates new objects as the result of evaluating an expression. Python assigns these objects to new variables with anassignmentstatement. Python removes variables with adelstatement. The underlying object is later garbage-collected when there are no more variables referring to the object.

Some Consequences. A Python variable is little more than a name which refers to an object. The central issue is to recognize that the underlying object is the essential part of our program; a variable name is just a meaningful label. This has a number of important consequences.

One consequence of a variable being simple a label is that any number of variables can refer to the same object. In other languages (C, C++, Java) there are two kinds of values: primitive and objects, and there are distinct rules for handling the two kinds of values. In Python, every variable is a simple reference to an underlying object. When talking about simple immutable objects, like the number 3, multiple variables referring to a common object is functionally equivalent to having a distinct copy of a primitive value. When talking about mutable objects, like lists, mappings, or complex objects, distinct variable references can change the state of the common object.

Another consequences is that the Python object fully defines it’s own type. The object’s type defines the representation, the range of values and the allowed operations on the object. The type is established when the object is created. For example, floating point addition and long integer objects have different representations, operations of adding these kinds of numbers are different, the objects created by addition are of distinct types. Python uses the type information to choose which addition operation to perform on two values. In the case of an expression with mixed types Python uses the type information to coerce one or both values to a common type.

This also means the “casting” an object to match the declared type of a variable isn’t meaningful in Python. You don’t use C++ or Java-style casting.

We’ve already worked with the four numeric types: plain integers, long integers, floating point numbers and complex numbers. We’ve touched on the string type, also. There are several other built-in types that we will look at in detail inData Structures. Plus, we can use class definitions to define new types to Python, something we’ll look at inData + Processing = Objects.

We commonly say that astatic language associates the type information with the variable. Only values of a certain type can be assigned to a given variable. Python, in contrast, is adynamiclanguage; a variable is just a label or tag attached to the object. Any variable can be associated with an object of any type. The final consequence of variables referring to objects is that a variable’s scope can be independent of the object itself. This means that variables which are in distinct namespaces can refer to the same object. When a function completes execution and the namespace is deleted, the variables are deleted, and the number of variables referring to an object is reduced. Additional variables may still refer to an object, meaning that the object will continue to exist. When only one variable refers to an object, then removing the last variable removes the last reference to the object, and the object can be removed from memory.

Also note that a expressions generally create new objects; if an object is not saved in a variable, it silently vanishes. We can safely ignore the results of a function.

Scope and Namespaces. A Python variable is a name which refers to an object. To be useful, each variable must have ascopeof visibility. The scope is defined as the set of statements that can make use of this variable. A variable with global scope can be referenced anywhere. On the other hand, variable with local scopecan only be referenced in a limited suite of statements.

This notion of scope is essential to being able to keep a intellectual grip on a program. Programs of even moderate complexity need to keep pools of variables with separate scopes. This allows you to reuse variable names without risk of confusion from inadvertantly changing the value of a variable used elsewhere in a program.

Python collects variables into pools called namespaces. A new namespace is created as part of evaluating the body of a function or module, or creating a new object. Additionally, there is one global namespace. This means that each variable (and the state that it implies) is isolated to the execution of a single function or module. By separating all locally scoped variables into separate namespaces, we don’t have an endless clutter of global variables.

In the rare case that you need a global variable, theglobalstatement is available to assign a variable to the global namespace.

When we introduce functions in Functions, classes in Classes and modules in Components, Modules and Packages, we’ll revisit this namespace technique for managing scope. In particular, see Functions and Namespacesfor a digression on this.