如何从Python背景理解接口
我很难理解C#中接口的用法。 这很可能是因为我来自Python,但在那里没有使用它 我不理解其他解释,因为它们没有完全回答我关于接口的问题。e、 g 据我所知,接口告诉类它可以做什么,而不是如何做。这意味着在某个时候必须告诉类如何执行这些方法 如果是这样的话,接口有什么意义?为什么不在类中定义方法呢 我看到的唯一好处是清楚地知道类可以/不能做什么,但代价是不干代码如何从Python背景理解接口,python,interface,Python,Interface,我很难理解C#中接口的用法。 这很可能是因为我来自Python,但在那里没有使用它 我不理解其他解释,因为它们没有完全回答我关于接口的问题。e、 g 据我所知,接口告诉类它可以做什么,而不是如何做。这意味着在某个时候必须告诉类如何执行这些方法 如果是这样的话,接口有什么意义?为什么不在类中定义方法呢 我看到的唯一好处是清楚地知道类可以/不能做什么,但代价是不干代码 我知道Python不需要接口,我认为这限制了我的理解,但我不太明白为什么。它在Python中以抽象类的形式(通常)使用 目的各不相同
我知道Python不需要接口,我认为这限制了我的理解,但我不太明白为什么。它在Python中以抽象类的形式(通常)使用 目的各不相同,在java中它们解决多重继承,在python中它们充当两个类之间的契约 类A做了一些事情,其中一部分涉及到类B。类B可以通过多种方式实现,因此,不要创建10个不同的类并希望它们能够正确使用,而是让它们从抽象类(接口)继承,并确保它们必须实现定义为抽象的所有方法。(请注意,如果他们没有实现任何方法,那么在构建时,安装包时,而不是运行包时,它将崩溃,这在中型/大型项目中非常重要) 您还知道,实现这些方法的任何类都将与使用它的类一起工作。这听起来很琐碎,但业务方面喜欢它,因为这意味着您可以将部分代码外包,它将连接并与您的其余代码协同工作
class Dog(Pet):
def thank_owner(self):
print('woof')
beethoven = Dog('Beethoven')
feed(beethoven) # yes, I use the same function. I haven't changed it at all!
据我所知,接口告诉类它可以做什么,而不是如何做。这意味着在某个时候必须告诉类如何执行这些方法
他们实际上告诉它必须做什么,至于他们如何做,我们不在乎
如果是这样的话,接口有什么意义?为什么不在类中定义方法呢
这不是重点,但是是的,您绝对需要在从接口继承的类中定义方法
让我们给你一个更具体的例子
假设您有一个运行某些任务的python框架。这些任务可以在本地运行(在运行python框架的同一台计算机上),可以在分布式系统上运行,通过将它们提交给某个中央调度器,可以在docker容器中运行,在Amazon Web services上运行。。。。你明白了
您所需要的只是一个接口(python中的一个抽象类),该接口有一个run_任务方法,至于使用哪种方法取决于您自己
e、 g:
现在是重要的一点,因为你可能会问为什么我需要所有这些
难题?(如果yopur项目足够小,您可能不知道,但根据大小,有一个断点,您几乎必须开始使用这些东西)
使用运行程序的类只需要理解接口,例如,您有一个任务类,该类可以将任务的执行委托给TaskRunner,至于实现了哪一个,您不关心,它们在某种意义上是多态的
class Task:
def __init__(self, task_runner):
self.task_runner = task_runner
self.task_command = 'ls'
def run_this_task(self):
self.task_runner.run_task(self.task_command)
如果你是一个程序员,你的老板可以告诉你,我需要一个新的类在AWS上执行命令,你把它当作一个命令,它实现了一个task_runner方法,那么你不需要知道任何关于其余代码的事情,你可以把这个部分作为一个完全独立的部分来实现(这是外包部分,现在你可以让100人设计100种不同的产品,他们不需要知道任何代码,只需要知道接口)
C Sharp有静态类型系统。编译器需要知道类有哪些方法。这就是为什么我们必须为每个变量设置类型:
def feed(cat: Cat):
cat.moew() # he thanks the owner
但是,如果我们必须编写代码,却不知道变量的确切类型,该怎么办
def feed(it):
it.thank_owner()
此外,我们必须假设我们的函数将用于各种类。别忘了,我们必须让编译器知道每个变量的类型!该怎么办?解决方案:
class Pet: # an interface
def thank_owner(self):
raise NotImplementedError()
def feed(it: Pet):
it.thank_owner()
class Cat(Pet): # inherits the interface Pet
def thank_owner(self):
print('meow') # or self.meow() if we want to avoid big changes and follow DRY rule at the same time
tom = Cat('Tom')
feed(tom)
但是如何处理Cat?解决方案:
class Pet: # an interface
def thank_owner(self):
raise NotImplementedError()
def feed(it: Pet):
it.thank_owner()
class Cat(Pet): # inherits the interface Pet
def thank_owner(self):
print('meow') # or self.meow() if we want to avoid big changes and follow DRY rule at the same time
tom = Cat('Tom')
feed(tom)
顺便说一下,现在我们可以很容易地添加新的宠物。我们不必重写代码
class Dog(Pet):
def thank_owner(self):
print('woof')
beethoven = Dog('Beethoven')
feed(beethoven) # yes, I use the same function. I haven't changed it at all!
请注意,我们创建这个类的时间晚于
feed()
和Pet
。在编写代码之前,我们没有考虑Dog
,这一点很重要。我们对此并不好奇。但是,当我们需要扩展代码时,我们没有遇到任何问题。类Pet:#一个接口定义感谢所有者(self):raise NotImplementedError()您的宠物接口将在运行时崩溃,而不是在构建时崩溃,这首先违背了接口的目的。当然是在运行时。它是Python!我想解释一下接口的用途。如果您放置一个抽象类并扩展它,而不实现抽象方法,它将在构建时崩溃(相当于java/C#中的编译时),关键是要使python在这方面更像java或C#(有一个编译步骤非常好,因为它强制键入,python提供了选项,但并不强迫您这样做)。