Python curses是否存在与C curses中chtype字符串等效的实现?
Python curses 实现预定义带属性字符串的方案
在C curses中,我们可以通过chtype类型(通常为unsigned int)存储字符及其关联属性,预定义好带属性的字符串后,只需调用一次addchstr()就能复用,代码简洁高效。示例如下:
#include <curses.h> static const chtype hello[] = { 'H' | A_BOLD, 'e' | COLOR_PAIR(1) | A_UNDERLINE, 'l' | COLOR_PAIR(2) | A_REVERSE, 'l' | COLOR_PAIR(3) | A_ITALIC, 'o', ' ' | COLOR_PAIR(1), 'W' | COLOR_PAIR(2) | A_BOLD, 'o' | COLOR_PAIR(3) | A_STANDOUT, 'r' | A_BOLD, 'l' | COLOR_PAIR(1) | A_ITALIC | A_UNDERLINE | A_BLINK, 'd' | COLOR_PAIR(2), '!' | COLOR_PAIR(3) | A_BOLD | A_REVERSE | A_UNDERLINE | A_ITALIC, '\0' }; int main(void){ initscr(); start_color(); cbreak(); noecho(); curs_set(0); use_default_colors(); init_pair(1, COLOR_YELLOW, COLOR_BLUE); init_pair(2, COLOR_WHITE, COLOR_GREEN); init_pair(3, COLOR_RED, COLOR_CYAN); addchstr(hello); refresh(); getch(); endwin(); return 0; }
但在Python curses中,仅支持单个带属性字符的输出(如c = ord('A') | curses.A_BOLD; stdscr.addch(c)),没有直接对应addchstr()的方法,只能通过分段调用addstr()处理属性相同的子串,操作繁琐。以下是几种实现「预定义后轻松复用」的变通方案:
方案1:模拟C风格的属性字符序列,批量调用addch()
将每个带属性的字符以ord(字符) | 属性的形式存入列表,封装一个批量输出的函数,定义一次即可重复调用:
import curses # 预定义带属性的字符序列 hello = [ ord('H') | curses.A_BOLD, ord('e') | curses.color_pair(1) | curses.A_UNDERLINE, ord('l') | curses.color_pair(2) | curses.A_REVERSE, ord('l') | curses.color_pair(3) | curses.A_ITALIC, ord('o'), ord(' ') | curses.color_pair(1), ord('W') | curses.color_pair(2) | curses.A_BOLD, ord('o') | curses.color_pair(3) | curses.A_STANDOUT, ord('r') | curses.A_BOLD, ord('l') | curses.color_pair(1) | curses.A_ITALIC | curses.A_UNDERLINE | curses.A_BLINK, ord('d') | curses.color_pair(2), ord('!') | curses.color_pair(3) | curses.A_BOLD | curses.A_REVERSE | curses.A_UNDERLINE | curses.A_ITALIC, ] def add_chstr(win, ch_seq): for ch in ch_seq: win.addch(ch) def main(stdscr): curses.start_color() curses.cbreak() curses.noecho() curses.curs_set(0) curses.use_default_colors() curses.init_pair(1, curses.COLOR_YELLOW, curses.COLOR_BLUE) curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_GREEN) curses.init_pair(3, curses.COLOR_RED, curses.COLOR_CYAN) add_chstr(stdscr, hello) stdscr.refresh() stdscr.getch() if __name__ == "__main__": curses.wrapper(main)
方案2:封装「子串+属性」元组列表,批量调用addstr()
将相同属性的连续子串与属性打包成元组,存入列表后批量输出,相比逐个调用addch()能减少函数调用次数,性能更优:
import curses # 预定义(子串, 属性)元组列表 hello_parts = [ ('H', curses.A_BOLD), ('e', curses.color_pair(1) | curses.A_UNDERLINE), ('l', curses.color_pair(2) | curses.A_REVERSE), ('l', curses.color_pair(3) | curses.A_ITALIC), ('o', 0), (' ', curses.color_pair(1)), ('W', curses.color_pair(2) | curses.A_BOLD), ('o', curses.color_pair(3) | curses.A_STANDOUT), ('r', curses.A_BOLD), ('l', curses.color_pair(1) | curses.A_ITALIC | curses.A_UNDERLINE | curses.A_BLINK), ('d', curses.color_pair(2)), ('!', curses.color_pair(3) | curses.A_BOLD | curses.A_REVERSE | curses.A_UNDERLINE | curses.A_ITALIC), ] def add_attr_str(win, parts): for s, attr in parts: win.addstr(s, attr) def main(stdscr): curses.start_color() curses.cbreak() curses.noecho() curses.curs_set(0) curses.use_default_colors() curses.init_pair(1, curses.COLOR_YELLOW, curses.COLOR_BLUE) curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_GREEN) curses.init_pair(3, curses.COLOR_RED, curses.COLOR_CYAN) add_attr_str(stdscr, hello_parts) stdscr.refresh() stdscr.getch() if __name__ == "__main__": curses.wrapper(main)
方案3:自定义类封装,支持更复杂的复用场景
如果需要对带属性字符串进行更灵活的管理(如指定输出位置、修改内容等),可以封装成自定义类,实现专属的绘制方法:
import curses class AttrString: def __init__(self, parts): self.parts = parts def draw(self, win, y=0, x=0): win.move(y, x) for s, attr in self.parts: win.addstr(s, attr) # 实例化预定义的带属性字符串 hello = AttrString([ ('H', curses.A_BOLD), ('e', curses.color_pair(1) | curses.A_UNDERLINE), ('l', curses.color_pair(2) | curses.A_REVERSE), ('l', curses.color_pair(3) | curses.A_ITALIC), ('o', 0), (' ', curses.color_pair(1)), ('W', curses.color_pair(2) | curses.A_BOLD), ('o', curses.color_pair(3) | curses.A_STANDOUT), ('r', curses.A_BOLD), ('l', curses.color_pair(1) | curses.A_ITALIC | curses.A_UNDERLINE | curses.A_BLINK), ('d', curses.color_pair(2)), ('!', curses.color_pair(3) | curses.A_BOLD | curses.A_REVERSE | curses.A_UNDERLINE | curses.A_ITALIC), ]) def main(stdscr): curses.start_color() curses.cbreak() curses.noecho() curses.curs_set(0) curses.use_default_colors() curses.init_pair(1, curses.COLOR_YELLOW, curses.COLOR_BLUE) curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_GREEN) curses.init_pair(3, curses.COLOR_RED, curses.COLOR_CYAN) hello.draw(stdscr) stdscr.refresh() stdscr.getch() if __name__ == "__main__": curses.wrapper(main)
以上三种方案都能实现「定义一次,多次复用」的需求,无需每次输出时重复分段调用。其中方案1最贴近C curses的原生用法,方案2兼顾简洁性与性能,方案3适合复杂场景下的扩展。
内容的提问来源于stack exchange,提问作者user21711984
相关产品推荐
相关产品推荐

