简体   繁体   English

鸭子打字:如何避免名称冲突?

[英]Duck typing: how to avoid name collisions?

I think understand the idea of duck typing, and would like to use it more often in my code.我想理解鸭子打字的想法,并希望在我的代码中更频繁地使用它。 However, I am concerned about one potential problem: name collision.但是,我担心一个潜在的问题:名称冲突。

Suppose I want an object to do something.假设我想要一个 object 来做某事。 I know the appropriate method, so I simply call it and see what happens.我知道合适的方法,所以我简单地调用它,看看会发生什么。 In general, there are three possible outcomes:一般来说,可能的结果有以下三种:

  1. The method is not found and AttributeError exception is raised.未找到该方法并引发AttributeError异常。 This indicates that the object isn't what I think it is.这表明 object 不是我想的那样。 That's fine, since with duck typing I'm either catching such an exception, or I am willing to let the outer scope deal with it (or let the program terminate).这很好,因为使用 duck typing 我要么捕获这样的异常,要么我愿意让外部 scope 处理它(或让程序终止)。

  2. The method is found, it does precisely what I want, and everything is great.方法找到了,它正是我想要的,一切都很好。

  3. The method is found, but it's not the method that I want;方法找到了,但不是我要的方法; it's a same-name method from an entirely unrelated class. The execution continues, until either inconsistent state is detected later, or, in the worst case, the program silently produces incorrect output.它是来自完全不相关的 class 的同名方法。执行将继续,直到稍后检测到不一致的 state,或者在最坏的情况下,程序会默默地生成不正确的 output。

Now, I can see how good quality names can reduce the chances of outcome #3.现在,我可以看到优质名称如何降低结果 #3 的可能性。 But projects are combined, code is reused, libraries are swapped, and it's quite possible that at some point two methods have the same name and are completely unrelated (ie, they are not intended to substitute for each other in a polymorphism).但是项目合并了,代码被重用了,库被交换了,很可能在某些时候两个方法具有相同的名称并且完全不相关(即,它们不打算在多态性中相互替代)。

One solution I was thinking about is to add a registry of method names.我正在考虑的一种解决方案是添加一个方法名称注册表。 Each registry record would contain:每个注册表记录将包含:

  • method name (unique; ie, only one record per name)方法名称(唯一;即每个名称只有一条记录)
  • its generalized description (ie, applicable to any instance it might be called on)它的一般描述(即适用于可能调用它的任何实例)
  • the set of classes which it is intended to be used in它打算用于的一组类

If a method is added to a new class, the class needs to be added to the registry (by hand).如果将方法添加到新的 class,则需要将 class 添加到注册表(手动)。 At that time, the programmer would presumably notice if the method is not consistent with the meaning already attached to it, and if necessary, use another name.那时,程序员大概会注意到该方法是否与它已经附加的含义不一致,并且在必要时使用另一个名称。

Whenever a method is called, the program would automatically verify that the name is in the registry and the class of the instance is one of the classes in the record.每当调用一个方法时,程序会自动验证该名称是否在注册表中,并且该实例的 class 是否是记录中的类之一。 If not, an exception would be raised.如果不是,将引发异常。

I understand this is a very heavy approach, but in some cases where precision is critical, I can see it might be useful.我知道这是一种非常繁重的方法,但在某些精度至关重要的情况下,我认为它可能会有用。 Has it been tried (in Python or other dynamically typed languages)?是否尝试过(Python 或其他动态类型语言)? Are there any tools that do something similar?是否有任何工具可以做类似的事情? Are there any other approaches worth considering?还有其他值得考虑的方法吗?

Note: I'm not referring to name clashes at the global level, where avoiding namespace pollution would be the right approach.注意:我指的不是全局级别的名称冲突,避免命名空间污染才是正确的方法。 I'm referring to clashes at the method names;我指的是方法名称的冲突; these are not affected by namespaces.这些不受名称空间的影响。

Well, if this is critical , you probably should not be using duck typing...好吧,如果这很关键,你可能不应该使用鸭子打字......

In practice, programs are finite systems, and the range of possible types passed into any particular routine does not cause the issues you are worrying about (most often there's only ever one type passed in).实际上,程序是有限系统,传递给任何特定例程的可能类型的范围不会导致您担心的问题(通常只有一种类型传入)。

But if you want address this issue anyway, python provides ABCs (abstract base classes).但是如果你想解决这个问题,python 提供了ABCs (抽象基类)。 these allow you to associated a "type" with any set of methods and so would work something like the registry you suggest (you can either inherit from an ABC in the normal way, or simply "register" with it).这些允许您将“类型”与任何一组方法相关联,因此可以像您建议的注册表一样工作(您可以以正常方式从 ABC 继承,或者简单地“注册”它)。

You can then check for these types manually or automate the checking with decorators from pytyp .然后,您可以手动检查这些类型或使用pytyp中的装饰器自动检查。

But, despite being the author of pytyp, and finding these questions interesting, I personally do not find such an approach useful.但是,尽管我是 pytyp 的作者,并且发现这些问题很有趣,但我个人并不认为这种方法有用。 In practice, what you are worrying about simply does not happen (if you want to worry about something, focus on the lack of documentation from types when using higher order functions.).实际上,您担心的事情根本不会发生(如果您想担心某事,请关注使用高阶函数时类型缺少文档。)。

PS note - ABCs are purely metadata. PS 注 - ABC 纯粹是元数据。 They do not enforce anything.他们不强制执行任何事情。 Also, checking with pytyp decorators is horrendously inefficient - you really want to do this only where it is critical.此外,使用 pytyp 装饰器进行检查效率极低——你真的只想在关键的地方这样做。

If you are following good programming practice or let me rather say if your code is Pythoic then chances are you would seldom face such issues.如果您遵循良好的编程习惯,或者让我更愿意说您的代码是否是 Pythoic,那么您很可能很少会遇到此类问题。 Refer the FAQ What are the “best practices” for using import in a module?请参阅常见问题解答 在模块中使用导入的“最佳实践”是什么? . . It is generally not advised to clutter the namespace and the only time when there could be a conflict if you are trying to reuse the Python reserved names and or standard libraries or name conflicts with module name.通常不建议将命名空间弄乱,并且只有在您尝试重用 Python 保留名称和/或标准库或名称与模块名称冲突时才会出现冲突。 But if you encounter conflict as such then there is a serious issue with the code.但是,如果您遇到这样的冲突,则代码存在严重问题。 For example例如

  1. Why would someone name a variable as list or define a function called len?为什么有人会将一个变量命名为 list 或定义一个名为 len 的 function?
  2. Why would someone name a variable difflib when s/he is intending to import it in the current namespace?当他/她打算将变量导入当前命名空间时,为什么有人会命名变量 difflib?

To address your problem, look at abstract base classes .要解决您的问题,请查看抽象基类 They're a Pythonic way to deal with this issue;它们是处理这个问题的 Pythonic 方式; you can define common behavior in a base class, and even define ways to determine if a particular object is a "virtual baseclass" of the abstract base class. This somewhat mimics the registry you're describing, without requiring all classes know about the registry beforehand.您可以在基类 class 中定义常见行为,甚至定义确定特定 object 是否是抽象基类 class 的“虚拟基类”的方法。这在某种程度上模仿了您所描述的注册表,而不需要所有类都知道注册表预先。

In practice, though, this issue doesn't crop up as often as you might expect.但在实践中,这个问题并不像您预期的那样频繁出现。 Objects with an __iter__ method or a __str__ method are simply broken if the methods don't work the way you expect.如果方法不能按您预期的方式工作,则具有__iter__方法或__str__方法的对象就会被破坏。 Likewise, if you say an argument to your function requires a .callback() method defined on it, people are going to do the right thing.同样,如果您说 function 的参数需要在其上定义的.callback()方法,那么人们会做正确的事情。

If you are worried that the lack of static type checking will let some bugs get through, the answer isn't to bolt on type checking, it is to write tests.如果你担心缺少 static 类型检查会让一些错误通过,答案不是加强类型检查,而是编写测试。

In the presence of unit tests, a type checking system becomes largely redundant as a means of catching bugs.在存在单元测试的情况下,类型检查系统作为捕获错误的一种手段在很大程度上变得多余。 While it is true that a type checking system can catch some bugs, it will only catch a small subset of potential bugs.虽然类型检查系统确实可以捕获一些错误,但它只会捕获一小部分潜在错误。 To catch the rest you'll need tests.要赶上 rest,您需要进行测试。 Those unit tests will necessarily catch most of the type errors that a type checking system would have caught, as well as bugs that the type checking system cannot catch.这些单元测试必然会捕获类型检查系统会捕获的大部分类型错误,以及类型检查系统无法捕获的错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM