【问题标题】:Is there a way in the hy language to use doto on self?在 hy 语言中有没有办法在 self 上使用 doto?
【发布时间】:2015-03-09 18:43:05
【问题描述】:

希望有人可以帮助我解决这个问题。我正在将一些 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))]])

我看不到在 self 上使用 (doto) 的方法。

【问题讨论】:

    标签: hy


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

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

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

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

      (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 中使用 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提出了问题

      我们可能会向 Hy 添加一个 attach 宏。如果您想早点试用,我还发布了implementation

      用法:

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

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

      (doto self
        (.configure foo bar)
        (attach spam eggs))
      

      【讨论】:

        猜你喜欢
        • 2019-08-25
        • 1970-01-01
        • 1970-01-01
        • 2010-11-20
        • 1970-01-01
        • 2023-03-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多