我是一个非常业余的Python学习者,最近我开始学习课程的概念。我可以大致理解类的概念,但我不明白为什么我不能简单地写一些函数而不是写一个类?
例如,(我从交互式Python学习)给出的练习之一(我应该用一个类来写)是:
添加一个与distanceFromOrigin类似的distanceFromPoint方法,只不过它以Point作为参数并计算该点与自身之间的距离。
将方法reflect_x添加到Point中,该方法返回新的Point,该方法是关于x轴的点的反射。例如,Point(3, 5).reflect_x()是(3, -5)。
他们使用如下类编写代码:
import math
class Point:
""" Point class for representing and manipulating x,y coordinates."""
def __init__(self, initX, initY):
""" Create a new point at the given coordinates."""
self.x = initX
self.y = initY
def getX(self):
return self.x
def getY(self):
return self.y
def distanceFromOrigin(self):
return ((self.x ** 2) + (self.y ** 2)) ** 0.5
def distanceFromPoint(self, otherP):
dx = (otherP.getX() - self.x)
dy = (otherP.getY() - self.y)
return math.sqrt(dy**2 + dx**2)
p = Point(3, 3)
q = Point(6, 7)
print(p.distanceFromPoint(q))
当我可以这样简单地写它们时,我为什么要使用类:
def distanceFromPoint(p,q): # they are tuples
y = (p[0]-q[0])**(2)+(p[1]-q[1])**(2)
return y**(1/2)
def reflectx(p):
return (p[0],-p[1])
p = (3,3)
q = (6,7)
至少getX和getY方法不被视为pythonic代码。您可以直接访问x和y属性。
除了下面更一般的答案:你不需要GETX/GETY。python没有真正的私有成员,所以只使用x/y是可以的。如果需要覆盖它们,则属性始终可用。
@马提亚斯:我是Python的新手。我不明白什么是Python密码,为什么getx,gety不是Python密码?
你不需要因为什么是"Python"或什么不是"Python"而失眠,但我希望你看到,mypoint.x比mypoint.getX()更简单、更清晰。但在这样一个简单的例子中很难说明OOP的威力。直到我有真正的问题要解决,我才真正"明白",我突然意识到,如果我写了一个继承自其他人先前定义的类的类,那么这个类会非常简单。
@内科马蒂:你能提到那些在python oop中引导你进入"啊哈"时刻的练习吗?
正如我所说,这是一个真正的问题,而不是像你这样的练习,我以前没有见过基于我遇到的人工例子的OOP点。也许你能想到一些你真正想要创造的东西,并用这个过程作为学习这些技术的工具?
虽然您的问题似乎是"为什么选择OO",但我确实觉得至少在Python中过度使用了OO方法。我见过很多代码做简单的事情,使用OO没有(至少是显而易见的)原因(根本没有使用继承等)。如果不编写类,整个代码可能会简单得多,并且使用函数式编程方法很容易测试。这并不意味着类是坏东西,它们对于解决大多数大的和/或复杂的问题是必要的,但我总是发现它们被过度使用。
使用OOP的一大优点是可扩展性。
假设您编写了一个以点的形式处理大量数据的应用程序。现在您的客户添加了规范,以及每个点的X和Y坐标,您的应用程序需要知道每个点是什么颜色。
如果编写代码将每个点存储为一个元组((x, y)),则可以将颜色作为第三个值添加:(x, y, colour)。但是现在你必须检查你所有的代码,找出它被破坏的地方,因为你改变了数据格式。如果您使用了一个类,您可以简单地定义一个继承自Point的新类,并添加必要的功能:
class ColouredPoint(Point):
""" Class for points which are coloured, based on Point"""
def __init__(self, initX, initY, initCol):
Point.__init__(self, initX, initY)
self.colour = initCol
p = ColouredPoint(3, 3,"green")
q = ColouredPoint(6, 7,"red")
r = Point(8, 4)
print(p.distanceFromPoint(q))
print(p.colour)
print(p.distanceFromPoint(r))
所有与Point类一起使用的代码仍然可以与新类一起使用,即使您没有编写或不能更改Point类的定义,也可以这样做。
你说的坏代码是什么意思?无类函数不能忽略附加值吗?例如,在没有类的情况下编码时,p[2]上可能有一个字符串作为元组,而tuple在计算距离时会忽略这一点。
这是真的,但是你的reflectx函数在这个问题上会怎么样——它会丢失额外的数据。我敢肯定,您可以想出一个解决方案,但我希望您看到,您所想到的对原始数据的更改和扩展越多,就越难设计出始终行为正确的数据类型。当您了解到现实应用程序的复杂性时,OOP就变得更加简单和健壮了,而以上只是使用OOP的原因之一。
如果我总结类"添加新函数(操作某些对象)或有效地更改对象结构"的需求,是否会遗漏一些内容?使用OOP的其他原因是什么?
除了可扩展性之外,OOP还有许多类似1的特性。组织:在代码中描述和定义数据和过程。2。状态:OOP帮助您定义和跟踪状态。三。封装:过程和数据存储在一起。4.继承:继承允许您在一个地方(在一个类中)定义数据和过程,然后稍后重写或扩展该功能。5。可重用性:所有这些原因和其他原因都允许代码具有更大的可重用性。面向对象代码允许您一次性编写实体(测试)代码,然后反复使用。
可以在类外部声明函数。但是在编程中,将它们存储在类中是一种更好的实践。OOP被认为更具可读性和可重用性。
在这种情况下,两点之间的距离取决于点,所以在这个类中使用DistanceFromPoint方法是合乎逻辑的。
类还允许您确定距离点的距离,而不是包含错误值(如两个以上坐标)的元组的距离。
我可以在距离函数中定义一个检查(使用if函数),如果前两个数据(在元组中)是整数,那么计算,否则显示一个错误。那我为什么要上课呢?
你举的一个例子对于证明类的使用是错误的。
类是描述事物的一种很好的方式,而不是操作数据。所以一个点只有两位信息来描述它(在二维空间中)。
想想更抽象的东西,比如电影文件。电影有各种各样的相关信息:标题,持续时间,流派,演员,年龄,流行度,语言,奖项…继续。尝试编写处理所有这些信息的长列表的函数,您将很快看到类的优点。
数学也许是一个没有那么多上下文信息的领域,只有几个变量,它们定义了一切。现实世界中的数据定义不太清楚,因此从类的可扩展性中获益。
你能详细描述一下你的第二段吗(一节课很好…)?如果没有太多的例子,我就无法清楚地理解这一点,而且我对Python还很陌生。
功能和面向对象编程是不同的范例。
在python中,一切都是一个对象,甚至是ints。整个语言都倾向于面向对象的编程,这就是为什么您应该选择它,特别是如果您的程序会增长的话。
您混合了函数式编程和命令式编程。函数编程并不意味着使用函数。你可以用python进行函数编程,但是他在文章中描述的方式是命令式编程。