如何记录鸭子类型?
我的文档臃肿,因为每当我遇到复杂的鸭子类型时,我都需要某种方式来表达“这个鸭子类型”,但却陷入了“你的函数需要这个输入,但并不需要这个输入”的无限循环中。不记录它”,然后记录它。这会导致臃肿、重复的文档,例如:
def Foo(arg):
"""
Args:
arg: An object that supports X functionality, and Y functionality,
and can be passed to Z other functionality.
"""
# Insert code here.
def Bar(arg):
"""
Args:
arg: An object that supports X functionality, and Y functionality,
and can be passed to Z other functionality.
"""
# Insert code here.
等等,对于 Baz
、Qux
和其他函数。我需要一些更简短的方式来编写“arg
is a (type of object)”。
对于某些鸭子类型,它就像“类似字典的对象”一样简单:我们知道我们对字典的期望,因此,我们知道要传递什么。一个dict
,或者可以模仿它的东西。
我觉得 C++ 对于模板化类型也有同样的问题。 Haskell 会有它,但可以使用类型类的定义来记录它。 (注:Haskell 类!= Java/C++/Python/等中的类。)(注:我并没有真正用 Haskell 编程,所以如果这是一个蹩脚的例子,请原谅我。)
我应该走传统的 OO 路线吗?只需编写一个基类,然后在文档中说“类似这个基类的任何东西”?代码不会强制从基类派生(因为不需要从基类派生对象),并且基类本质上除了记录接口的属性之外不会添加任何值。
另一方面,我正在编写 Python 程序,并且尝试使用语言的惯用法进行编程。 (否则通常会造成伤害。)基类有利于继承功能,但是当您的基类完全抽象时,它似乎不会在鸭子类型语言中增加价值。
编辑:对于答案:我知道鸭子打字是什么(这应该从帖子中显而易见)。我在哪里记录它是问题,尤其是。当不存在可附加文档的类时。
I'm having documentation bloat on me, as anytime I encounter a complex duck-type, I need some way to say "this duck type" but instead get caught in an endless cycle of "your function requires this of this input, but doesn't document it", and then documenting it. This results in bloated, repetitive documentation, such as the following:
def Foo(arg):
"""
Args:
arg: An object that supports X functionality, and Y functionality,
and can be passed to Z other functionality.
"""
# Insert code here.
def Bar(arg):
"""
Args:
arg: An object that supports X functionality, and Y functionality,
and can be passed to Z other functionality.
"""
# Insert code here.
And so on, and so on, for Baz
, Qux
, and other functions. I need some shorter way of writing "arg
is a (type of object)".
For some duck types, it's as easy as "A dict-like object": we know what we expect of a dict, and so, we know what to pass. A dict
, or something that can mimic it.
I feel C++ has this same problem with templated types. Haskell would have it, but one can use a type class's definition to document it. (Note: Haskell classes != classes in Java/C++/Python/etc.) (Note: I don't really program in Haskell, so forgive me if it is a crappy example.)
Should I go the traditional OO route, and just write a base class, and say, "anything like this base class" in the docs? The code wouldn't enforce deriving from the base class (as there is no requirement for the object to be derived from it), and the base class adds no value except to document the properties of the interface, essentially.
On the other hand, I'm programming Python, and I try to program within the idioms of a language. (As doing otherwise usually hurts.) Base classes are good for inheriting functionality, but when your base class is completely abstract, it doesn't seem to add value in a duck-typed language.
EDIT: To the answers: I know what duck typing is (that should be evident from the post). Where do I document it is the question, esp. when no class exists to attach documentation to.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
鸭子类型背后的想法是,您记录您正在期待一只鸭子,并且由其他对象来假装是一只鸭子。
文档中没有任何 API 指定它接受 StringIO 对象;但是,我们可以在大多数需要“类似文件对象”的地方使用它们。
此外,在大多数情况下,标准库试图避免命名鸭子类型所需的特定方法。这使得实施可以改变。 random.sample API,用于例如,可以根据可迭代或序列来定义。
如果您想比这更具体,您可以使用抽象基类。有几个已经包含在集合模块中(例如如 Iterable、Hashable 和 Sized)或 数字模块(Rational、积分等)。按照这些模型来编写自己的模型并不难。然后,文档简单地提到需要哪些 ABC(例如 x 是 大小 可迭代 和y 是一个 积分)。
The idea behind duck typing is that you document that you are expecting a duck, and it is up to other objects to fake being a duck.
Nowhere in the docs does any API specify that it accepts a StringIO object; however, we can use them in most places that expect a "file-like object".
Also, for the most part, the standard library tries to avoid naming the specific methods demanded of a duck type. That leaves the implementation open to change. The random.sample API, for example, could have been defined in terms of iterables or in terms of sequences.
If you want to be more specific than this, you could use abstract base classes. Several are already included in the collections module (such as Iterable, Hashable, and Sized) or numbers module (Rational, Integral, etc). It is not hard to model after those to write your own. Then, the documentation simply mentions which ABCs are required (e.g. x is a Sized Iterable and y is an Integral).
鸭子类型的要点在于,“类型”的概念成为一种抽象直观的想法,而不是正式成为语言一部分的东西。与类型检查作为语言一部分的语言相比,这使得键入更加流畅和灵活。
使用鸭子类型时所需要的不是程序知道您正在使用什么“类型”,而是其他程序员知道。因此,如果您有一整套对特定“类型”的对象进行操作的类/函数/等,并且该类型无法用几句话来描述,只需在注释或文档字符串中添加一个部分(甚至外部 .txt 文件)描述您的类型并为其命名。然后你就可以在任何地方引用这个名字了。
The point of duck typing is that the notion of "type" becomes an abstract intuitive idea, rather than something that is formally part of the language. This makes typing much more fluid and flexible than in languages where type checking is part of the language.
What is required when using duck typing is not that the program knows what "type" you're using, but that other programmers do. So if you have a whole family of classes/functions/etc that operate on objects of a particular "type", and that type is not able to be described in a few words, just add a section in comments or a docstring (or even an external .txt file) describing your type and naming it. Then you can just refer to that name everywhere.
更严格类型的语言(例如 Java)具有“接口”的概念:任何实现该接口的类都应该提供的方法集合。
我想你可以借用这个概念,而不必带来严格类型的包袱:只需定义并记录一个抽象类
Foo
,然后说你的方法需要“aFoo
”或类似Foo
的对象”。如果您不愿意,您甚至不必让任何其他类实际继承Foo
;阅读文档的人仍然知道到哪里去查找类似Foo
的对象的期望。More strictly typed languages, like Java, have the concept of "interfaces": collections of methods that any class implementing the interface is supposed to provide.
I suppose you could borrow the concept without necessarily bringing along the baggage of strict typing: just define and document an abstract class
Foo
, and then say that your method expects "aFoo
or aFoo
-like object". You don't even have to make any other class actually inherit fromFoo
if you don't want to; people reading the documentation will still know where to go to find out what is expected of aFoo
-like object.