Python:是否更新具有占位符的dict字符串?

Python:是否更新具有占位符的dict字符串?,python,python-3.x,string,eval,Python,Python 3.x,String,Eval,考虑以下字符串:“{'a':a,'b':b,'c':10}”。现在我想更新这个“字符串”并添加新的键d,比如说值20,所以结果将是“{'a':a,'b':b,'c':10,'d':20}” 通常,您可以将字符串(eval或literal\u eval)求值为dict,以您想要的方式更新并将其转换回字符串。但在本例中,有一些占位符,在计算时无法识别 更新它的最佳方法是什么,以便旧值保持不变,但“dict string”已正确更新?我认为您可以: 选项1-添加 在字符串末尾的“}”前面插入新字符串“

考虑以下字符串:
“{'a':a,'b':b,'c':10}”
。现在我想更新这个“字符串”并添加新的键
d
,比如说值
20
,所以结果将是
“{'a':a,'b':b,'c':10,'d':20}”

通常,您可以将字符串(
eval
literal\u eval
)求值为dict,以您想要的方式更新并将其转换回字符串。但在本例中,有一些占位符,在计算时无法识别

更新它的最佳方法是什么,以便旧值保持不变,但“dict string”已正确更新?

我认为您可以:

选项1-添加

在字符串末尾的“}”前面插入新字符串“key:value”

选项2-用于添加/更新的RagEx

1-使用
find()
并搜索密钥。如果存在,则使用正则表达式替换:

re.replace(regex_search,regex_replace,contents)
因此,使用类似于:

string = re.sub(r'key: (.+),', 'key: value', article)


2-如果
find()

this_string = "{'a': A, 'b': B, 'c': 10}"
this_add = "'d': 20"
this_string = f"{this_string[:-1]}, {this_add}{this_string[-1]}"
print(this_string)
将输出

{'a': A, 'b': B, 'c': 10, 'd': 20}
如果需要在两者之间插入新字符串,可以使用string.find执行类似的操作,以定位索引并改用该索引号


它基本上是重写整个字符串,但字符串是不可变的。我们能做什么呢。

这绝不是最好的解决方案,但这里有一种方法:

import re

dict_str = "{'a': A, 'b': B, 'c': 10}"

def update_dict(dict_str, **keyvals):
    """creates an updated dict_str

        Parameters:
            dict_str (str): current dict_str
            **keyvals: variable amounts of key-values

        Returns:
            str:updated string

    """
    new_entries = ", ".join(map(lambda keyval: f"'{keyval[0]}': {keyval[1]}", keyvals.items())) # create a string representation for each key-value and join by ','
    return dict_str.replace("}", f", {new_entries}{'}'}")   # update the dict_str by removing the last '}' and add the new entries

输出:

updated = update_dict(dict_str,
    d = 20,
    e = 30
)
print(updated)

为了获得正确解析dict的更健壮的解决方案,您可以使用子类
lib2to3.refactor.RefactoringTool
来重构代码,该子类是
lib2to3.fixer\u base.BaseFix
的子类,具有查找
dictsetmaker
节点的模式,以及一种
transform
方法,该方法使用叶节点扩展
子项
列表,叶节点由将用于dict中新键值对的令牌组成:

from lib2to3 import fixer_base, refactor, pytree
from lib2to3.pgen2 import token

class AddKeyValue(fixer_base.BaseFix):
    PATTERN = "dictsetmaker"

    def transform(self, node, results):
        node.children.extend((
            pytree.Leaf(token.COMMA, ','),
            pytree.Leaf(token.STRING, "'d'", prefix=' '),
            pytree.Leaf(token.COLON, ':'),
            pytree.Leaf(token.NUMBER, 20, prefix=' ')
        ))
        return node

class Refactor(refactor.RefactoringTool):
    def __init__(self, fixers):
        self._fixers= [cls(None, None) for cls in fixers]
        super().__init__(None)

    def get_fixers(self):
        return self._fixers, []

s = "{'a': A, 'b': B, 'c': 10}"
print(Refactor([AddKeyValue]).refactor_string(s + '\n', ''))
这将产生:

{'a': A, 'b': B, 'c': 10, 'd': 20}
lib2to3
是往返稳定的,因此在转换后保留所有空格,如果要在新节点之前插入空格,则应使用
前缀指定新节点

您可以在
lib2to3
模块的中找到Python语法的定义


演示:

您为什么要使用字典的字符串表示法?有许多XML文件都有这种所谓的上下文(XML文件数据存储在数据库中),这是字典的字符串表示法。这样的上下文可以有占位符,这些占位符在某个点上被计算。我需要更新上下文以添加自定义密钥。如果不是placeholers,这将很容易,因为当时我不知道它们的值是什么,也不应该真正关心。这些占位符到底是什么?例如,
active\u id
,是触发打开特定XML生成视图的另一条记录的id。这个ID是动态的,这意味着它可能会不同于它被打开的位置(在系统中)。因此,当需要计算上下文时,就知道要使用什么值,但我会在计算它之前进行更新(可以编写XML文件来更新其他特定的XML数据,但有很多这样的文件,所以我认为只需找到所有需要的内容并添加自定义数据(然后通过python完成)。您的问题不清楚。请在无法使用
eval
的位置显示有问题的字符串。
{'a': A, 'b': B, 'c': 10, 'g': 2, 'h': 3}
from lib2to3 import fixer_base, refactor, pytree
from lib2to3.pgen2 import token

class AddKeyValue(fixer_base.BaseFix):
    PATTERN = "dictsetmaker"

    def transform(self, node, results):
        node.children.extend((
            pytree.Leaf(token.COMMA, ','),
            pytree.Leaf(token.STRING, "'d'", prefix=' '),
            pytree.Leaf(token.COLON, ':'),
            pytree.Leaf(token.NUMBER, 20, prefix=' ')
        ))
        return node

class Refactor(refactor.RefactoringTool):
    def __init__(self, fixers):
        self._fixers= [cls(None, None) for cls in fixers]
        super().__init__(None)

    def get_fixers(self):
        return self._fixers, []

s = "{'a': A, 'b': B, 'c': 10}"
print(Refactor([AddKeyValue]).refactor_string(s + '\n', ''))
{'a': A, 'b': B, 'c': 10, 'd': 20}