Cara menggunakan python print multiple characters
Fungsi print() digunakan untuk mencetak ouput program di layar. Ada beberapa teknik dalam menulis output program di python. Show
Menggunakan fungsi dasar print()Contoh Print("hello ngodingdata") Bisa juga disimpan di variabel hello = "hello ngodingdata" print(hello) Ketika ingin mencetak string dan variabel dalam satu statement dapat menggunakan penguhubung + nama = "faqih" print("halo, Selamat pagi "+nama) Mencetak output dengan metode formatAda teknik lain untuk mencetak hasil program dengan metode format. Dengan teknik ini memudahkan dalam mencetak yang terdiri dari beberapa variabel Nilai variabel di fungsi print() ditulis {} sehingga dapat dipisahkan antara string dan variabel Contohnya begini nama = "faqih" print("selamat pagi {}".format(nama)) Teknik ini lebih memudahkan programmer dalam mencetak statement dalam satu baris dibandingkan dengan metode yang pertama yaitu memisahkan string dan variabel dengan simbol + Misalnya begini.. Di dalam suatu kelas terdapat 4 anak yang mempunyai nilai matakuliah yang berbeda-beda toni = 100 rani = 87 jaka = 90 diah = 69 Kalau ingin dicetak dengan metode pertama di python adalah sebagai berikut print("nilai toni = "+str(toni)+ " dan nilai rani = " +str(rani)+ \ " dan nilai jaka = " +str(jaka)+ " dan nilai diah = "+str(diah)) Sedangkan kalau dicetak dengan metode format adalah seperti ini print("nilai toni = {} dan nilai rani = {} dan nilai jaka = {} dan nilai diah = {}" \ .format(toni, rani, jaka, diah)) Kedua kode diatas sama-sama menghasilkan ouput $ python cetak.py nilai toni = 100 dan nilai rani = 87 dan nilai jaka = 90 dan nilai diah = 69 Mana yang anda pilih? Ada teknik lain untuk memanipulasi agar saat mencetak statement dalam satu baris tapi di kode python tetap memanggil fungsi print() beberapa kali Tekniknya adalah dengan men-disable newline karena default fungsi print() di akhir statement adalah newline Caranya adalah dengan mengkosongkan string di akhir statement dengan keyword end print("nilai toni = "+str(toni), end='') print(" dan nilai rani = "+str(rani), end='') print(" dan nilai jaka = "+str(jaka), end='') print(" dan nilai diah = "+str(diah)) Mencetak ouput dengan f-stringMetode f-string diperkenalkan di python 3.6 Caranya adalah menambah karakter “f” di awal fungsi print() Teknik ini memperbaiki metode format agar lebih mudah dan efisien digunakan Contoh mencetak dengan metode format nama = "faqih" print("selamat pagi {}".format(nama)) Contoh case yang sama dicetak dengan f-string hello = "hello ngodingdata" print(hello)0 Jadi variabel akan ditulis beriringan dengan string di dalam { } tanpa harus memisah antara string dan variabel dengan simbol – simbol yang rumit Berdasarkan case diatas, kode print() untuk mencetak ouput di layar dapat ditulis sebagai berikut untuk menghasilkan output yang sama If you’re like most Python users, including me, then you probably started your Python journey by learning about 94. It helped you write your very own 95 one-liner. You can use it to display formatted messages onto the screen and perhaps find some bugs. But if you think that’s all there is to know about Python’s 94 function, then you’re missing out on a lot!Keep reading to take full advantage of this seemingly boring and unappreciated little function. This tutorial will get you up to speed with using Python 94 effectively. However, prepare for a deep dive as you go through the sections. You may be surprised how much 94 has to offer!By the end of this tutorial, you’ll know how to:
If you’re a complete beginner, then you’ll benefit most from reading the first part of this tutorial, which illustrates the essentials of printing in Python. Otherwise, feel free to skip that part and jump around as you see fit. Note: 94 was a major addition to Python 3, in which it replaced the old 02 statement available in Python 2.There were a number of good reasons for that, as you’ll see shortly. Although this tutorial focuses on Python 3, it does show the old way of printing in Python for reference. Free Bonus: Click here to get our free Python Cheat Sheet that shows you the basics of Python 3, like working with data types, dictionaries, lists, and Python functions. Printing in a NutshellLet’s jump in by looking at a few real-life examples of printing in Python. By the end of this section, you’ll know every possible way of calling 94. Or, in programmer lingo, you’d say you’ll be familiar with the function signature.Remove adsCalling >>> import os >>> os.linesep '\r\n' 94The simplest example of using Python 94 requires just a few keystrokes:>>>
You don’t pass any arguments, but you still need to put empty parentheses at the end, which tell Python to actually execute the function rather than just refer to it by name. This will produce an invisible newline character, which in turn will cause a blank line to appear on your screen. You can call 94 multiple times like this to add vertical space. It’s just as if you were hitting Enter on your keyboard in a word processor.Newline CharacterShow/Hide A newline character is a special control character used to indicate the end of a line (EOL). It usually doesn’t have a visible representation on the screen, but some text editors can display such non-printable characters with little graphics. The word “character” is somewhat of a misnomer in this case, because a newline is often more than one character long. For example, the Windows operating system, as well as the HTTP protocol, represent newlines with a pair of characters. Sometimes you need to take those differences into account to design truly portable programs. To find out what constitutes a newline in your operating system, use Python’s built-in 07 module.This will immediately tell you that Windows and DOS represent the newline as a sequence of 08 followed by 09:>>>
On Unix, Linux, and recent versions of macOS, it’s a single 09 character:>>>
The classic Mac OS X, however, sticks to its own “think different” philosophy by choosing yet another representation: >>>
Notice how these characters appear in string literals. They use special syntax with a preceding backslash ( 11) to denote the start of an escape character sequence. Such sequences allow for representing control characters, which would be otherwise invisible on screen.Most programming languages come with a predefined set of escape sequences for special characters such as these:
The last two are reminiscent of mechanical typewriters, which required two separate commands to insert a newline. The first command would move the carriage back to the beginning of the current line, while the second one would advance the roll to the next line. By comparing the corresponding ASCII character codes, you’ll see that putting a backslash in front of a character changes its meaning completely. However, not all characters allow for this–only the special ones. To compare ASCII character codes, you may want to use the built-in 17 function:>>>
Keep in mind that, in order to form a correct escape sequence, there must be no space between the backslash character and a letter! As you just saw, calling 94 without arguments results in a blank line, which is a line comprised solely of the newline character. Don’t confuse this with an empty line, which doesn’t contain any characters at all, not even the newline!You can use Python’s string literals to visualize these two:
The first one is one character long, whereas the second one has no content. Note: To remove the newline character from a string in Python, use its 19 method, like this:>>>
This strips any trailing whitespace from the right edge of the string of characters. In a more common scenario, you’d want to communicate some message to the end user. There are a few ways to achieve this. First, you may pass a string literal directly to 94:>>>
This will print the message verbatim onto the screen. String LiteralsShow/Hide String literals in Python can be enclosed either in single quotes ( 21) or double quotes ( 22). According to the official style guide, you should just pick one and keep using it consistently. There’s no difference, unless you need to nest one in another.For example, you can’t use double quotes for the literal and also include double quotes inside of it, because that’s ambiguous for the Python interpreter:
What you want to do is enclose the text, which contains double quotes, within single quotes:
The same trick would work the other way around: 0Alternatively, you could use escape character sequences mentioned earlier, to make Python treat those internal double quotes literally as part of the string literal: 1Escaping is fine and dandy, but it can sometimes get in the way. Specifically, when you need your string to contain relatively many backslash characters in literal form. One classic example is a file path on Windows: 2Notice how each backslash character needs to be escaped with yet another backslash. This is even more prominent with regular expressions, which quickly get convoluted due to the heavy use of special characters: 3Fortunately, you can turn off character escaping entirely with the help of raw-string literals. Simply prepend an 23 or 24 before the opening quote, and now you end up with this: 4That’s much better, isn’t it? There are a few more prefixes that give special meaning to string literals in Python, but you won’t get into them here. Lastly, you can define multi-line string literals by enclosing them between 25 or 26, which are often used as docstrings.Here’s an example: 5To prevent an initial newline, simply put the text right after the opening 26: 6You can also use a backslash to get rid of the newline: 7To remove indentation from a multi-line string, you might take advantage of the built-in 28 module:>>> 8This will take care of unindenting paragraphs for you. There are also a few other useful functions in 28 for text alignment you’d find in a word processor.Secondly, you could extract that message into its own variable with a meaningful name to enhance readability and promote code reuse: >>> 9Lastly, you could pass an expression, like string concatenation, to be evaluated before printing the result: >>> 0In fact, there are a dozen ways to format messages in Python. I highly encourage you to take a look at f-strings, introduced in Python 3.6, because they offer the most concise syntax of them all: >>> 1Moreover, f-strings will prevent you from making a common mistake, which is forgetting to type cast concatenated operands. Python is a strongly typed language, which means it won’t allow you to do this: >>> 2That’s wrong because adding numbers to strings doesn’t make sense. You need to explicitly convert the number to string first, in order to join them together: >>> 3Unless you handle such errors yourself, the Python interpreter will let you know about a problem by showing a traceback. Note: 30 is a global built-in function that converts an object into its string representation.You can call it directly on any object, for example, a number: >>> 4Built-in data types have a predefined string representation out of the box, but later in this article, you’ll find out how to provide one for your custom classes. As with any function, it doesn’t matter whether you pass a literal, a variable, or an expression. Unlike many other functions, however, 94 will accept anything regardless of its type.So far, you only looked at the string, but how about other data types? Let’s try literals of different built-in types and see what comes out: >>> 5Watch out for the 32 constant, though. Despite being used to indicate an absence of a value, it will show up as 33 rather than an empty string:>>> 6How does 94 know how to work with all these different types? Well, the short answer is that it doesn’t. It implicitly calls 30 behind the scenes to type cast any object into a string. Afterward, it treats strings in a uniform way.Later in this tutorial, you’ll learn how to use this mechanism for printing custom data types such as your classes. Okay, you’re now able to call 94 with a single argument or without any arguments. You know how to print fixed or formatted messages onto the screen. The next subsection will expand on message formatting a little bit.Syntax in Python 2Show/Hide To achieve the same result in the previous language generation, you’d normally want to drop the parentheses enclosing the text: 7That’s because 02 wasn’t a function back then, as you’ll see in the . Note, however, that in some cases parentheses in Python are redundant. It wouldn’t harm to include them as they’d just get ignored. Does that mean you should be using the 02 statement as if it were a function? Absolutely not!For example, parentheses enclosing a single expression or a literal are optional. Both instructions produce the same result in Python 2: >>> 8Round brackets are actually part of the expression rather than the 02 statement. If your expression happens to contain only one item, then it’s as if you didn’t include the brackets at all.On the other hand, putting parentheses around multiple items forms a : >>> 9This is a known source of confusion. In fact, you’d also get a tuple by appending a trailing comma to the only item surrounded by parentheses: >>> 0The bottom line is that you shouldn’t call 02 with brackets in Python 2. Although, to be completely accurate, you can work around this with the help of a 41 import, which you’ll read more about in the relevant section.Remove adsSeparating Multiple ArgumentsYou saw 94 called without any arguments to produce a blank line and then called with a single argument to display either a fixed or a formatted message.However, it turns out that this function can accept any number of positional arguments, including zero, one, or more arguments. That’s very handy in a common case of message formatting, where you’d want to join a few elements together. Positional ArgumentsShow/Hide Arguments can be passed to a function in one of several ways. One way is by explicitly naming the arguments when you’re calling the function, like this: >>> 1Since arguments can be uniquely identified by name, their order doesn’t matter. Swapping them out will still give the same result: >>> 2Conversely, arguments passed without names are identified by their position. That’s why positional arguments need to follow strictly the order imposed by the function signature: >>> 3 94 allows an thanks to the 44 parameter.Let’s have a look at this example: >>> 4 94 concatenated all four arguments passed to it, and it inserted a single space between them so that you didn’t end up with a squashed message like 46.Notice that it also took care of proper type casting by implicitly calling 30 on each argument before joining them together. If you recall from the previous subsection, a naïve concatenation may easily result in an error due to incompatible types:>>> 5Apart from accepting a variable number of positional arguments, 94 defines four named or keyword arguments, which are optional since they all have default values. You can view their brief documentation by calling 49 from the interactive interpreter.Let’s focus on 50 just for now. It stands for separator and is assigned a single space ( 51) by default. It determines the value to join elements with.It has to be either a string or 32, but the latter has the same effect as the default space:>>> 6If you wanted to suppress the separator completely, you’d have to pass an empty string ( 53) instead:>>> 7You may want 94 to join its arguments as separate lines. In that case, simply pass the escaped newline character described earlier:>>> 8A more useful example of the 50 parameter would be printing something like file paths:>>> 9Remember that the separator comes between the elements, not around them, so you need to account for that in one way or another: >>> 0Specifically, you can insert a slash character ( 56) into the first positional argument, or use an empty string as the first argument to enforce the leading slash.Note: Be careful about joining elements of a list or tuple. Doing it manually will result in a well-known 57 if at least one of the elements isn’t a string:>>> 1It’s safer to just unpack the sequence with the star operator ( 58) and let 94 handle type casting:>>> 2Unpacking is effectively the same as calling 94 with individual elements of the list.One more interesting example could be exporting data to a comma-separated values (CSV) format: >>> 3This wouldn’t handle edge cases such as escaping commas correctly, but for simple use cases, it should do. The line above would show up in your terminal window. In order to save it to a file, you’d have to redirect the output. Later in this section, you’ll see how to use 94 to write text to files straight from Python.Finally, the 50 parameter isn’t constrained to a single character only. You can join elements with strings of any length:>>> 4In the upcoming subsections, you’ll explore the remaining keyword arguments of the 94 function.Syntax in Python 2Show/Hide To print multiple elements in Python 2, you must drop the parentheses around them, just like before: >>> 5If you kept them, on the other hand, you’d be passing a single tuple element to the 02 statement:>>> 6Moreover, there’s no way of altering the default separator of joined elements in Python 2, so one workaround is to use string interpolation like so: >>> 7That was the default way of formatting strings until the 65 method got backported from Python 3.Remove adsPreventing Line BreaksSometimes you don’t want to end your message with a trailing newline so that subsequent calls to 94 will continue on the same line. Classic examples include updating the progress of a long-running operation or prompting the user for input. In the latter case, you want the user to type in the answer on the same line: 8Many programming languages expose functions similar to 94 through their standard libraries, but they let you decide whether to add a newline or not. For example, in Java and C#, you have two distinct functions, while other languages require you to explicitly append 09 at the end of a string literal.Here are a few examples of syntax in such languages: LanguageExamplePerl 69C 70C++ 71In contrast, Python’s 94 function always adds 09 without asking, because that’s what you want in most cases. To disable it, you can take advantage of yet another keyword argument, 74, which dictates what to end the line with.In terms of semantics, the 74 parameter is almost identical to the 50 one that you saw earlier:
Now you understand what’s happening under the hood when you’re calling 94 without arguments. Since you don’t provide any positional arguments to the function, there’s nothing to be joined, and so the default separator isn’t used at all. However, the default value of 74 still applies, and a blank line shows up.Note: You may be wondering why the 74 parameter has a fixed default value rather than whatever makes sense on your operating system.Well, you don’t have to worry about newline representation across different operating systems when printing, because 94 will handle the conversion automatically. Just remember to always use the 09 escape sequence in string literals.This is currently the most portable way of printing a newline character in Python: >>> 9If you were to try to forcefully print a Windows-specific newline character on a Linux machine, for example, you’d end up with broken output: >>> 0On the flip side, when you open a file for reading with 86, you don’t need to care about newline representation either. The function will translate any system-specific newline it encounters into a universal 78. At the same time, you have control over how the newlines should be treated both on input and output if you really need that.To disable the newline, you must specify an empty string through the 74 keyword argument: 1Even though these are two separate 94 calls, which can execute a long time apart, you’ll eventually see only one line. First, it’ll look like this: 2However, after the second call to 94, the same line will appear on the screen as: 3As with 50, you can use 74 to join individual pieces into a big blob of text with a custom separator. Instead of joining multiple arguments, however, it’ll append text from each function call to the same line: 4These three instructions will output a single line of text: 5You can mix the two keyword arguments: 6Not only do you get a single line of text, but all items are separated with a comma: 7There’s nothing to stop you from using the newline character with some extra padding around it: 8It would print out the following piece of text: 9As you can see, the 74 keyword argument will accept arbitrary strings.Note: Looping over lines in a text file preserves their own newline characters, which combined with the 94 function’s default behavior will result in a redundant newline character:>>> 0There are two newlines after each line of text. You want to strip one of the them, as shown earlier in this article, before printing the line: 1Alternatively, you can keep the newline in the content but suppress the one appended by 94 automatically. You’d use the 74 keyword argument to do that:>>> 2By ending a line with an empty string, you effectively disable one of the newlines. You’re getting more acquainted with printing in Python, but there’s still a lot of useful information ahead. In the upcoming subsection, you’ll learn how to intercept and redirect the 94 function’s output.Syntax in Python 2Show/Hide Preventing a line break in Python 2 requires that you append a trailing comma to the expression: 3However, that’s not ideal because it also adds an unwanted space, which would translate to 98 instead of 99 in Python 3. You can test this with the following code snippet: 4Notice there’s a space between the words 00 and 01: 5In order to get the expected result, you’d need to use one of the tricks explained later, which is either importing the 94 function from 41 or falling back to the 04 module: 6This will print the correct output without extra space: 7While using the 04 module gives you control over what gets printed to the standard output, the code becomes a little bit more cluttered.Remove adsPrinting to a FileBelieve it or not, 94 doesn’t know how to turn messages into text on your screen, and frankly it doesn’t need to. That’s a job for lower-level layers of code, which understand bytes and know how to push them around. 94 is an abstraction over these layers, providing a convenient interface that merely delegates the actual printing to a stream or file-like object. A stream can be any file on your disk, a network socket, or perhaps an in-memory buffer.In addition to this, there are three standard streams provided by the operating system:
Standard StreamsShow/Hide Standard output is what you see in the terminal when you run various command-line programs including your own Python scripts: 8Unless otherwise instructed, 94 will default to writing to standard output. However, you can tell your operating system to temporarily swap out 09 for a file stream, so that any output ends up in that file rather than the screen: 9That’s called stream redirection. The standard error is similar to 09 in that it also shows up on the screen. Nonetheless, it’s a separate stream, whose purpose is to log error messages for diagnostics. By redirecting one or both of them, you can keep things clean.Note: To redirect 10, you need to know about file descriptors, also known as file handles.They’re arbitrary, albeit constant, numbers associated with standard streams. Below, you’ll find a summary of the file descriptors for a family of POSIX-compliant operating systems: StreamFile Descriptor 080 091 102Knowing those descriptors allows you to redirect one or more streams at a time: CommandDescription 18Redirect 09 20Redirect 10 22Redirect 09 and 10 to separate files 25Redirect 09 and 10 to the same fileNote that 28 is the same as 29.Some programs use different coloring to distinguish between messages printed to 09 and 10:While both 09 and 10 are write-only, 08 is read-only. You can think of standard input as your keyboard, but just like with the other two, you can swap out 08 for a file to read data from.In Python, you can access all standard streams through the built-in 04 module:>>> 0As you can see, these predefined values resemble file-like objects with 37 and 38 attributes as well as 39 and 40 methods among many others.By default, 94 is bound to 42 through its 43 argument, but you can change that. Use that keyword argument to indicate a file that was open in write or append mode, so that messages go straight to it: 1This will make your code immune to stream redirection at the operating system level, which might or might not be desired. For more information on working with files in Python, you can check out Reading and Writing Files in Python (Guide). Note: Don’t try using 94 for writing binary data as it’s only well suited for text.Just call the binary file’s 40 directly: 2If you wanted to write raw bytes on the standard output, then this will fail too because 42 is a character stream:>>> 3You must dig deeper to get a handle of the underlying byte stream instead: >>> 4This prints an uppercase letter 47 and a newline character, which correspond to decimal values of 65 and 10 in ASCII. However, they’re encoded using hexadecimal notation in the bytes literal.Note that 94 has no control over character encoding. It’s the stream’s responsibility to encode received Unicode strings into bytes correctly. In most cases, you won’t set the encoding yourself, because the default UTF-8 is what you want. If you really need to, perhaps for legacy systems, you can use the 38 argument of 86: 5Instead of a real file existing somewhere in your file system, you can provide a fake one, which would reside in your computer’s memory. You’ll use this technique later for mocking 94 in unit tests:>>> 6If you got to this point, then you’re left with only one keyword argument in 94, which you’ll see in the next subsection. It’s probably the least used of them all. Nevertheless, there are times when it’s absolutely necessary.Syntax in Python 2Show/Hide There’s a special syntax in Python 2 for replacing the default 42 with a custom file in the 02 statement: 7Because strings and bytes are represented with the same 55 type in Python 2, the 02 statement can handle binary data just fine: 8Although, there’s a problem with character encoding. The 86 function in Python 2 lacks the 38 parameter, which would often result in the dreadful 59:>>> 9Notice how non-Latin characters must be escaped in both Unicode and string literals to avoid a syntax error. Take a look at this example: 0Alternatively, you could specify source code encoding according to PEP 263 at the top of the file, but that wasn’t the best practice due to portability issues: 1Your best bet is to encode the Unicode string just before printing it. You can do this manually: 2However, a more convenient option is to use the built-in 60 module: 3It’ll take care of making appropriate conversions when you need to read or write files. Remove adsBuffering >>> import os >>> os.linesep '\r\n' 94 CallsIn the previous subsection, you learned that 94 delegates printing to a file-like object such as 42. Some streams, however, buffer certain I/O operations to enhance performance, which can get in the way. Let’s take a look at an example.Imagine you were writing a countdown timer, which should append the remaining time to the same line every second: 4Your first attempt may look something like this: 5As long as the 64 variable is greater than zero, the code keeps appending text without a trailing newline and then goes to sleep for one second. Finally, when the countdown is finished, it prints 65 and terminates the line.Unexpectedly, instead of counting down every second, the program idles wastefully for three seconds, and then suddenly prints the entire line at once: That’s because the operating system buffers subsequent writes to the standard output in this case. You need to know that there are three kinds of streams with respect to buffering:
Unbuffered is self-explanatory, that is, no buffering is taking place, and all writes have immediate effect. A line-buffered stream waits before firing any I/O calls until a line break appears somewhere in the buffer, whereas a block-buffered one simply allows the buffer to fill up to a certain size regardless of its content. Standard output is both line-buffered and block-buffered, depending on which event comes first. Buffering helps to reduce the number of expensive I/O calls. Think about sending messages over a high-latency network, for example. When you connect to a remote server to execute commands over the SSH protocol, each of your keystrokes may actually produce an individual data packet, which is orders of magnitude bigger than its payload. What an overhead! It would make sense to wait until at least a few characters are typed and then send them together. That’s where buffering steps in. On the other hand, buffering can sometimes have undesired effects as you just saw with the countdown example. To fix it, you can simply tell 94 to forcefully flush the stream without waiting for a newline character in the buffer using its 67 flag: 6That’s all. Your countdown should work as expected now, but don’t take my word for it. Go ahead and test it to see the difference. Congratulations! At this point, you’ve seen examples of calling 94 that cover all of its parameters. You know their purpose and when to use them. Understanding the signature is only the beginning, however. In the upcoming sections, you’ll see why.Syntax in Python 2Show/Hide There isn’t an easy way to flush the stream in Python 2, because the 02 statement doesn’t allow for it by itself. You need to get a handle of its lower-level layer, which is the standard output, and call it directly: 7Alternatively, you could disable buffering of the standard streams either by providing the 70 flag to the Python interpreter or by setting up the 71 environment variable: 8Note that 94 was backported to Python 2 and made available through the 41 module. Unfortunately, it doesn’t come with the 67 parameter:>>> 9What you’re seeing here is a docstring of the 94 function. You can display docstrings of various objects in Python using the built-in 76 function.Printing Custom Data TypesUp until now, you only dealt with built-in data types such as strings and numbers, but you’ll often want to print your own abstract data types. Let’s have a look at different ways of defining them. For simple objects without any logic, whose purpose is to carry data, you’ll typically take advantage of 77, which is available in the standard library. Named tuples have a neat textual representation out of the box:>>> 0That’s great as long as holding data is enough, but in order to add behaviors to the 78 type, you’ll eventually need to define a class. Take a look at this example: 1If you now create an instance of the 78 class and try to print it, you’ll get this bizarre output, which is quite different from the equivalent 77:>>> 2It’s the default representation of objects, which comprises their address in memory, the corresponding class name and a module in which they were defined. You’ll fix that in a bit, but just for the record, as a quick workaround you could combine 77 and a custom class through inheritance: 3Your 78 class has just become a specialized kind of 77 with two attributes, which you can customize.Note: In Python 3, the 84 statement can be replaced with the ellipsis ( 85) literal to indicate a placeholder: 4This prevents the interpreter from raising 86 due to missing indented block of code.That’s better than a plain 77, because not only do you get printing right for free, but you can also add custom methods and properties to the class. However, it solves one problem while introducing another. Remember that tuples, including named tuples, are immutable in Python, so they can’t change their values once created.It’s true that designing immutable data types is desirable, but in many cases, you’ll want them to allow for change, so you’re back with regular classes again. Note: Following other languages and frameworks, Python 3.7 introduced data classes, which you can think of as mutable tuples. This way, you get the best of both worlds: >>> 5The syntax for variable annotations, which is required to specify class fields with their corresponding types, was defined in Python 3.6. From earlier subsections, you already know that 94 implicitly calls the built-in 30 function to convert its positional arguments into strings. Indeed, calling 30 manually against an instance of the regular 78 class yields the same result as printing it:>>> 6 30, in turn, looks for one of two magic methods within the class body, which you typically implement. If it doesn’t find one, then it falls back to the ugly default representation. Those magic methods are, in order of search:
The first one is recommended to return a short, human-readable text, which includes information from the most relevant attributes. After all, you don’t want to expose sensitive data, such as user passwords, when printing objects. However, the other one should provide complete information about an object, to allow for restoring its state from a string. Ideally, it should return valid Python code, so that you can pass it directly to 95:>>> 7Notice the use of another built-in function, 96, which always tries to call 97 in an object, but falls back to the default representation if it doesn’t find that method.Note: Even though 94 itself uses 30 for type casting, some compound data types delegate that call to 96 on their members. This happens to lists and tuples, for example.Consider this class with both magic methods, which return alternative string representations of the same object: 8If you print a single object of the 01 class, then you won’t see the password, because 02 will call 03, which eventually will invoke 04:>>> 9However, if you put the same 05 variable inside a list by wrapping it in square brackets, then the password will become clearly visible:>>> 00That’s because sequences, such as lists and tuples, implement their 06 method so that all of their elements are first converted with 96.Python gives you a lot of freedom when it comes to defining your own data types if none of the built-in ones meet your needs. Some of them, such as named tuples and data classes, offer string representations that look good without requiring any work on your part. Still, for the most flexibility, you’ll have to define a class and override its magic methods described above. Syntax in Python 2Show/Hide The semantics of 06 and 97 didn’t change since Python 2, but you must remember that strings were nothing more than glorified byte arrays back then. To convert your objects into proper Unicode, which was a separate data type, you’d have to provide yet another magic method: 10.Here’s an example of the same 01 class in Python 2: 01As you can see, this implementation delegates some work to avoid duplication by calling the built-in 12 function on itself.Both 06 and 97 methods must return strings, so they encode Unicode characters into specific byte representations called character sets. UTF-8 is the most widespread and safest encoding, while 15 is a special constant to express funky characters, such as 16, as escape sequences in plain ASCII, such as 17.The 02 statement is looking for the magic 06 method in the class, so the chosen charset must correspond to the one used by the terminal. For example, default encoding in DOS and Windows is CP 852 rather than UTF-8, so running this can result in a 59 or even garbled output:>>> 02However, if you ran the same code on a system with UTF-8 encoding, then you’d get the proper spelling of a popular Russian name: >>> 03It’s recommended to convert strings to Unicode as early as possible, for example, when you’re reading data from a file, and use it consistently everywhere in your code. At the same time, you should encode Unicode back to the chosen character set right before presenting it to the user. It seems as if you have more control over string representation of objects in Python 2 because there’s no magic 10 method in Python 3 anymore. You may be asking yourself if it’s possible to convert an object to its byte string representation rather than a Unicode string in Python 3. It’s possible, with a special 22 method that does just that:>>> 04Using the built-in 23 function on an instance delegates the call to its 24 method defined in the corresponding class.Remove adsUnderstanding Python >>> import os >>> os.linesep '\r\n' 94You know how to use 94 quite well at this point, but knowing what it is will allow you to use it even more effectively and consciously. After reading this section, you’ll understand how printing in Python has improved over the years.Print Is a Function in Python 3You’ve seen that 94 is a function in Python 3. More specifically, it’s a built-in function, which means that you don’t need to import it from anywhere:>>> 05It’s always available in the global namespace so that you can call it directly, but you can also access it through a module from the standard library: >>> 06This way, you can avoid name collisions with custom functions. Let’s say you wanted to redefine 94 so that it doesn’t append a trailing newline. At the same time, you wanted to rename the original function to something like 29:>>> 07Now you have two separate printing functions just like in the Java programming language. You’ll define custom 94 functions in the later as well. Also, note that you wouldn’t be able to overwrite 94 in the first place if it wasn’t a function.On the other hand, 94 isn’t a function in the mathematical sense, because it doesn’t return any meaningful value other than the implicit 32:>>> 08Such functions are, in fact, procedures or subroutines that you call to achieve some kind of side-effect, which ultimately is a change of a global state. In the case of 94, that side-effect is showing a message on the standard output or writing to a file.Because 94 is a function, it has a well-defined signature with known attributes. You can quickly find its documentation using the editor of your choice, without having to remember some weird syntax for performing a certain task.Besides, functions are easier to extend. Adding a new feature to a function is as easy as adding another keyword argument, whereas changing the language to support that new feature is much more cumbersome. Think of stream redirection or buffer flushing, for example. Another benefit of 94 being a function is composability. Functions are so-called first-class objects or first-class citizens in Python, which is a fancy way of saying they’re values just like strings or numbers. This way, you can assign a function to a variable, pass it to another function, or even return one from another. 94 isn’t different in this regard. For instance, you can take advantage of it for dependency injection: 09Here, the 38 parameter lets you inject a callback function, which defaults to 94 but can be any callable. In this example, printing is completely disabled by substituting 94 with a dummy function that does nothing.Note: A dependency is any piece of code required by another bit of code. Dependency injection is a technique used in code design to make it more testable, reusable, and open for extension. You can achieve it by referring to dependencies indirectly through abstract interfaces and by providing them in a push rather than pull fashion. There’s a funny explanation of dependency injection circulating on the Internet:
Composition allows you to combine a few functions into a new one of the same kind. Let’s see this in action by specifying a custom 41 function that prints to the standard error stream and prefixes all messages with a given log level:>>> 10This custom function uses partial functions to achieve the desired effect. It’s an advanced concept borrowed from the functional programming paradigm, so you don’t need to go too deep into that topic for now. However, if you’re interested in this topic, I recommend taking a look at the 42 module.Unlike statements, functions are values. That means you can mix them with expressions, in particular, lambda expressions. Instead of defining a full-blown function to replace 94 with, you can make an anonymous lambda expression that calls it:>>> 11However, because a lambda expression is defined in place, there’s no way of referring to it elsewhere in the code. Note: In Python, you can’t put statements, such as assignments, conditional statements, loops, and so on, in an anonymous lambda function. It has to be a single expression! Another kind of expression is a ternary conditional expression: >>> 12Python has both conditional statements and . The latter is evaluated to a single value that can be assigned to a variable or passed to a function. In the example above, you’re interested in the side-effect rather than the value, which evaluates to 32, so you simply ignore it.As you can see, functions allow for an elegant and extensible solution, which is consistent with the rest of the language. In the next subsection, you’ll discover how not having 94 as a function caused a lot of headaches.Remove ads>>> import os >>> os.linesep '\n' 02 Was a Statement in Python 2A statement is an instruction that may evoke a side-effect when executed but never evaluates to a value. In other words, you wouldn’t be able to print a statement or assign it to a variable like this: 13That’s a syntax error in Python 2. Here are a few more examples of statements in Python:
Note: Python 3.8 brings a controversial walrus operator ( 51), which is an assignment expression. With it, you can evaluate an expression and assign the result to a variable at the same time, even within another expression!Take a look at this example, which calls an expensive function once and then reuses the result for further computation: 14This is useful for simplifying the code without losing its efficiency. Typically, performant code tends to be more verbose: 15The controversy behind this new piece of syntax caused a lot of argument. An abundance of negative comments and heated debates eventually led Guido van Rossum to step down from the Benevolent Dictator For Life or BDFL position. Statements are usually comprised of reserved keywords such as 48, 53, or 02 that have fixed meaning in the language. You can’t use them to name your variables or other symbols. That’s why redefining or mocking the 02 statement isn’t possible in Python 2. You’re stuck with what you get.Furthermore, you can’t print from anonymous functions, because statements aren’t accepted in lambda expressions: >>> 16The syntax of the 02 statement is ambiguous. Sometimes you can add parentheses around the message, and they’re completely optional:>>> 17At other times they change how the message is printed: >>> 18String concatenation can raise a 57 due to incompatible types, which you have to handle manually, for example:>>> 19Compare this with similar code in Python 3, which leverages sequence unpacking: >>> 20There aren’t any keyword arguments for common tasks such as flushing the buffer or stream redirection. You need to remember the quirky syntax instead. Even the built-in 76 function isn’t that helpful with regards to the 02 statement:>>> 21Trailing newline removal doesn’t work quite right, because it adds an unwanted space. You can’t compose multiple 02 statements together, and, on top of that, you have to be extra diligent about character encoding.The list of problems goes on and on. If you’re curious, you can jump back to the and look for more detailed explanations of the syntax in Python 2. However, you can mitigate some of those problems with a much simpler approach. It turns out the 94 function was backported to ease the migration to Python 3. You can import it from a special 41 module, which exposes a selection of language features released in later Python versions.Note: You may import future functions as well as baked-in language constructs such as the 63 statement.To find out exactly what features are available to you, inspect the module: >>> 22You could also call 64, but that would show a lot of uninteresting internal details of the module.To enable the 94 function in Python 2, you need to add this import statement at the beginning of your source code: 23From now on the 02 statement is no longer available, but you have the 94 function at your disposal. Note that it isn’t the same function like the one in Python 3, because it’s missing the 67 keyword argument, but the rest of the arguments are the same.Other than that, it doesn’t spare you from managing character encodings properly. Here’s an example of calling the 94 function in Python 2:>>> 24You now have an idea of how printing in Python evolved and, most importantly, understand why these backward-incompatible changes were necessary. Knowing this will surely help you become a better Python programmer. Remove adsPrinting With StyleIf you thought that printing was only about lighting pixels up on the screen, then technically you’d be right. However, there are ways to make it look cool. In this section, you’ll find out how to format complex data structures, add colors and other decorations, build interfaces, use animation, and even play sounds with text! Pretty-Printing Nested Data StructuresComputer languages allow you to represent data as well as executable code in a structured way. Unlike Python, however, most languages give you a lot of freedom in using whitespace and formatting. This can be useful, for example in compression, but it sometimes leads to less readable code. Pretty-printing is about making a piece of data or code look more appealing to the human eye so that it can be understood more easily. This is done by indenting certain lines, inserting newlines, reordering elements, and so forth. Python comes with the 70 module in its standard library, which will help you in pretty-printing large data structures that don’t fit on a single line. Because it prints in a more human-friendly way, many popular REPL tools, including JupyterLab and IPython, use it by default in place of the regular 94 function.Note: To toggle pretty printing in IPython, issue the following command: >>> 25This is an example of Magic in IPython. There are a lot of built-in commands that start with a percent sign ( 72), but you can find more on PyPI, or even create your own.If you don’t care about not having access to the original 94 function, then you can replace it with 74 in your code using import renaming:>>> 26Personally, I like to have both functions at my fingertips, so I’d rather use something like 75 as a short alias: 27At first glance, there’s hardly any difference between the two functions, and in some cases there’s virtually none: >>> 28That’s because 74 calls 96 instead of the usual 30 for type casting, so that you may evaluate its output as Python code if you want to. The differences become apparent as you start feeding it more complex data structures:>>> 29The function applies reasonable formatting to improve readability, but you can customize it even further with a couple of parameters. For example, you may limit a deeply nested hierarchy by showing an ellipsis below a given level: >>> 30The ordinary 94 also uses ellipses but for displaying recursive data structures, which form a cycle, to avoid stack overflow error:>>> 31However, 74 is more explicit about it by including the unique identity of a self-referencing object:>>> 32The last element in the list is the same object as the entire list. Note: Recursive or very large data sets can be dealt with using the 81 module as well:>>> 33This module supports most of the built-in types and is used by the Python debugger. 74 automatically sorts dictionary keys for you before printing, which allows for consistent comparison. When you’re comparing strings, you often don’t care about a particular order of serialized attributes. Anyways, it’s always best to compare actual dictionaries before serialization.Dictionaries often represent JSON data, which is widely used on the Internet. To correctly serialize a dictionary into a valid JSON-formatted string, you can take advantage of the 83 module. It too has pretty-printing capabilities:>>> 34Notice, however, that you need to handle printing yourself, because it’s not something you’d typically want to do. Similarly, the 70 module has an additional 85 function that returns a string, in case you had to do something other than printing it.Surprisingly, the signature of 74 is nothing like the 94 function’s one. You can’t even pass more than one positional argument, which shows how much it focuses on printing data structures.Remove adsAdding Colors With ANSI Escape SequencesAs personal computers got more sophisticated, they had better graphics and could display more colors. However, different vendors had their own idea about the API design for controlling it. That changed a few decades ago when people at the American National Standards Institute decided to unify it by defining ANSI escape codes. Most of today’s terminal emulators support this standard to some degree. Until recently, the Windows operating system was a notable exception. Therefore, if you want the best portability, use the 88 library in Python. It translates ANSI codes to their appropriate counterparts in Windows while keeping them intact in other operating systems.To check if your terminal understands a subset of the ANSI escape sequences, for example, related to colors, you can try using the following command: 35My default terminal on Linux says it can display 256 distinct colors, while xterm gives me only 8. The command would return a negative number if colors were unsupported. ANSI escape sequences are like a markup language for the terminal. In HTML you work with tags, such as 89 or 90, to change how elements look in the document. These tags are mixed with your content, but they’re not visible themselves. Similarly, escape codes won’t show up in the terminal as long as it recognizes them. Otherwise, they’ll appear in the literal form as if you were viewing the source of a website.As its name implies, a sequence must begin with the non-printable Esc character, whose ASCII value is 27, sometimes denoted as 91 in hexadecimal or 92 in octal. You may use Python number literals to quickly verify it’s indeed the same number:>>> 36Additionally, you can obtain it with the 93 escape sequence in the shell: 37The most common ANSI escape sequences take the following form: ElementDescriptionExampleEscnon-printable escape character 94 95opening square bracket 95numeric codeone or more numbers separated with 97 98character codeuppercase or lowercase letter 99The numeric code can be one or more numbers separated with a semicolon, while the character code is just one letter. Their specific meaning is defined by the ANSI standard. For example, to reset all formatting, you would type one of the following commands, which use the code zero and the letter 99: 38At the other end of the spectrum, you have compound code values. To set foreground and background with RGB channels, given that your terminal supports 24-bit depth, you could provide multiple numbers: 39It’s not just text color that you can set with the ANSI escape codes. You can, for example, clear and scroll the terminal window, change its background, move the cursor around, make the text blink or decorate it with an underline. In Python, you’d probably write a helper function to allow for wrapping arbitrary codes into a sequence: >>> 40This would make the word 01 appear in red, bold, and underlined font:However, there are higher-level abstractions over ANSI escape codes, such as the mentioned 88 library, as well as tools for building user interfaces in the console.Remove adsBuilding Console User InterfacesWhile playing with ANSI escape codes is undeniably a ton of fun, in the real world you’d rather have more abstract building blocks to put together a user interface. There are a few libraries that provide such a high level of control over the terminal, but 03 seems to be the most popular choice.Note: To use the 03 library in Windows, you need to install a third-party package: 41That’s because 03 isn’t available in the standard library of the Python distribution for Windows.Primarily, it allows you to think in terms of independent graphical widgets instead of a blob of text. Besides, you get a lot of freedom in expressing your inner artist, because it’s really like painting a blank canvas. The library hides the complexities of having to deal with different terminals. Other than that, it has great support for keyboard events, which might be useful for writing video games. How about making a retro snake game? Let’s create a Python snake simulator: First, you need to import the 03 module. Since it modifies the state of a running terminal, it’s important to handle errors and gracefully restore the previous state. You can do this manually, but the library comes with a convenient wrapper for your main function: 42Note, the function must accept a reference to the screen object, also known as 07, that you’ll use later for additional setup.If you run this program now, you won’t see any effects, because it terminates immediately. However, you can add a small delay to have a sneak peek: 43This time the screen went completely blank for a second, but the cursor was still blinking. To hide it, just call one of the configuration functions defined in the module: 44Let’s define the snake as a list of points in screen coordinates: 45The head of the snake is always the first element in the list, whereas the tail is the last one. The initial shape of the snake is horizontal, starting from the top-left corner of the screen and facing to the right. While its y-coordinate stays at zero, its x-coordinate decreases from head to tail. To draw the snake, you’ll start with the head and then follow with the remaining segments. Each segment carries 08 coordinates, so you can unpack them: 46Again, if you run this code now, it won’t display anything, because you must explicitly refresh the screen afterward: 47You want to move the snake in one of four directions, which can be defined as vectors. Eventually, the direction will change in response to an arrow keystroke, so you may hook it up to the library’s key codes: 48How does a snake move? It turns out that only its head really moves to a new location, while all other segments shift towards it. In each step, almost all segments remain the same, except for the head and the tail. Assuming the snake isn’t growing, you can remove the tail and insert a new head at the beginning of the list: 49To get the new coordinates of the head, you need to add the direction vector to it. However, adding tuples in Python results in a bigger tuple instead of the algebraic sum of the corresponding vector components. One way to fix this is by using the built-in 09, 10, and 11 functions.The direction will change on a keystroke, so you need to call 12 to obtain the pressed key code. However, if the pressed key doesn’t correspond to the arrow keys defined earlier as dictionary keys, the direction won’t change: 50By default, however, 12 is a blocking call that would prevent the snake from moving unless there was a keystroke. Therefore, you need to make the call non-blocking by adding yet another configuration: 51You’re almost done, but there’s just one last thing left. If you now loop this code, the snake will appear to be growing instead of moving. That’s because you have to erase the screen explicitly before each iteration. Finally, this is all you need to play the snake game in Python: 52This is merely scratching the surface of the possibilities that the 03 module opens up. You may use it for game development like this or more business-oriented applications.Living It Up With Cool AnimationsNot only can animations make the user interface more appealing to the eye, but they also improve the overall user experience. When you provide early feedback to the user, for example, they’ll know if your program’s still working or if it’s time to kill it. To animate text in the terminal, you have to be able to freely move the cursor around. You can do this with one of the tools mentioned previously, that is ANSI escape codes or the 03 library. However, I’d like to show you an even simpler way.If the animation can be constrained to a single line of text, then you might be interested in two special escape character sequences:
The first one moves the cursor to the beginning of the line, whereas the second one moves it only one character to the left. They both work in a non-destructive way without overwriting text that’s already been written. Let’s take a look at a few examples. You’ll often want to display some kind of a spinning wheel to indicate a work in progress without knowing exactly how much time’s left to finish: Many command line tools use this trick while downloading data over the network. You can make a really simple stop motion animation from a sequence of characters that will cycle in a round-robin fashion: 53The loop gets the next character to print, then moves the cursor to the beginning of the line, and overwrites whatever there was before without adding a newline. You don’t want extra space between positional arguments, so separator argument must be blank. Also, notice the use of Python’s raw strings due to backslash characters present in the literal. When you know the remaining time or task completion percentage, then you’re able to show an animated progress bar: First, you need to calculate how many hashtags to display and how many blank spaces to insert. Next, you erase the line and build the bar from scratch: 54As before, each request for update repaints the entire line. Note: There’s a feature-rich 18 library, along with a few other similar tools, that can show progress in a much more comprehensive way.Making Sounds With >>> import os >>> os.linesep '\r\n' 94If you’re old enough to remember computers with a PC speaker, then you must also remember their distinctive beep sound, often used to indicate hardware problems. They could barely make any more noises than that, yet video games seemed so much better with it. Today you can still take advantage of this small loudspeaker, but chances are your laptop didn’t come with one. In such a case, you can enable terminal bell emulation in your shell, so that a system warning sound is played instead. Go ahead and type this command to see if your terminal can play a sound: 55This would normally print text, but the 20 flag enables the interpretation of backslash escapes. As you can see, there’s a dedicated escape sequence 21, which stands for “alert”, that outputs a special bell character. Some terminals make a sound whenever they see it.Similarly, you can print this character in Python. Perhaps in a loop to form some kind of melody. While it’s only a single note, you can still vary the length of pauses between consecutive instances. That seems like a perfect toy for Morse code playback! The rules are the following:
According to those rules, you could be “printing” an SOS signal indefinitely in the following way: 56In Python, you can implement it in merely ten lines of code: 57Maybe you could even take it one step further and make a command line tool for translating text into Morse code? Either way, I hope you’re having fun with this! Mocking Python >>> import os >>> os.linesep '\r\n' 94 in Unit TestsNowadays, it’s expected that you ship code that meets high quality standards. If you aspire to become a professional, you must learn how to test your code. Software testing is especially important in dynamically typed languages, such as Python, which don’t have a compiler to warn you about obvious mistakes. Defects can make their way to the production environment and remain dormant for a long time, until that one day when a branch of code finally gets executed. Sure, you have , type checkers, and other tools for static code analysis to assist you. But they won’t tell you whether your program does what it’s supposed to do on the business level. So, should you be testing 94? No. After all, it’s a built-in function that must have already gone through a comprehensive suite of tests. What you want to test, though, is whether your code is calling 94 at the right time with the expected parameters. That’s known as a behavior.You can test behaviors by mocking real objects or functions. In this case, you want to mock 94 to record and verify its invocations.Note: You might have heard the terms: dummy, fake, stub, spy, or mock used interchangeably. Some people make a distinction between them, while others don’t. Martin Fowler explains their differences in a short glossary and collectively calls them test doubles. Mocking in Python can be done twofold. First, you can take the traditional path of statically-typed languages by employing dependency injection. This may sometimes require you to change the code under test, which isn’t always possible if the code is defined in an external library: 58This is the same example I used in an earlier section to talk about function composition. It basically allows for substituting 94 with a custom function of the same interface. To check if it prints the right message, you have to intercept it by injecting a mocked function:>>> 59Calling this mock makes it save the last message in an attribute, which you can inspect later, for example in an 50 statement.In a slightly alternative solution, instead of replacing the entire 94 function with a custom wrapper, you could redirect the standard output to an in-memory file-like stream of characters:>>> 60This time the function explicitly calls 94, but it exposes its 43 parameter to the outside world.However, a more Pythonic way of mocking objects takes advantage of the built-in 31 module, which uses a technique called monkey patching. This derogatory name stems from it being a “dirty hack” that you can easily shoot yourself in the foot with. It’s less elegant than dependency injection but definitely quick and convenient.Note: The 31 module got absorbed by the standard library in Python 3, but before that, it was a third-party package. You had to install it separately: 61Other than that, you referred to it as 31, whereas in Python 3 it’s part of the unit testing module, so you must import from 34.What monkey patching does is alter implementation dynamically at runtime. Such a change is visible globally, so it may have unwanted consequences. In practice, however, patching only affects the code for the duration of test execution. To mock 94 in a test case, you’ll typically use the 36 decorator and specify a target for patching by referring to it with a fully qualified name, that is including the module name: 62This will automatically create the mock for you and inject it to the test function. However, you need to declare that your test function accepts a mock now. The underlying mock object has lots of useful methods and attributes for verifying behavior. Did you notice anything peculiar about that code snippet? Despite injecting a mock to the function, you’re not calling it directly, although you could. That injected mock is only used to make assertions afterward and maybe to prepare the context before running the test. In real life, mocking helps to isolate the code under test by removing dependencies such as a database connection. You rarely call mocks in a test, because that doesn’t make much sense. Rather, it’s other pieces of code that call your mock indirectly without knowing it. Here’s what that means: 63The code under test is a function that prints a greeting. Even though it’s a fairly simple function, you can’t test it easily because it doesn’t return a value. It has a side-effect. To eliminate that side-effect, you need to mock the dependency out. Patching lets you avoid making changes to the original function, which can remain agnostic about 94. It thinks it’s calling 94, but in reality, it’s calling a mock you’re in total control of.There are many reasons for testing software. One of them is looking for bugs. When you write tests, you often want to get rid of the 94 function, for example, by mocking it away. Paradoxically, however, that same function can help you find bugs during a related process of debugging you’ll read about in the next section.Syntax in Python 2Show/Hide You can’t monkey patch the 02 statement in Python 2, nor can you inject it as a dependency. However, you have a few other options:
Let’s examine them one by one. Stream redirection is almost identical to the example you saw earlier: >>> 64There are only two differences. First, the syntax for stream redirection uses chevron ( 44) instead of the 43 argument. The other difference is where 46 is defined. You can import it from a similarly named 46 module, or 48 for a faster implementation.Patching the standard output from the 04 module is exactly what it sounds like, but you need to be aware of a few gotchas: 65First of all, remember to install the 31 module as it wasn’t available in the standard library in Python 2.Secondly, the 02 statement calls the underlying 40 method on the mocked object instead of calling the object itself. That’s why you’ll run assertions against 53.Finally, a single 02 statement doesn’t always correspond to a single call to 55. In fact, you’ll see the newline character written separately.The last option you have is importing 94 from 57 and patching it: 66Again, it’s nearly identical to Python 3, but the 94 function is defined in the 59 module rather than 60.>>> import os >>> os.linesep '\r\n' 94 DebuggingIn this section, you’ll take a look at the available tools for debugging in Python, starting from a humble 94 function, through the 63 module, to a fully fledged debugger. After reading it, you’ll be able to make an educated decision about which of them is the most suitable in a given situation.Note: Debugging is the process of looking for the root causes of bugs or defects in software after they’ve been discovered, as well as taking steps to fix them. The term bug has an about the origin of its name. TracingAlso known as print debugging or caveman debugging, it’s the most basic form of debugging. While a little bit old-fashioned, it’s still powerful and has its uses. The idea is to follow the path of program execution until it stops abruptly, or gives incorrect results, to identify the exact instruction with a problem. You do that by inserting print statements with words that stand out in carefully chosen places. Take a look at this example, which manifests a rounding error: >>> 67As you can see, the function doesn’t return the expected value of 64, but now you know it’s because the sum is a little off. Tracing the state of variables at different steps of the algorithm can give you a hint where the issue is.Rounding ErrorShow/Hide In this case, the problem lies in how floating point numbers are represented in computer memory. Remember that numbers are stored in binary form. Decimal value of 64 turns out to have an infinite binary representation, which gets rounded.For more information on rounding numbers in Python, you can check out How to Round Numbers in Python. This method is simple and intuitive and will work in pretty much every programming language out there. Not to mention, it’s a great exercise in the learning process. On the other hand, once you master more advanced techniques, it’s hard to go back, because they allow you to find bugs much quicker. Tracing is a laborious manual process, which can let even more errors slip through. The build and deploy cycle takes time. Afterward, you need to remember to meticulously remove all the 94 calls you made without accidentally touching the genuine ones.Besides, it requires you to make changes in the code, which isn’t always possible. Maybe you’re debugging an application running in a remote web server or want to diagnose a problem in a post-mortem fashion. Sometimes you simply don’t have access to the standard output. That’s precisely where logging shines. LoggingLet’s pretend for a minute that you’re running an e-commerce website. One day, an angry customer makes a phone call complaining about a failed transaction and saying he lost his money. He claims to have tried purchasing a few items, but in the end, there was some cryptic error that prevented him from finishing that order. Yet, when he checked his bank account, the money was gone. You apologize sincerely and make a refund, but also don’t want this to happen again in the future. How do you debug that? If only you had some trace of what happened, ideally in the form of a chronological list of events with their context. Whenever you find yourself doing print debugging, consider turning it into permanent log messages. This may help in situations like this, when you need to analyze a problem after it happened, in an environment that you don’t have access to. There are sophisticated tools for log aggregation and searching, but at the most basic level, you can think of logs as text files. Each line conveys detailed information about an event in your system. Usually, it won’t contain personally identifying information, though, in some cases, it may be mandated by law. Here’s a breakdown of a typical log record: 68As you can see, it has a structured form. Apart from a descriptive message, there are a few customizable fields, which provide the context of an event. Here, you have the exact date and time, the log level, the logger name, and the thread name. Log levels allow you to filter messages quickly to reduce noise. If you’re looking for an error, you don’t want to see all the warnings or debug messages, for example. It’s trivial to disable or enable messages at certain log levels through the configuration, without even touching the code. With logging, you can keep your debug messages separate from the standard output. All the log messages go to the standard error stream by default, which can conveniently show up in different colors. However, you can redirect log messages to separate files, even for individual modules! Quite commonly, misconfigured logging can lead to running out of space on the server’s disk. To prevent that, you may set up log rotation, which will keep the log files for a specified duration, such as one week, or once they hit a certain size. Nevertheless, it’s always a good practice to archive older logs. Some regulations enforce that customer data be kept for as long as five years! Compared to other programming languages, logging in Python is simpler, because the 63 module is bundled with the standard library. You just import and configure it in as little as two lines of code: 69You can call functions defined at the module level, which are hooked to the root logger, but more the common practice is to obtain a dedicated logger for each of your source files: 70The advantage of using custom loggers is more fine-grain control. They’re usually named after the module they were defined in through the 68 variable.Note: There’s a somewhat related 69 module in Python, which can also log messages to the standard error stream. However, it has a narrower spectrum of applications, mostly in library code, whereas client applications should use the 63 module.That said, you can make them work together by calling 71.One last reason to switch from the 94 function to logging is thread safety. In the upcoming section, you’ll see that the former doesn’t play well with multiple threads of execution.DebuggingThe truth is that neither tracing nor logging can be considered real debugging. To do actual debugging, you need a debugger tool, which allows you to do the following:
A crude debugger that runs in the terminal, unsurprisingly named 73 for “The Python Debugger,” is distributed as part of the standard library. This makes it always available, so it may be your only choice for performing remote debugging. Perhaps that’s a good reason to get familiar with it.However, it doesn’t come with a graphical interface, so using 73 may be a bit tricky. If you can’t edit the code, you have to run it as a module and pass your script’s location: 71Otherwise, you can set up a breakpoint directly in the code, which will pause the execution of your script and drop you into the debugger. The old way of doing this required two steps: >>> 72This shows up an interactive prompt, which might look intimidating at first. However, you can still type native Python at this point to examine or modify the state of local variables. Apart from that, there’s really only a handful of debugger-specific commands that you want to use for stepping through the code. Note: It’s customary to put the two instructions for spinning up a debugger on a single line. This requires the use of a semicolon, which is rarely found in Python programs: 73While certainly not Pythonic, it stands out as a reminder to remove it after you’re done with debugging. Since Python 3.7, you can also call the built-in 75 function, which does the same thing, but in a more compact way and with some additional : 74You’re probably going to use a visual debugger integrated with a code editor for the most part. PyCharm has an excellent debugger, which boasts high performance, but you’ll find plenty of alternative IDEs with debuggers, both paid and free of charge. Debugging isn’t the proverbial silver bullet. Sometimes logging or tracing will be a better solution. For example, defects that are hard to reproduce, such as race conditions, often result from temporal coupling. When you stop at a breakpoint, that little pause in program execution may mask the problem. It’s kind of like the Heisenberg principle: you can’t measure and observe a bug at the same time. These methods aren’t mutually exclusive. They complement each other. Thread-Safe PrintingI briefly touched upon the thread safety issue before, recommending 63 over the 94 function. If you’re still reading this, then you must be comfortable with the concept of threads.Thread safety means that a piece of code can be safely shared between multiple threads of execution. The simplest strategy for ensuring thread-safety is by sharing immutable objects only. If threads can’t modify an object’s state, then there’s no risk of breaking its consistency. Another method takes advantage of local memory, which makes each thread receive its own copy of the same object. That way, other threads can’t see the changes made to it in the current thread. But that doesn’t solve the problem, does it? You often want your threads to cooperate by being able to mutate a shared resource. The most common way of synchronizing concurrent access to such a resource is by locking it. This gives exclusive write access to one or sometimes a few threads at a time. However, locking is expensive and reduces concurrent throughput, so other means for controlling access have been invented, such as atomic variables or the compare-and-swap algorithm. Printing isn’t thread-safe in Python. The 94 function holds a reference to the standard output, which is a shared global variable. In theory, because there’s no locking, a context switch could happen during a call to 55, intertwining bits of text from multiple 94 calls.Note: A context switch means that one thread halts its execution, either voluntarily or not, so that another one can take over. This might happen at any moment, even in the middle of a function call. In practice, however, that doesn’t happen. No matter how hard you try, writing to the standard output seems to be atomic. The only problem that you may sometimes observe is with messed up line breaks: 75To simulate this, you can increase the likelihood of a context switch by making the underlying 40 method go to sleep for a random amount of time. How? By mocking it, which you already know about from an earlier section: 76First, you need to store the original 40 method in a variable, which you’ll delegate to later. Then you provide your fake implementation, which will take up to one second to execute. Each thread will make a few 94 calls with its name and a letter: A, B, and C.If you read the mocking section before, then you may already have an idea of why printing misbehaves like that. Nonetheless, to make it crystal clear, you can capture values fed into your 84 function. You’ll notice that you get a slightly different sequence each time: 77Even though 55 itself is an atomic operation, a single call to the 94 function can yield more than one write. For example, line breaks are written separately from the rest of the text, and context switching takes place between those writes.Note: The atomic nature of the standard output in Python is a byproduct of the Global Interpreter Lock, which applies locking around bytecode instructions. Be aware, however, that many interpreter flavors don’t have the GIL, where multi-threaded printing requires explicit locking. You can make the newline character become an integral part of the message by handling it manually: 78This will fix the output: 79Notice, however, that the 94 function still keeps making a separate call for the empty suffix, which translates to useless 88 instruction: 80A truly thread-safe version of the 94 function could look like this: 81You can put that function in a module and import it elsewhere: 82Now, despite making two writes per each 94 request, only one thread is allowed to interact with the stream, while the rest must wait: 83I added comments to indicate how the lock is limiting access to the shared resource. Note: Even in single-threaded code, you might get caught up in a similar situation. Specifically, when you’re printing to the standard output and the standard error streams at the same time. Unless you redirect one or both of them to separate files, they’ll both share a single terminal window. Conversely, the 63 module is thread-safe by design, which is reflected by its ability to display thread names in the formatted message:>>> 84It’s another reason why you might not want to use the 94 function all the time.Python Print CounterpartsBy now, you know a lot of what there is to know about 94! The subject, however, wouldn’t be complete without talking about its counterparts a little bit. While 94 is about the output, there are functions and libraries for the input.Built-InPython comes with a built-in function for accepting input from the user, predictably called 95. It accepts data from the standard input stream, which is usually the keyboard:>>> 85The function always returns a string, so you might need to parse it accordingly: 86The prompt parameter is completely optional, so nothing will show if you skip it, but the function will still work: >>> 87Nevertheless, throwing in a descriptive call to action makes the user experience so much better. Note: To read from the standard input in Python 2, you have to call 96 instead, which is yet another built-in. Unfortunately, there’s also a misleadingly named 95 function, which does a slightly different thing.In fact, it also takes the input from the standard stream, but then it tries to evaluate it as if it was Python code. Because that’s a potential security vulnerability, this function was completely removed from Python 3, while 96 got renamed to 95.Here’s a quick comparison of the available functions and what they do: Python 2Python 3 96 95 95 03As you can tell, it’s still possible to simulate the old behavior in Python 3. Asking the user for a password with 95 is a bad idea because it’ll show up in plaintext as they’re typing it. In this case, you should be using the 05 function instead, which masks typed characters. This function is defined in a module under the same name, which is also available in the standard library:>>> 88The 06 module has another function for getting the user’s name from an environment variable:>>> 89Python’s built-in functions for handling the standard input are quite limited. At the same time, there are plenty of third-party packages, which offer much more sophisticated tools. Third-PartyThere are external Python packages out there that allow for building complex graphical interfaces specifically to collect data from the user. Some of their features include:
Demonstrating such tools is outside of the scope of this article, but you may want to try them out. I personally got to know about some of those through the Python Bytes Podcast. Here they are:
Nonetheless, it’s worth mentioning a command line tool called 11 that adds powerful line editing capabilities to your Python scripts for free. You don’t have to do anything for it to work!Let’s assume you wrote a command-line interface that understands three instructions, including one for adding numbers: 90At first glance, it seems like a typical prompt when you run it: 91But as soon as you make a mistake and want to fix it, you’ll see that none of the function keys work as expected. Hitting the Left arrow, for example, results in this instead of moving the cursor back: 92Now, you can wrap the same script with the 11 command. Not only will you get the arrow keys working, but you’ll also be able to search through the persistent history of your custom commands, use autocompletion, and edit the line with shortcuts: 93Isn’t that great? ConclusionYou’re now armed with a body of knowledge about the 94 function in Python, as well as many surrounding topics. You have a deep understanding of what it is and how it works, involving all of its key elements. Numerous examples gave you insight into its evolution from Python 2.Apart from that, you learned how to:
Now that you know all this, you can make interactive programs that communicate with users or produce data in popular file formats. You’re able to quickly diagnose problems in your code and protect yourself from them. Last but not least, you know how to implement the classic snake game. If you’re still thirsty for more information, have questions, or simply would like to share your thoughts, then feel free to reach out in the comments section below. Mark as Completed Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: The Python print() Function: Go Beyond the Basics 🐍 Python Tricks 💌 Get a short & sweet Python Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team. Send Me Python Tricks » About Bartosz Zaczyński Bartosz is a bootcamp instructor, author, and polyglot programmer in love with Python. He helps his students get into software engineering by sharing over a decade of commercial experience in the IT industry. » More about BartoszEach tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are: Aldren Joanna Mike Master Real-World Python Skills With Unlimited Access to Real Python Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas: Level Up Your Python Skills » Master Real-World Python Skills Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas: Level Up Your Python Skills » What Do You Think? Rate this article: Tweet Share Share EmailWhat’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know. Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students. and get answers to common questions in our support portal. |