Python / PyCharm 的 __slots__ 类型注释

Alb*_*ert 5 python pycharm

如何为通过 定义的属性提供类型注释__slots__?例如对于这个类:

class DiffMatch:
  __slots__ = ["ref_seq_idx", "ref_txt", "hyp_txt", "start_time", "end_time"]

  def __repr__(self):
    return "%s(%s)" % (self.__class__.__name__, ", ".join(["%s=%r" % (a, getattr(self, a)) for a in self.__slots__]))
Run Code Online (Sandbox Code Playgroud)

(如果可能的话,在注释中兼容 Python 2(否则只有 Python 3 就可以了),并且 PyCharm 可以处理它(实际上这对我来说现在最重要)。)

Mar*_*ers 8

__slots__只告诉对象为潜在type()属性腾出空间。列表中的名称本身并不是属性。你所拥有的只是一堆描述符。没有值,因此没有类型。

因此,您需要创建实际的属性,并且这些属性具有类型注释的所有常规选项。

对于 Python 3.6 及更高版本,请使用变量类型注释

class DiffMatch:
    __slots__ = ["ref_seq_idx", "ref_txt", "hyp_txt", "start_time", "end_time"]

    ref_seq_idx: int
    # ...
Run Code Online (Sandbox Code Playgroud)

或者对于3.6之前的版本(包括Python 2),您必须在可以设置属性的方法上注释类型。否则没有真实实例属性支持。您可以为此添加一个虚拟方法:

class DiffMatch:
    __slots__ = ["ref_seq_idx", "ref_txt", "hyp_txt", "start_time", "end_time"]

    def __type_hints__(self, ref_seq_idx, ...):
        """Dummy method to annotate the instance attribute types
        # type: (int, ...) -> None
        """
        self.ref_seq_idx = ref_seq_idx
        # ...
Run Code Online (Sandbox Code Playgroud)

其中每个参数的所有类型都在文档字符串中列出。如果您__init__的类有一个方法也涉及所有属性,则不需要虚拟方法。

请注意,您无法为它们设置类默认值,这意味着您无法使用ref_seq_idx = None # type: int(Python 3.6 之前的版本)或ref_seq_idx: int = None(Python 3.6 及更高版本);__slots__名称被转换为类上的描述符对象,因此名称已经设置。

最后但并非最不重要的一点是,我会认真研究attrs来为您构建这些类型。PyCharm 2018.2 最近添加了对该库的支持,因此会自动获取类型信息:

@attr.s(slots=True)
class DiffMatch:
    ref_seq_idx = attr.ib(init=False)  # type: int
    # ...
Run Code Online (Sandbox Code Playgroud)

您将__repr__免费获得生成的方法。该init=False注释告诉attrs不要在 中包含该名称__init__,此时实例在实例化时根本不会设置该属性。