看完ArjanCodes关于数据类的视频后,
我一直在尝试从 json 配置文件向 python 数据类添加变量,以格式化 Jupyterlab 中打印函数 printT 的字体样式。
我使用 ANSI 转义符进行格式化,如果我将变量导入数据类,它就不再起作用了。打印出 ANSI 代码,而不是格式化文本。
# config.json
{
"lb" : "\n",
"solid_line" : "'___'*20 + config.lb",
"dotted_line" : "'---'*20 + config.lb",
"BOLD" : "\\033[1m",
"END" : "\\033[0m"
}
# config.py
from dataclasses import dataclass
import json
@dataclass
class PrintConfig:
lb : str
solid_line : str
dotted_line : str
BOLD : str
END : str
def read_config(config_file : str) -> PrintConfig:
with open(config_file, 'r') as file:
data = json.load(file)
return(PrintConfig(**data))
# helper.py
from config import read_config
config = read_config('config.json')
def printT(title,linebreak= True,addLine = True, lineType = config.solid_line,toDisplay = None):
'''
Prints a line break, the input text and a solid line.
Inputs:
title = as string
linebreak = True(default) or False; Adds a line break before printing the title
addLine = True(default) or False; Adds a line after printing the title
lineType = solid_line(default) or dotted_line; Defines line type
toDisplay = displays input, doesnt work with df.info(),because info executes during input
'''
if linebreak:
print(config.lb)
print(config.BOLD + title + config.END)
if addLine:
print(lineType)
if toDisplay is not None:
display(toDisplay)
# test.ipynb
from helper import printT
printT('Hello World')
\033[1mHello World\033[0m
'___'*20 + config.lb
你好世界
如果我使用 eval
if addLine: print(eval(lineType))
,它会起作用,但我想更深入地了解这里的机制。有没有办法让它在没有评估的情况下工作?
还有这部分
"solid_line" : "'___'*20 + config.lb"
感觉不对
这个字符串由一个实际的反斜杠后跟数字
033
等组成
"BOLD" : "\\033[1m",
要在 ansi 终端上打开粗体,您需要一个转义字符(八进制 33),后跟
[1m
。在 Python 中,您可以使用单个反斜杠编写这些转义码:"\033[1m"
。在 json 文件中,您必须提供转义字符 \u001b
的 unicode 代码点。如果其余的都是有序的,你会看到黑体字。
"BOLD" : "\u001b[1m",
"END" : "\u001b[0m"
至于
eval
部分,您有一个字符串,其中包含您需要评估的表达式。我假设您是这样写的,因为您首先尝试不使用双引号,例如,
"dotted_line" : '---'*20 + config.lb,
你得到了一个 json 语法错误。这并不奇怪:Json 文件是数据,而不是代码,它们不能包含表达式或变量引用。将您的配置放在您包含的 python 文件中而不是加载 json,或者将依赖项移动到代码中。或两者兼而有之。
在 python 文件中,
config.py
:
config = {
"lb": "\n",
"solid_line" : '___'*20,
...
在
helper.py
:
...
if addLine:
print(lineType + config.lb)
这是一个基本的配置系统。我不会添加输出,因为它需要屏幕截图,但它适用于 bash/macos。 灵感来自和[tip_colors_and_formatting]
来自(https://misc.flogisoft.com/bash/tip_colors_and_formatting):
在 Bash 中,可以通过以下语法获取字符:
u001b \x1B
\e
没有用,所以我继续使用 \x1B
因为它在链接的 SE 答案中有效。 \033
也有效,我检查过。
from dataclasses import dataclass
PREFIX = "\x1B["
#these aren't configurable, they are ANSI constants so probably
#not useful to put them in a config json
CODES = dict(
prefix = PREFIX,
bold = f"1",
reset = f"{PREFIX}0m",
red = "31",
green = "32",
)
@dataclass
class PrintConfig:
bold : bool = False
color : str = ""
def __post_init__(self):
# these are calculated variables, none of client code's
# business:
self.start = self.end = ""
start = ""
if self.bold:
start += CODES["bold"] + ";"
if self.color:
start += CODES[self.color.lower()] + ";"
if start:
self.end = CODES["reset"]
#add the escape prefix, then the codes and close with m
self.start = f"{CODES['prefix']}{start}".rstrip(";") + "m"
def print(self,v):
print(f"{self.start}{v}{self.end}")
normal = PrintConfig()
normal.print("Hello World")
bold = PrintConfig(bold=1)
print(f"{bold=}:")
bold.print(" Hello World")
boldred = PrintConfig(bold=1,color="red")
print(f"{boldred=}:")
boldred.print(" Hello bold red")
#this is how you would do it from json
green = PrintConfig(**dict(color="green"))
green.print(" Little Greenie")
#inspired from https://stackoverflow.com/a/287934
print("\n\ninspired by...")
CSI = "\x1B["
print(CSI+"31;40m" + "Colored Text" + CSI + "0m")
print(CSI+"1m" + "Colored Text" + CSI + "0m")