python中的类接口

python中的类接口,python,oop,Python,Oop,我越来越深入python,发现很难理解接口的概念 这个问题更具理论性 据我所知,为最终用户(非开发人员用户)提供接口是可取的,但是为什么类也应该为其他对象/类(基本上是其他程序/程序员)提供接口来使用呢?? 在本例中,在B类中使用注释1或注释2如何改变程序的功能 class A(): def __init__(self,a): self.a = a print self.a def seta(self,newa): #setter self.a =

我越来越深入python,发现很难理解接口的概念

这个问题更具理论性

据我所知,为最终用户(非开发人员用户)提供接口是可取的,但是为什么类也应该为其他对象/类(基本上是其他程序/程序员)提供接口来使用呢?? 在本例中,在B类中使用注释1或注释2如何改变程序的功能

class A():
   def __init__(self,a):
      self.a = a
      print self.a
   def seta(self,newa): #setter
      self.a = newa
      print self.a
   def geta(self): #getter
      return self.a


class B(object):
   def __init__(self,oobj,b):
      self.b = b
      self.oobj = oobj
      print self.b
   def addab(self):
      #a = self.oobj.geta() # —> 1. using interface : the getter method 
      #return (self.b +a)
      return (self.b+self.oobj.a) # —> 2.directly accessing the a attribute
希望我已经明确了

编辑:
我确实检查了提到的另一个线程,认为它可能是重复的,但即使在试图理解@property之前,我也试图理解不在程序中通过不同的对象修改属性的原因。

使用setter方法的原因之一是立即验证输入,并且不要让无效值进一步传播到代码中。越早识别无效值,就越容易进行故障排除

考虑以下类别:

class A():
    def __init__(self, s, pos):
        self.s   = s
        self.pos = pos

    def get_char(self):
        return self.s[self.pos]

现在考虑这个代码:

a = A("Foo", 1)
a.pos = 2 
a.pos = 10              # Raises no error... yet
a.pos = "Foo"           # Raises no error... yet
# ... time passes ...
print(a.get_char())     # Raises an error now, but much later than when an invalid attribute was set
您可以将
pos
属性设置为您想要的任何属性,直到尝试在
get_char()
方法中使用
pos
属性时,才会出现错误。这可能很难排除故障

因此,一些语言处理这一问题的一种方法是以某种方式屏蔽这些属性——可能通过将它们设置为“受保护”或“私有”——并通过getter和setter让其余的代码访问它们

这样,就可以将代码添加到setter方法中以验证值

例如:

class B():
    def __init__(self, s, pos):
        self._s   = s
        self._pos = pos

    def get_pos(self):
        return self._pos

    def set_pos(self, newpos):
        if not 0 < newpos < len(self._s): raise IndexError
        self._pos = newpos

    def get_char(self):
        return self._s[self._pos]
现在,对
b.set_pos(10)
b.set_pos(“Foo”)
的调用都将导致
索引器
,允许您立即捕获无效输入

输入Python的属性 但是Python给了我们(和装饰器)做同样的事情,但是更酷

考虑:

class C(object):
    def __init__(self, s, pos):
        self._s   = s
        self._pos = pos

    @property
    def pos(self):
        return self._pos

    @pos.setter
    def pos(self, newpos):
        if not 0 < newpos < len(self._s): raise IndexError
        self._pos = newpos

    def get_char(self):
        return self._s[self._pos]
但是对于属性,C类也与A类完全相同

与类A和类C交互以供参考的代码的两部分:

a = A("Foo", 1)
a.pos = 2
a.pos = 10
a.pos = "Foo"
print(a.get_char())

c = C("Foo", 1)
c.pos = 2
c.pos = 10
c.pos = "Foo"
print(c.get_char())
从类a开始,然后在需要某种输入验证时,以类C结束,这种情况并不少见

因此,使用属性,您可以获得getter/setter方法的安全性/灵活性,但不需要更改外部代码


注意:输入验证不是需要getter/setter方法的唯一原因。例如,如果您希望(有条件地)修改给定的值,或在不影响API的情况下更改内部表示形式,它们会很有用。

接口的一个重要目的是鼓励松散耦合,其中一个类不依赖于其他类的内部实现。同时,它允许我们定义一个类,确信其他开发人员不会以可能导致意外行为的方式处理内部属性。它通过告诉其他开发人员“下面是您应该如何使用这个类”使事情变得更简单

在现实世界中,类的实现细节通常会发生很大的变化。如果其他类依赖于该类的内部实现细节,那么当这些细节发生更改时,依赖于该类的代码将开始出现故障。通过定义一个公共接口,一个类向依赖它的其他类承诺“我将始终拥有这些可用的属性和方法,即使我如何执行它们的细节可能会改变。”

此外,公共接口允许您定义更适合您工作领域的直观API。例如,考虑一个存储餐馆评论的程序。作为一个开发者,能够打电话给restaurant.average_review_score,而不必太多地谈论餐厅的定义,这会更好

关于这个想法的更多信息,我强烈推荐您阅读史蒂夫·麦康奈尔的《代码全集》


也就是说,在Python中,不使用getter或setter直接访问类的属性是很常见的。这与大多数其他OO语言(如java、C++和C语言)的约定有很大的不同。在这些语言中,语言本身包含用于区分公共接口和私有实现的结构。在Python中,我们依赖于约定和礼貌,尽可能不要与被标记为私有使用和下划线的成员混在一起。

不要用Python编写getter和setter。在Python中不鼓励重复使用getter和setter。你凭什么认为这种用法是受鼓励的?@durga:什么书?如果有一本书告诉您在Python中使用getter和setter,请停止阅读它。我现在至少得到了一个上下文,其中这些方法是有用的。我现在会尽量把注意力集中在房产上。非常感谢。那解释有道理。。我会查一下你提到的那本书。
c = C("Foo", 1)
c.pos = 2               # This is fine
c.pos = 10              # This raises an error
c.pos = "Foo"           # This raises an error
# ... time passes ...
print(c.get_char())
a = A("Foo", 1)
a.pos = 2
a.pos = 10
a.pos = "Foo"
print(a.get_char())

c = C("Foo", 1)
c.pos = 2
c.pos = 10
c.pos = "Foo"
print(c.get_char())