How Does print() Work in Python?

Note: For this article, I didn’t use AI for writing, generating pictures, or even suggesting ideas.


Overview:

Have you ever asked yourself how Python’s print() function works?

Yes, yes, how to use it. Everyone knows how, but figuring out the core elements will be interesting.

Short Description:

  • Python interpreter starts.
  • Create buffer of type FileIO or BufferedWriter, we will see later.
  • Create sys.stdout object:
sys.stdout = TextIOWrapper(buffer, encoding)

Enter fullscreen mode Exit fullscreen mode

TextIOWrapper works as a cover for FileIO or BufferedWriter and also includes encoding as an option (‘utf-8’, ‘ASCII’, etc).

  • The print() calls sys.stdout.write.
  • sys.stdout.write is calling its internal function written in C.
  • C code call Syscall.
  • Execution go down to the Kernel.
  • Finally, drivers.

️Let’s check out the print() definition:

The print() function has two overloads, which accept any number of values and only four named parameters: separator, end, file, and flush.

The sep parameter specifies how to join objects together.

end controls what will be at the end of the print; by default, it is “\n” (next line).

file prints the values to a stream, file, or to sys.stdout by default, but as we mentioned above, the first overload accepts the parameter of type SupportsWrite only, and in the second overload, file has a type that supports both writing and flushing (It supports writing and flushing with the write() and flush() methods).

Thus, flush cannot be true in the first overload, in case that file may not have the method flush().

What are sys.stdout and sys.stderr?:

sys.stdout: standard output stream.

sys.stderr: the standard error output stream.

They are special Python objects of type TextIOWrapper, and we can use them to print information directly through an alternative method instead of the built-in print() function.

TextIOWrapper—First Layer:

This class is the upper class of print levels, as we mention above, sys.stoud and sys.stderr are objects of TextIOWrapper class.

TextIOWrapper can have either unbuffered(FileIO) or buffered IO (BufferedWriter) object, and it depends on the variable PYTHONUNBUFFERED

hmm‼️, you’ve seen this variable before; it’s used in Docker images, where it is set like PYTHONUNBUFFERED 1.

This instructs Python to run in UNBUFFERED mode, which is recommended when using Python inside a Docker container. The reason for this is that it does not allow Python to buffer outputs; instead, it prints output directly, avoiding some complications in the Docker image when running your Python application.

Okay, when PYTHONUNBUFFERED=0 the class BufferedWriter will be utilized, and when PYTHONUNBUFFERED=1, we will use FileIO directly without any buffers, which is unbuffered I/O.

Take in mind: in most cases python uses buffered output as default, PYTHONUNBUFFERED=0

Buffered Writer—Second Layer:

This class stores many values until they reach the maximum value of the buffer, and then prints the output.
We use buffers because physical output inside OS is not a cheap operation.

It uses FileIO as inner layer, so BufferedWriter works as additional layer that let us store data and output them in chunks.

️Constructor:

  • self.buffer_size: If the buffer_size is not given, it defaults to DEFAUTL_BUFFER_SIZE = 8 * 1024.

  • _write_buff: Store data in order to print it.

  • _write_lock: We use Lock() in order to print the data in safe thread mode.

  • raw: is a write stream, type of FileIO.

️write() method:

  • Using safe lock thread, we check whether our buffer is already full, in this case we flush the output (write to the output stream).

  • Add output data to _write_buff and flush the _write_buff if it gets full.

  • Return length of added data (printed data or which will be printed).

Flush methods:

  • flush(): just execute _flush_unlocked() method with thread lock.

  • _flush_unlocked(): while loop puts the _write_buff on the write stream, and delete the first n written bytes until the write buffer get empty.

FileIO—Last Layer:

️Constructor:

File Descriptor: named as fd.
_File descriptors in Python are identifiers that represents the open files in the os kernel and are kept in a table of files. Typically, they have non-negative values. Negative results denote an error or a “no value” condition. They support a variety of file-related operations. In general, descriptors are a special approach Python uses to maintain attributes.

️write() method:

  • Write bytes b to file, return number written.

  • Only makes one system call, so not all of the data may be written. The number of bytes actually written is returned. In non-blocking mode, returns None if the write would block.

Flush method:

Simply returns None, because FileIO don’t have buffer, and it writes inside the system directly.

References:

Source
PYTHONUNBUFFERED
Buffered Writer
File Descriptor


You can also find me there 🙂

Github

Medium

原文链接:How Does print() Work in Python?

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容