コンテンツにスキップ

未翻訳のページ

このページはまだ日本語に翻訳されていないため、英語の原文を表示しています。 翻訳に協力する

tty Module Complexity

The tty module switches a Unix terminal between its line-buffered default, cbreak mode and raw mode. It is a thin layer over termios: each mode is a handful of bit operations on the seven-item attribute list that termios.tcgetattr() returns.

Every operation here is O(1). The attribute list has a fixed length, and its control-character list holds termios.NCCS entries, a constant of the platform, so nothing on this page grows with an input. The one wait is outside that bound: with TCSADRAIN or the default TCSAFLUSH, tcsetattr() does not return until output already queued for the terminal has been sent, and TCSAFLUSH also discards input that has arrived but not been read.

Complexity Reference

Changing a terminal's mode

Operation Time Space Notes
tty.setraw(fd, when=termios.TCSAFLUSH) O(1) O(1) One tcgetattr() and one tcsetattr(); also turns off signal keys and output processing
tty.setcbreak(fd, when=termios.TCSAFLUSH) O(1) O(1) One tcgetattr() and one tcsetattr(); turns off echo and line buffering, keeps signal keys and output processing
Restoring with termios.tcsetattr(fd, when, saved) O(1) O(1) saved from termios.tcgetattr(), or from the return value of setraw()/setcbreak() on 3.12.1+

Editing an attribute list

Operation Time Space Notes
tty.cfmakeraw(mode) O(1) O(1) Edits mode in place and makes no system call; 3.12+
tty.cfmakecbreak(mode) O(1) O(1) Edits mode in place and makes no system call; 3.12+

Constants

Operation Time Space Notes
tty.IFLAG, tty.OFLAG, tty.CFLAG, tty.LFLAG, tty.ISPEED, tty.OSPEED, tty.CC O(1) O(1) Indices 0 to 6 into the attribute list

Raw and Cbreak Mode

Both modes make input readable as each byte arrives, without waiting for a whole line, and without echoing it. Raw mode also turns off the keys that raise signals and the terminal's output processing, so Ctrl-C arrives as a byte rather than as KeyboardInterrupt. Save the attributes first and restore them in a finally block; the saved list is all that restoring needs.

import os
import termios
import tty

controller, terminal = os.openpty()
try:
    saved = termios.tcgetattr(terminal)       # O(1)
    try:
        tty.setcbreak(terminal)               # O(1)
        mode = termios.tcgetattr(terminal)
        assert not mode[tty.LFLAG] & (termios.ECHO | termios.ICANON)
        assert mode[tty.LFLAG] & termios.ISIG # signal keys stay on

        tty.setraw(terminal)                  # O(1)
        mode = termios.tcgetattr(terminal)
        assert not mode[tty.LFLAG] & termios.ISIG
        assert not mode[tty.OFLAG] & termios.OPOST
    finally:
        termios.tcsetattr(terminal, termios.TCSADRAIN, saved)  # O(1)
    restored = termios.tcgetattr(terminal)
    restored[tty.LFLAG] &= ~termios.PENDIN  # macOS sets it when canonical mode returns
    assert restored == saved
finally:
    os.close(terminal)
    os.close(controller)

Building a Mode Without Touching the Terminal

cfmakeraw() and cfmakecbreak() do the bit operations of setraw() and setcbreak() on a list you pass in, and return None. They make no system call, so a mode can be prepared once and applied with termios.tcsetattr() whenever it is needed.

import os
import termios
import tty

controller, terminal = os.openpty()
try:
    mode = termios.tcgetattr(terminal)
    assert tty.cfmakeraw(mode) is None        # O(1), edits mode in place
    assert not mode[tty.LFLAG] & termios.ECHO
    assert mode[tty.CC][termios.VMIN] == 1
    assert termios.tcgetattr(terminal)[tty.LFLAG] & termios.ECHO  # not applied yet

    termios.tcsetattr(terminal, termios.TCSANOW, mode)  # O(1)
    assert not termios.tcgetattr(terminal)[tty.LFLAG] & termios.ECHO
finally:
    os.close(terminal)
    os.close(controller)

Performance Best Practices

✅ Do:

  • Save the attributes once and restore them in finally: both are O(1), and a terminal left in raw mode outlives the program
  • Switch back and forth with lists prepared once by cfmakeraw() or cfmakecbreak() (3.12+): each switch is then one tcsetattr(), where setraw() and setcbreak() also read the attributes first

❌ Avoid:

  • The default TCSAFLUSH when input typed ahead matters - it is discarded; pass TCSADRAIN or TCSANOW as when
  • Restoring from the value setraw() or setcbreak() returns in code that also runs before 3.12.1 - call termios.tcgetattr() first instead

Version Notes

  • Python 3.12+: Added cfmakeraw() and cfmakecbreak(); setraw() and setcbreak() return a list instead of None
  • Python 3.12.1+: That list is the attributes the call replaced, and restores the terminal; on 3.12.0 its VMIN and VTIME entries already hold the new mode's values
  • Python 3.12.2+: setcbreak() and cfmakecbreak() leave carriage-return translation (ICRNL) as it was, which setcbreak() also does on 3.11; 3.12.0 and 3.12.1 clear it
  • termios - tcgetattr() and tcsetattr(), the calls these functions wrap
  • pty - pseudo-terminal pairs, and spawn(), which puts the caller's terminal in raw mode
  • curses - cbreak() and raw() for full-screen programs