<p>我根据ubntu的答案制作了一个简单的版本,名为<a href="https://pypi.org/project/magicattr/" rel="nofollow noreferrer">magicattr</a>,也可以通过解析和遍历ast来处理attrs、list和dict。</p>
<p>例如,对于这个类:</p>
<pre><code>class Person:
settings = {
'autosave': True,
'style': {
'height': 30,
'width': 200
},
'themes': ['light', 'dark']
}
def __init__(self, name, age, friends):
self.name = name
self.age = age
self.friends = friends
bob = Person(name="Bob", age=31, friends=[])
jill = Person(name="Jill", age=29, friends=[bob])
jack = Person(name="Jack", age=28, friends=[bob, jill])
</code></pre>
<p>你可以这么做</p>
<pre><code># Nothing new
assert magicattr.get(bob, 'age') == 31
# Lists
assert magicattr.get(jill, 'friends[0].name') == 'Bob'
assert magicattr.get(jack, 'friends[-1].age') == 29
# Dict lookups
assert magicattr.get(jack, 'settings["style"]["width"]') == 200
# Combination of lookups
assert magicattr.get(jack, 'settings["themes"][-2]') == 'light'
assert magicattr.get(jack, 'friends[-1].settings["themes"][1]') == 'dark'
# Setattr
magicattr.set(bob, 'settings["style"]["width"]', 400)
assert magicattr.get(bob, 'settings["style"]["width"]') == 400
# Nested objects
magicattr.set(bob, 'friends', [jack, jill])
assert magicattr.get(jack, 'friends[0].friends[0]') == jack
magicattr.set(jill, 'friends[0].age', 32)
assert bob.age == 32
</code></pre>
<p>它也不允许您/某人调用函数或赋值,因为它不使用eval或允许赋值/调用节点。</p>
<pre><code>with pytest.raises(ValueError) as e:
magicattr.get(bob, 'friends = [1,1]')
# Nice try, function calls are not allowed
with pytest.raises(ValueError):
magicattr.get(bob, 'friends.pop(0)')
</code></pre>