Python 标准库中的命名元组不需要类声明。您使用函数调用创建类。
=> (import [collections [namedtuple]])
=> (namedtuple 'Point3D '[x y z])
<class '__console__.Point3D'>
=> (setv Point3D _) ; Hy's repl sets _ to the previous result.
=> (Point3D 1 2 3)
Point3D(x=1, y=2, z=3)
命名元组实例是不可变的,就像普通的 Python 元组一样。你不能分配给他们。
Python 允许您在大多数对象上设置任意属性。这是在 Hy 中执行此操作的示例。
=> (setv spam (fn[]))
=> (setv spam.x 7)
=> spam.x
7
在上面的示例中,我x
在一个空函数对象上设置了一个属性。有些对象虽然没有属性 dict。您可以使用__slots__
语法自己创建此类对象。(有关其工作原理,请参阅Python 文档。)
在 Python(和 Hy)self
中,类声明中不存在,只存在于方法中,因为它是第一个参数。这就是为什么你不能分配给它。您可以setv
直接取而代之的是一个名称,但这会放入类字典中,而不是任何特定实例中。
=> (defclass Foo []
... (setv class-foo 7) ; lives in the class dict
... (defn __init__ [self foo]
... (setv self.foo foo))) ; lives in the instance dict
=> Foo.class-foo
7
=> (. (Foo 12) foo) ; the (.) form accesses attributes.
12
=> (. (Foo 12) class-foo) ; not in the instance, so look in its class
7
Hy 还没有 Python 类型注释的语法。元NamedTuple
类使用这些。__annotations__
在某些情况下,您可以通过自己创建 dict来解决此问题。
(import [collections [OrderedDict]]
[typing [NamedTuple]])
(defclass Key [NamedTuple]
(setv (get (vars) '__annotations__)
(doto (OrderedDict)
(assoc 'KEY KEY
'IDX IDX
'END END))))
这应该与 Python 一样工作
class Key(NamedTuple):
KEY: KEY
IDX: IDX
END: END
虽然它实际上编译成更像
class Key(NamedTuple):
:G_1235 = OrderedDict()
:G_1235[HySymbol('KEY')] = KEY
:G_1235[HySymbol('IDX')] = IDX
:G_1235[HySymbol('END')] = END
vars()[HySymbol('__annotations__')] = :G_1235
还有其他方法可以OrderedDict
在 Hy 中创建一个,但这是最直接的方法之一。我们需要对注解 dict 进行排序,因为NamedTuple
s 是有序的。
A HySymbol
is-a Python 字符串(子类),在大多数情况下工作方式相同。这:G_1235
是一个 Hy gensym 名称。这些不是 Python 有效的标识符,但 Hy 编译为 Python 抽象语法树,并且 AST 将接受这样的名称。您可以亲自了解 Hy 如何使用 AST 本身或其近似 Python 等效项的--spy
选项或函数来编译 repl 中的内容。(disassemble ...)
您还可以NamedTuple
通过分配给您在类主体中使用 注释的名称来提供默认值setv
。
如果您使用的是 Python 3.6+(并且您将获得NamedTuple
元类),那么您可以使用 kwargs 来制作OrderedDict
,因为PEP 468。不要OrderedDict
在不保证 kwargs 顺序的早期版本中使用这种方式。
在海,
(defclass Foo [NamedTuple]
(setv (get (vars) '__annotations__)
(OrderedDict :name str
:ID int)
name "foo"
ID 42))
请注意,一个人setv
可以分配多对。元类将最后两对用作NamedTuple
默认值。
在repl
=> (Foo)
Foo(name='foo', ID=42)
=> (Foo "bar")
Foo(name='bar', ID=42)
=> _.ID
42