Python 访问对象属性 a la with-slots lisp

标签 python common-lisp with-statement

common-lisp可以写

(defclass thing ()
       ((x :initarg :x :accessor thing-x)
        (y :initarg :y :accessor thing-y)))

;; create foo of class thing with values (x=0,y=1)
(setq foo (make-instance 'thing :x 0 :y 1))

;; access attributes x and y in the scope defined by with-slots as
;; local variables and increment them
(with-slots (x y) foo 
    (incf x) (incf y))
;; now foo has values (x=1,y=2)

现在,在 Python3 中,我已经实现了一个数学模型,在该模型中我创建了一个变量和其他组件的字典。如果那时我需要用这些变量写一些数学表达式,在创建模型之后,我必须写类似的东西

model.expr1 = model.var1 + data.coef2 * model.var2 ....

当然,var1...varn 有更长的更具描述性的名称。

为了提高可读性我想要一些东西

with ModelSlots(model) as (var1, var2, ... varn):
    model.expr1 = var1 + data.coef2 * var2 ...
    ...

据我了解,每个上下文管理器只返回一个对象,因此上面的解决方案应该是不可能的。

你知道如何在 python 中实现它吗?

当然,最明显的解决办法是

var1 = model.var1
var2 = model.var2
...

但这很冗长,难以阅读,使上下文更加困惑,并且还可能导致模糊的错误,因为我可能会无意中将一些局部 var 变量初始化为错误的值。

每个变量都有多个上下文管理器

with Var1(model) as var1:
    with Var2(model) as var2:
      ...

也不是解决方案,因为我可以在同一范围内使用多个变量,我可能想快速更改或添加新变量。必须为它们中的每一个定义一个上下文管理器会太麻烦。

TIA

编辑1

评论 Felix 解决方案。插槽的排序/匹配可以通过以下方式解决:

from bunch import Bunch

class ModelSlots:

def __init__(self, model, *slots):
    self._model = model
    self._slots = list(map(lambda x: getattr(model,x), slots))

def __enter__(self):
    return self._slots

def __exit__(self, *args):
    pass


if __name__ == '__main__':
    model = Bunch()
    model.foo = 1
    model.bar = 2
    with ModelSlots(model, "bar", "foo") as (bar,foo):
        print((foo, bar))
# prints (1,2)

但是你需要重复插槽的名称两次,带引号和不带引号......

最佳答案

Python 支持元组解包,即使在 with 语句中也是如此。请参阅下面的实际操作:

class ModelSlots:

    def __init__(self, model):
        self._model = model

    def __enter__(self):
        return self._model.values()

    def __exit__(self, *args):
        pass


if __name__ == '__main__':
    model = {"foo": 1, "bar": 2}
    with ModelSlots(model) as (foo, bar):
        print(foo + bar)
        # prints 3

这是你要的吗?

我不确定这在总体上是否是个好主意。 with 语句中的名称 foobar 与模型中的变量名称无关,因此很容易意外混淆它们(例如通过更改它们的顺序) .这可能会导致非常微妙的错误。

总而言之,我认为它“有点”可能,但根据您的应用程序可能会很危险。

关于Python 访问对象属性 a la with-slots lisp,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53776132/

相关文章:

emacs - 是什么让您想学习 Common Lisp?你想从中得到什么?

functional-programming - 我在我的 Lisp 程序中收到的警告很少,但我不知道如何解决它们

sql - 从在 DB2 中使用 WITH 子句的 Select 查询插入故事

sql - WITH 是否创建一个临时表,如果可以,它可以安全地用于多个线程吗?

python - AWS SAM : Unable to unmarshal input

mongodb - 在 cl-mongo 中实现 MongoDB SASL 身份验证

python - 在 Python 3 中读取 MP3

python - 写入文件时的奇怪行为

python - Flask URL 变量类型无?

python - 神经网络关于输入的导数