2

希望有人可以帮助我解决这个问题。我正在将一些 python 代码移植到 hy,并试图弄清楚如何使用 doto 宏删除一些重复的代码。例如,看一个像这样的 python 类:

class Foo(object):
  def __init__(self, x, y, z):
      self.x = x
      self.y = y
      self.z = z

我如何将其转换为 hy 以使用 doto?

(defclass Foo [object]
  [[__init__ (fn [self x y z]
               (doto self  ;
                 (setv ...) ; What goes here? 
  ))]])

问题是看起来你通常会做这样的事情:

(defclass Foo [object]
  [[__init__ (fn [self x y z]
               (setv self.x x)
               (setv self.y y)
               (setv self.z z))]])

我看不到在自己身上使用 (doto) 的方法。

4

2 回答 2

2

这是一个有趣的想法。你可以这样做:

(doto self
  (setattr "x" x)
  (setattr "y" y)
  (setattr "z" z))

但也好不到哪里去。考虑定义一个宏:

(defmacro vars-to-attrs [obj &rest attrs]
  (let [[actions (list (map
                        (fn (a) `(setattr (str '~a) ~a))
                        attrs))]]
    `(doto ~obj ~@actions)))

然后像这样调用它:

(vars-to-attrs self x y z)

不过,这可能会更好地作为一个函数工作:

(defun vars-to-attrs-fun [obj &rest attrs]
  (for [a attrs]
    (setattr obj a (get (locals) a))))

然后这样称呼它:

(vars-to-attrs-fun self 'x 'y 'z)

或同等学历:

(vars-to-attrs-fun self "x" "y" "z")
于 2015-03-13T11:28:12.327 回答
0

如果您只想保留本地变量__init__,最简单的方法是直接.update将实例变量与本地变量一起使用。

(defclass Foo [object]
   (defn __init__ [self x y z]
     (.update (vars self) (vars))))

(顺便说一句,上面使用了我们defclass在 Github 上 Hy 版本的新语法,它不适用于当前的 PyPI 版本。[更新:它现在在当前的 PyPI 版本中])

这确实包括所有当地人,所以你会得到一个self.self,这可能是无害的,但del如果你愿意,你可以在之后。Hy 有时会生成局部变量以使语句表现得像表达式。如果您不小心,这些也可能最终出现在实例字典中。assoc您可以通过只输入您想要的名称来避免这种情况:

(assoc (vars self)
  'x x
  'y y
  'z z))

setv语法还采用任意数量的对,因此您可以改为执行以下操作:

;; new setv syntax
(setv self.x x
      self.y y
      self.z z)

在使用元组之前你几乎可以这样做:

;; works in both Hy versions
(setv (, self.x self.y self.z)
      (, x y z))

您还可以避免.update使用 a重复dict-comp,尽管这通常不会更短。

(.update (vars self) (dict-comp k (get (vars) k) [k '[x y z]]))

如果您仍然使用doto,则正确的语法是:

(doto self
    (-> (. x) (setv x))
    (-> (. y) (setv y))
    (-> (. z) (setv z)))

这确实避免了重复self,但它并不比上述替代方法短,因此doto对于这项特定工作来说是错误的工具。


更新

我为此提出了一个问题https://github.com/hylang/hy/issues/1532

我们可能会attach向 Hy. 添加一个宏。如果您想尽早尝试,我还发布了一个实现。

用法:

(defclass Foo []
  (defn __init__[self x y z]
    (attach self x y z)))

由于附件目标是第一个参数,attach因此也适用于 a->或 a doto,例如

(doto self
  (.configure foo bar)
  (attach spam eggs))
于 2016-05-12T04:03:09.630 回答