什么是“针对接口,而不是对象的代码”的Python版本?
受到一个很好的问题(以及一堆很好的答案)的启发。
“对一个接口,而不是一个对象的代码”语句在Python中有什么意义吗?
我正在寻找像原始问题的答案,但与Python的片段和想法。
“针对接口而不是对象的代码”在Python中并不具有字面意义,因为该语言没有接口function。 粗略的 Python等价物是“使用鸭子打字”。 如果你想看看一个对象是否是鸭子,换句话说,你应该检查它是否有一个quack()
方法,或者更好地尝试quack()
并提供适当的error handling,而不是testing它是否它是Duck
一个实例。
在Python中常见的鸭子types是文件(嗯,实际上是类文件对象),映射(类似于对象的对象),可调用函数(类似于对象的对象),序列(类list
对象)和迭代(你可以遍历的东西,可以是容器或发电机)。
例如,希望文件的Python特性通常很乐意接受实现所需file
方法的对象; 它不需要从file
类派生。 例如,要使用一个对象作为标准,它需要的主要是一个write()
方法(也许是flush()
和close()
,它们实际上不需要做任何事情)。 类似地,可调用是具有__call__()
方法的任何对象; 它不需要从函数types派生(事实上,你不能从函数types派生)。
你应该采取类似的方法。 检查你要用对象做什么的方法和属性。 更好的是,logging你的期望,并假设谁调用你的代码不是一个总的doofus。 (如果他们给你一个你不能使用的对象,他们肯定会很快从错误中得出结论。)只有在必要时才testing特定的types。 这是必要的,这就是为什么Python给你type()
, isinstance()
和issubclass()
,但要小心。
Python的鸭子打字相当于“针对接口而不是对象的代码”,因为build议您不要让代码过于依赖对象的types,而是要看看它是否具有所需的接口。 不同的是,在Python中,“接口”仅仅意味着提供特定行为的对象的属性和方法的非forms捆绑,而不是特定名称的语言构造。
您可以使用abc
模块在某种程度上正式化Python“接口”,它允许您使用任何标准声明给定的类是给定“抽象基类”(接口)的子类,例如“它具有属性color
, tail_length
, quack
,而quack
是tail_length
。“ 但是这比具有界面function的静态语言要严格得多。
要理解Python中的接口,您必须了解鸭子input。 从非常Python的词汇表 :
duck-typing :一种编程风格,它不会查看对象的types以确定它是否具有正确的界面; 相反,方法或属性被简单地调用或使用(“如果它看起来像一只鸭子,像一只鸭子,它肯定是一只鸭子。”)通过强调接口而不是特定types,精心devise的代码通过允许多态性取代。 鸭式input避免了使用type()或isinstance()的testing。 (但是请注意,duck-typing可以用抽象基类来补充),而是通常使用hasattr()testing或EAFP编程。
Python鼓励对接口进行编码,只是它们不是强制执行,而是按照惯例。 像iterables,callables或文件接口这样的概念在Python中非常普遍 – 以及依赖于接口(如map,filter或reduce)的内build函数。
一个接口意味着你期望某些方法在对象之间呈现和标准化; 这是一个接口或抽象基类的点,或者你想要考虑的任何实现。
例如(Java),可能有一个对称encryption的接口,如下所示:
public interface cipher { public void encrypt(byte[] block, byte[] key); public void decrypt(byte[] block, byte[] key); }
那么你可以实现它:
public class aes128 implements cipher { public void encrypt(byte[] block, byte[] key) { //... } public void decrypt(byte[] block, byte[] key) { //... } }
然后可以像这样声明一个对象:
cipher c;
我们在这里做了什么? 那么,我们已经创build了这个对象的types必须匹配接口的types。 c
可以指任何匹配这个接口的东西,所以下一个阶段是:
c = new aes128();
你现在可以调用你期望cipher
方法了。
这是Java。 现在,这是你在Python中做什么:
class aes128(Object): def __init__(self): pass def encrypt(self, block, key): # here I am going to pass, but you really # should check what you were passed, it could be # anything. Don't forget, if you're a frog not a duck # not to quack! pass
当你想使用这个,并且你不确定你传递的对象是什么,只是尝试使用它:
c = aes128() try: c.encrypt(someinput, someoutput) except: print "eh? No encryption method?!"
在这里,如果c.encrypt的实现存在,那么它将无法处理已传递的内容。 当然,如果c
是一个stringtypes,因此不是你需要的正确types,它也会自动抛出,并且你会捕获(希望)。
简而言之,一种编程forms是键入的,你必须遵守接口规则,另一种是说你甚至不需要把它们写下来,只要相信如果没有错误就行了。
我希望能向你们展示两者的实际区别。
“针对界面而不是对象编码”的Python版本是什么?
正确的引用是“ 针对接口的程序,而不是实现 ”。 这个原理在Python中是一样的,它在Smalltalk中就是它的起源语言。
是否声明“代码对一个接口,而不是一个对象”。 在Python中有什么意义?
是。 它在Python中与在(Smalltalk)引用的语言以及其他语言中具有相同的意义。