class 在 python 中的接口
class interfaces in python
我越来越喜欢 python 并且发现很难理解接口的概念。
这个问题比较理论化。
据我所知,为最终用户(非开发人员用户)提供界面是可取的,但为什么 classes 也应该为其他 objects/classes(基本上是其他 programs/programmers)) 使用??
在示例中,在 class B 中使用 comment1 或 comment 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
希望我已经说清楚了..
编辑:
我确实检查了提到的另一个可能重复的线程,但即使在尝试理解@属性 之前,我也在尝试理解不在程序中由不同对象自行修改属性的基本原理。
使用 setter 方法的原因之一是立即验证输入,而不是让无效值进一步传播到代码中。越早识别无效值,越容易排除故障。
考虑以下 class:
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
属性时才会出现错误.这可能很难排除故障。
所以一些语言处理这个问题的一种方法是以某种方式屏蔽这些属性——可能通过使它们成为 "protected" 或 "private"——并通过 getter 和setters.
这样,代码可以添加到 setter 方法来验证值 then.
例如:
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 = B("Foo", 1)
b.set_pos(2) # This is fine
b.set_pos(10) # This raises an error
b.set_pos("Foo") # This raises an error
# ... time passes ...
print(b.get_char())
现在,对 b.set_pos(10)
和 b.set_pos("Foo")
的调用都将导致 IndexError
,让您立即捕获无效输入。
输入Python的属性
但是 Python 给了我们 properties
, (and the @property
装饰器)做同样的事情,但更酷。
考虑:
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]
Class C 完全 与 Class B.
进行相同的输入验证
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())
但有了属性,Class C 也 看起来 与 Class A 完全一样!
A和C交互的两段代码class供参考:
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())
以 Class A 开头并不少见,然后当需要某种输入验证时,以 Class C 结尾。
因此,对于属性,您可以获得 getter/setter 方法中的 safety/flexibility 方法,而无需更改外部代码。
注意: 输入验证并不是需要 getter/setter 方法的唯一原因。例如,如果您想(有条件地)修改给定值,或更改内部表示而不影响 API.
,它们会很有帮助
接口的一个重要目的是鼓励松散耦合,其中一个 class 不依赖于其他 class 的内部实现。同时,它允许我们定义一个 class 确信其他开发人员不会以可能导致意外行为的方式乱用内部属性。它通过告诉其他开发人员 "here is how you are supposed to use this class."
让事情变得更简单
在现实世界中,classes 的实现细节经常会发生很大变化。如果其他 classes 依赖于 class 的内部实现细节,那么当这些细节发生变化时,依赖于 class 的代码将开始出现故障。通过定义一个 public 接口,一个 class 承诺依赖于它的其他 classes "I will always have these properties and methods available, even if the details of how I execute them may change."
此外 public 界面允许您定义更适合您工作领域的直观 API。例如,考虑一个存储餐厅评论的程序。作为开发人员,能够调用 restaurant.average_review_score 而不必过多关注餐厅的定义方式要好得多。
有关此想法的更多信息,我强烈建议您阅读 Steve McConnell 的 Code Complete。
也就是说,在 Python 中直接访问 class 的属性而不使用 getter 或 setter 是很常见的。这与大多数其他 OO 语言(如 Java、C++ 和 C#)中的约定完全不同。在这些语言中,语言本身包含用于区分 public 接口和私有实现的结构。在 Python 中,我们依赖于约定俗成和礼貌,尽可能不要与被标记为私人使用和下划线的成员混为一谈。
我越来越喜欢 python 并且发现很难理解接口的概念。
这个问题比较理论化。
据我所知,为最终用户(非开发人员用户)提供界面是可取的,但为什么 classes 也应该为其他 objects/classes(基本上是其他 programs/programmers)) 使用?? 在示例中,在 class B 中使用 comment1 或 comment 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
希望我已经说清楚了..
编辑: 我确实检查了提到的另一个可能重复的线程,但即使在尝试理解@属性 之前,我也在尝试理解不在程序中由不同对象自行修改属性的基本原理。
使用 setter 方法的原因之一是立即验证输入,而不是让无效值进一步传播到代码中。越早识别无效值,越容易排除故障。
考虑以下 class:
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
属性时才会出现错误.这可能很难排除故障。
所以一些语言处理这个问题的一种方法是以某种方式屏蔽这些属性——可能通过使它们成为 "protected" 或 "private"——并通过 getter 和setters.
这样,代码可以添加到 setter 方法来验证值 then.
例如:
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 = B("Foo", 1)
b.set_pos(2) # This is fine
b.set_pos(10) # This raises an error
b.set_pos("Foo") # This raises an error
# ... time passes ...
print(b.get_char())
现在,对 b.set_pos(10)
和 b.set_pos("Foo")
的调用都将导致 IndexError
,让您立即捕获无效输入。
输入Python的属性
但是 Python 给了我们 properties
, (and the @property
装饰器)做同样的事情,但更酷。
考虑:
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]
Class C 完全 与 Class B.
进行相同的输入验证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())
但有了属性,Class C 也 看起来 与 Class A 完全一样!
A和C交互的两段代码class供参考:
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())
以 Class A 开头并不少见,然后当需要某种输入验证时,以 Class C 结尾。
因此,对于属性,您可以获得 getter/setter 方法中的 safety/flexibility 方法,而无需更改外部代码。
注意: 输入验证并不是需要 getter/setter 方法的唯一原因。例如,如果您想(有条件地)修改给定值,或更改内部表示而不影响 API.
,它们会很有帮助接口的一个重要目的是鼓励松散耦合,其中一个 class 不依赖于其他 class 的内部实现。同时,它允许我们定义一个 class 确信其他开发人员不会以可能导致意外行为的方式乱用内部属性。它通过告诉其他开发人员 "here is how you are supposed to use this class."
让事情变得更简单在现实世界中,classes 的实现细节经常会发生很大变化。如果其他 classes 依赖于 class 的内部实现细节,那么当这些细节发生变化时,依赖于 class 的代码将开始出现故障。通过定义一个 public 接口,一个 class 承诺依赖于它的其他 classes "I will always have these properties and methods available, even if the details of how I execute them may change."
此外 public 界面允许您定义更适合您工作领域的直观 API。例如,考虑一个存储餐厅评论的程序。作为开发人员,能够调用 restaurant.average_review_score 而不必过多关注餐厅的定义方式要好得多。
有关此想法的更多信息,我强烈建议您阅读 Steve McConnell 的 Code Complete。
也就是说,在 Python 中直接访问 class 的属性而不使用 getter 或 setter 是很常见的。这与大多数其他 OO 语言(如 Java、C++ 和 C#)中的约定完全不同。在这些语言中,语言本身包含用于区分 public 接口和私有实现的结构。在 Python 中,我们依赖于约定俗成和礼貌,尽可能不要与被标记为私人使用和下划线的成员混为一谈。