7.Input and Output¶
There are several ways to present the output of a program; data can be printedin a human-readable form, or written to a file for future use. This chapter willdiscuss some of the possibilities.
7.1.Fancier Output Formatting¶
So far we’ve encountered two ways of writing values:expression statements andtheprint()
function. (A third way is using thewrite()
methodof file objects; the standard output file can be referenced assys.stdout
.See the Library Reference for more information on this.)
Often you’ll want more control over the formatting of your output than simplyprinting space-separated values. There are several ways to format output.
To useformatted string literals, begin a stringwith
f
orF
before the opening quotation mark or triple quotation mark.Inside this string, you can write a Python expression between{
and}
characters that can refer to variables or literal values.>>>year=2016>>>event='Referendum'>>>f'Results of the{year}{event}''Results of the 2016 Referendum'
The
str.format()
method of strings requires more manualeffort. You’ll still use{
and}
to mark where a variablewill be substituted and can provide detailed formatting directives,but you’ll also need to provide the information to be formatted. In the following codeblock there are two examples of how to format variables:>>>yes_votes=42_572_654>>>total_votes=85_705_149>>>percentage=yes_votes/total_votes>>>'{:-9} YES votes{:2.2%}'.format(yes_votes,percentage)' 42572654 YES votes 49.67%'
Notice how the
yes_votes
are padded with spaces and a negative sign only for negative numbers.The example also printspercentage
multiplied by 100, with 2 decimalplaces and followed by a percent sign (seeFormat Specification Mini-Language for details).Finally, you can do all the string handling yourself by using string slicing andconcatenation operations to create any layout you can imagine. Thestring type has some methods that perform useful operations for paddingstrings to a given column width.
When you don’t need fancy output but just want a quick display of somevariables for debugging purposes, you can convert any value to a string withtherepr()
orstr()
functions.
Thestr()
function is meant to return representations of values which arefairly human-readable, whilerepr()
is meant to generate representationswhich can be read by the interpreter (or will force aSyntaxError
ifthere is no equivalent syntax). For objects which don’t have a particularrepresentation for human consumption,str()
will return the same value asrepr()
. Many values, such as numbers or structures like lists anddictionaries, have the same representation using either function. Strings, inparticular, have two distinct representations.
Some examples:
>>>s='Hello, world.'>>>str(s)'Hello, world.'>>>repr(s)"'Hello, world.'">>>str(1/7)'0.14285714285714285'>>>x=10*3.25>>>y=200*200>>>s='The value of x is '+repr(x)+', and y is '+repr(y)+'...'>>>print(s)The value of x is 32.5, and y is 40000...>>># The repr() of a string adds string quotes and backslashes:>>>hello='hello, world\n'>>>hellos=repr(hello)>>>print(hellos)'hello, world\n'>>># The argument to repr() may be any Python object:>>>repr((x,y,('spam','eggs')))"(32.5, 40000, ('spam', 'eggs'))"
Thestring
module contains aTemplate
class that offersyet another way to substitute values into strings, using placeholders like$x
and replacing them with values from a dictionary, but offers much lesscontrol of the formatting.
7.1.1.Formatted String Literals¶
Formatted string literals (also called f-strings forshort) let you include the value of Python expressions inside a string byprefixing the string withf
orF
and writing expressions as{expression}
.
An optional format specifier can follow the expression. This allows greatercontrol over how the value is formatted. The following example rounds pi tothree places after the decimal:
>>>importmath>>>print(f'The value of pi is approximately{math.pi:.3f}.')The value of pi is approximately 3.142.
Passing an integer after the':'
will cause that field to be a minimumnumber of characters wide. This is useful for making columns line up.
>>>table={'Sjoerd':4127,'Jack':4098,'Dcab':7678}>>>forname,phoneintable.items():...print(f'{name:10} ==>{phone:10d}')...Sjoerd ==> 4127Jack ==> 4098Dcab ==> 7678
Other modifiers can be used to convert the value before it is formatted.'!a'
appliesascii()
,'!s'
appliesstr()
, and'!r'
appliesrepr()
:
>>>animals='eels'>>>print(f'My hovercraft is full of{animals}.')My hovercraft is full of eels.>>>print(f'My hovercraft is full of{animals!r}.')My hovercraft is full of 'eels'.
The=
specifier can be used to expand an expression to the text of theexpression, an equal sign, then the representation of the evaluated expression:
>>>bugs='roaches'>>>count=13>>>area='living room'>>>print(f'Debugging{bugs=}{count=}{area=}')Debugging bugs='roaches' count=13 area='living room'
Seeself-documenting expressions for more informationon the=
specifier. For a reference on these format specifications, seethe reference guide for theFormat Specification Mini-Language.
7.1.2.The String format() Method¶
Basic usage of thestr.format()
method looks like this:
>>>print('We are the{} who say "{}!"'.format('knights','Ni'))We are the knights who say "Ni!"
The brackets and characters within them (called format fields) are replaced withthe objects passed into thestr.format()
method. A number in thebrackets can be used to refer to the position of the object passed into thestr.format()
method.
>>>print('{0} and{1}'.format('spam','eggs'))spam and eggs>>>print('{1} and{0}'.format('spam','eggs'))eggs and spam
If keyword arguments are used in thestr.format()
method, their valuesare referred to by using the name of the argument.
>>>print('This{food} is{adjective}.'.format(...food='spam',adjective='absolutely horrible'))This spam is absolutely horrible.
Positional and keyword arguments can be arbitrarily combined:
>>>print('The story of{0},{1}, and{other}.'.format('Bill','Manfred',...other='Georg'))The story of Bill, Manfred, and Georg.
If you have a really long format string that you don’t want to split up, itwould be nice if you could reference the variables to be formatted by nameinstead of by position. This can be done by simply passing the dict and usingsquare brackets'[]'
to access the keys.
>>>table={'Sjoerd':4127,'Jack':4098,'Dcab':8637678}>>>print('Jack:{0[Jack]:d}; Sjoerd:{0[Sjoerd]:d}; '...'Dcab:{0[Dcab]:d}'.format(table))Jack: 4098; Sjoerd: 4127; Dcab: 8637678
This could also be done by passing thetable
dictionary as keyword arguments with the**
notation.
>>>table={'Sjoerd':4127,'Jack':4098,'Dcab':8637678}>>>print('Jack:{Jack:d}; Sjoerd:{Sjoerd:d}; Dcab:{Dcab:d}'.format(**table))Jack: 4098; Sjoerd: 4127; Dcab: 8637678
This is particularly useful in combination with the built-in functionvars()
, which returns a dictionary containing all local variables:
>>>table={k:str(v)fork,vinvars().items()}>>>message=" ".join([f'{k}: '+'{'+k+'};'forkintable.keys()])>>>print(message.format(**table))__name__: __main__; __doc__: None; __package__: None; __loader__: ...
As an example, the following lines produce a tidily alignedset of columns giving integers and their squares and cubes:
>>>forxinrange(1,11):...print('{0:2d}{1:3d}{2:4d}'.format(x,x*x,x*x*x))... 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 72910 100 1000
For a complete overview of string formatting withstr.format()
, seeFormat String Syntax.
7.1.3.Manual String Formatting¶
Here’s the same table of squares and cubes, formatted manually:
>>>forxinrange(1,11):...print(repr(x).rjust(2),repr(x*x).rjust(3),end=' ')...# Note use of 'end' on previous line...print(repr(x*x*x).rjust(4))... 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 72910 100 1000
(Note that the one space between each column was added by thewayprint()
works: it always adds spaces between its arguments.)
Thestr.rjust()
method of string objects right-justifies a string in afield of a given width by padding it with spaces on the left. There aresimilar methodsstr.ljust()
andstr.center()
. These methods donot write anything, they just return a new string. If the input string is toolong, they don’t truncate it, but return it unchanged; this will mess up yourcolumn lay-out but that’s usually better than the alternative, which would belying about a value. (If you really want truncation you can always add aslice operation, as inx.ljust(n)[:n]
.)
There is another method,str.zfill()
, which pads a numeric string on theleft with zeros. It understands about plus and minus signs:
>>>'12'.zfill(5)'00012'>>>'-3.14'.zfill(7)'-003.14'>>>'3.14159265359'.zfill(5)'3.14159265359'
7.1.4.Old string formatting¶
The % operator (modulo) can also be used for string formatting.Givenformat%values
(whereformat is a string),%
conversion specifications informat are replaced withzero or more elements ofvalues.This operation is commonly known as stringinterpolation. For example:
>>>importmath>>>print('The value of pi is approximately%5.3f.'%math.pi)The value of pi is approximately 3.142.
More information can be found in theprintf-style String Formatting section.
7.2.Reading and Writing Files¶
open()
returns afile object, and is most commonly used withtwo positional arguments and one keyword argument:open(filename,mode,encoding=None)
>>>f=open('workfile','w',encoding="utf-8")
The first argument is a string containing the filename. The second argument isanother string containing a few characters describing the way in which the filewill be used.mode can be'r'
when the file will only be read,'w'
for only writing (an existing file with the same name will be erased), and'a'
opens the file for appending; any data written to the file isautomatically added to the end.'r+'
opens the file for both reading andwriting. Themode argument is optional;'r'
will be assumed if it’somitted.
Normally, files are opened intext mode, that means, you read and writestrings from and to the file, which are encoded in a specificencoding.Ifencoding is not specified, the default is platform dependent(seeopen()
).Because UTF-8 is the modern de-facto standard,encoding="utf-8"
isrecommended unless you know that you need to use a different encoding.Appending a'b'
to the mode opens the file inbinary mode.Binary mode data is read and written asbytes
objects.You can not specifyencoding when opening file in binary mode.
In text mode, the default when reading is to convert platform-specific lineendings (\n
on Unix,\r\n
on Windows) to just\n
. When writing intext mode, the default is to convert occurrences of\n
back toplatform-specific line endings. This behind-the-scenes modificationto file data is fine for text files, but will corrupt binary data like that inJPEG
orEXE
files. Be very careful to use binary mode whenreading and writing such files.
It is good practice to use thewith
keyword when dealingwith file objects. The advantage is that the file is properly closedafter its suite finishes, even if an exception is raised at somepoint. Usingwith
is also much shorter than writingequivalenttry
-finally
blocks:
>>>withopen('workfile',encoding="utf-8")asf:...read_data=f.read()>>># We can check that the file has been automatically closed.>>>f.closedTrue
If you’re not using thewith
keyword, then you should callf.close()
to close the file and immediately free up any systemresources used by it.
Warning
Callingf.write()
without using thewith
keyword or callingf.close()
might result in the argumentsoff.write()
not being completely written to the disk, even if theprogram exits successfully.
After a file object is closed, either by awith
statementor by callingf.close()
, attempts to use the file object willautomatically fail.
>>>f.close()>>>f.read()Traceback (most recent call last): File"<stdin>", line1, in<module>ValueError:I/O operation on closed file.
7.2.1.Methods of File Objects¶
The rest of the examples in this section will assume that a file object calledf
has already been created.
To read a file’s contents, callf.read(size)
, which reads some quantity ofdata and returns it as a string (in text mode) or bytes object (in binary mode).size is an optional numeric argument. Whensize is omitted or negative, theentire contents of the file will be read and returned; it’s your problem if thefile is twice as large as your machine’s memory. Otherwise, at mostsizecharacters (in text mode) orsize bytes (in binary mode) are read and returned.If the end of the file has been reached,f.read()
will return an emptystring (''
).
>>>f.read()'This is the entire file.\n'>>>f.read()''
f.readline()
reads a single line from the file; a newline character (\n
)is left at the end of the string, and is only omitted on the last line of thefile if the file doesn’t end in a newline. This makes the return valueunambiguous; iff.readline()
returns an empty string, the end of the filehas been reached, while a blank line is represented by'\n'
, a stringcontaining only a single newline.
>>>f.readline()'This is the first line of the file.\n'>>>f.readline()'Second line of the file\n'>>>f.readline()''
For reading lines from a file, you can loop over the file object. This is memoryefficient, fast, and leads to simple code:
>>>forlineinf:...print(line,end='')...This is the first line of the file.Second line of the file
If you want to read all the lines of a file in a list you can also uselist(f)
orf.readlines()
.
f.write(string)
writes the contents ofstring to the file, returningthe number of characters written.
>>>f.write('This is a test\n')15
Other types of objects need to be converted – either to a string (in text mode)or a bytes object (in binary mode) – before writing them:
>>>value=('the answer',42)>>>s=str(value)# convert the tuple to string>>>f.write(s)18
f.tell()
returns an integer giving the file object’s current position in the filerepresented as number of bytes from the beginning of the file when in binary mode andan opaque number when in text mode.
To change the file object’s position, usef.seek(offset,whence)
. The position is computedfrom addingoffset to a reference point; the reference point is selected bythewhence argument. Awhence value of 0 measures from the beginningof the file, 1 uses the current file position, and 2 uses the end of the file asthe reference point.whence can be omitted and defaults to 0, using thebeginning of the file as the reference point.
>>>f=open('workfile','rb+')>>>f.write(b'0123456789abcdef')16>>>f.seek(5)# Go to the 6th byte in the file5>>>f.read(1)b'5'>>>f.seek(-3,2)# Go to the 3rd byte before the end13>>>f.read(1)b'd'
In text files (those opened without ab
in the mode string), only seeksrelative to the beginning of the file are allowed (the exception being seekingto the very file end withseek(0,2)
) and the only validoffset values arethose returned from thef.tell()
, or zero. Any otheroffset value producesundefined behaviour.
File objects have some additional methods, such asisatty()
andtruncate()
which are less frequently used; consult the LibraryReference for a complete guide to file objects.
7.2.2.Saving structured data withjson
¶
Strings can easily be written to and read from a file. Numbers take a bit moreeffort, since theread()
method only returns strings, which will have tobe passed to a function likeint()
, which takes a string like'123'
and returns its numeric value 123. When you want to save more complex datatypes like nested lists and dictionaries, parsing and serializing by handbecomes complicated.
Rather than having users constantly writing and debugging code to savecomplicated data types to files, Python allows you to use the popular datainterchange format calledJSON (JavaScript Object Notation). The standard module calledjson
can take Pythondata hierarchies, and convert them to string representations; this process iscalledserializing. Reconstructing the data from the string representationis calleddeserializing. Between serializing and deserializing, thestring representing the object may have been stored in a file or data, orsent over a network connection to some distant machine.
Note
The JSON format is commonly used by modern applications to allow for dataexchange. Many programmers are already familiar with it, which makesit a good choice for interoperability.
If you have an objectx
, you can view its JSON string representation with asimple line of code:
>>>importjson>>>x=[1,'simple','list']>>>json.dumps(x)'[1, "simple", "list"]'
Another variant of thedumps()
function, calleddump()
,simply serializes the object to atext file. So iff
is atext file object opened for writing, we can do this:
json.dump(x,f)
To decode the object again, iff
is abinary file ortext file object which has been opened for reading:
x=json.load(f)
Note
JSON files must be encoded in UTF-8. Useencoding="utf-8"
when openingJSON file as atext file for both of reading and writing.
This simple serialization technique can handle lists and dictionaries, butserializing arbitrary class instances in JSON requires a bit of extra effort.The reference for thejson
module contains an explanation of this.
See also
pickle
- the pickle module
Contrary toJSON,pickle is a protocol which allowsthe serialization of arbitrarily complex Python objects. As such, it isspecific to Python and cannot be used to communicate with applicationswritten in other languages. It is also insecure by default:deserializing pickle data coming from an untrusted source can executearbitrary code, if the data was crafted by a skilled attacker.