【问题标题】:Adding variables to dataclass from json config file从 json 配置文件向数据类添加变量
【发布时间】:2021-12-30 18:39:25
【问题描述】:

观看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)) 它会起作用,但我想更深入地了解这里的机制。有没有办法让它在没有 eval 的情况下工作?

还有这部分"solid_line" : "'___'*20 + config.lb"感觉不对。

Markdown as alternative to ANSI

【问题讨论】:

  • 如果您因缺乏明确性而投票关闭,如何就您发现不清楚的地方提供一些反馈?我可以很好地理解标题的明显意图,但不能理解实际的正文和示例代码。不是 VTC,因为我认为它可能是可以挽救的。
  • 建议。忘记 json 和配置读取。将代码最小化为您的问题。例如,硬编码一本字典,显示你正在尝试做什么。在数据类的实例上设置值?以某种方式扩展数据类?
  • 我编辑了这个问题,希望现在更清楚。感谢您关于不使用 json 和配置阅读的建议。我仍然很好奇为什么不评估字符串并且文本格式不正确。

标签: python ansi python-dataclasses python-jsons


【解决方案1】:

这是一个基本的配置系统。我不会添加输​​出,因为它需要屏幕截图,但它适用于 bash/macos。 Inspired by 和 [tip_colors_and_formatting]

来自 (https://misc.flogisoft.com/bash/tip_colors_and_formatting):

在 Bash 中,可以通过以下语法获取字符:

\e \033 \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")

【讨论】:

    【解决方案2】:

    这个字符串由一个实际的反斜杠后跟数字033等组成。

    "BOLD" : "\\033[1m",
    

    要在 ansi 终端上打开粗体,您需要一个转义字符(八进制 33),后跟 [1m。在 Python 中,您可以使用单个反斜杠编写这些转义码:"\033[1m"。在 json 文件中,您必须提供转义字符的 unicode 代码点 \u001b。如果其余的都按顺序排列,您会看到粗体字。

    "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)
    

    【讨论】:

    • 如果我使用一个反斜杠,我会收到此错误JSONDecodeError: Invalid \escape: line 13 column 15 (char 341)。我为每个suggestion添加了第二个@
    • 哦,哦,对了,忘记了。 json中的转义字符写\u001b,见here。或者如果你切换到 python 配置文件,你仍然可以写\033。 (编辑了我的答案以修复它。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 2018-02-02
    • 2018-07-04
    • 1970-01-01
    • 2022-10-05
    • 1970-01-01
    相关资源
    最近更新 更多