类与函数

mul*_*rse 56 oop class function

即使对于没有任何编程经验但具有公平数学背景的人来说,功能也很容易理解.另一方面,课程似乎更难掌握.

假设我想创建一个类/函数来计算给定他/她的生日年和当前年份的人的年龄.我应该为此创建一个类,还是一个函数?或者是依赖于场景的选择?

PS我正在研究Python,但我想这个问题是通用的.

Amb*_*ber 96

创建一个功能.函数特定的事情,类特定的事情.

类通常有方法,这些方法是与特定类相关联的函数,并且与类所属的事物相关联 - 但如果您想要做的只是做某事,那么您只需要一个函数.

从本质上讲,类是一种将函数(作为方法)和数据(作为属性)分组为围绕某种事物的逻辑单元的方法.如果您不需要分组,则无需上课.

  • 这不完全正确.类也允许调度类型.如果你有一个协作功能的组或模板,它可能是一次性执行,但是使用类可以购买在组中有选择地实现不同功能的可能性,以便获得模板的特化.普通函数不是那么容易做到的,因为没有类型可以作为它们之间的链接,并允许对子类型进行专门化...... (5认同)
  • 总结一下:一个“类”对函数和数据进行分组。这在任何情况下都没有好处。我们有函数、数据类型和模块将它们组合在一起。即使你需要adhoc函数多态性:不同数据类型的不同函数实现,也有比OOP类更好的解决方案;考虑最终与语言无关的 Haskell 风格的类型类。 (2认同)

lil*_*shu 18

我将在这个问题上打破常规 (7年后编辑:我不再是这个问题上的唯一声音,有一个完整的编码运动就是为了做到这一点,称为“函数式编程”)并提供替代方案观点看法:

永远不要创建类。始终使用函数。

编辑:研究一再表明类是一种过时的编程方法。几乎所有关于该主题的研究论文都支持函数式编程而不是面向对象编程。

对类的依赖很容易导致编码人员创建臃肿且缓慢的代码。传递的类(因为它们是对象)比调用函数并传递一两个字符串需要更多的计算能力。正确的函数命名约定几乎可以完成创建类可以做的所有事情,并且只需要一小部分开销和更好的代码可读性。

但这并不意味着您不应该学习理解类。如果您与其他人一起编码,人们会一直使用它们,您需要知道如何处理这些类。编写依赖于函数的代码意味着代码将更小、更快且更具可读性。我见过仅使用快速而快速的函数编写的大型网站,也见过功能最少的小型网站,这些网站严重依赖于类并且经常崩溃。(当您的类扩展了包含类作为其类的一部分的类时,您知道您已经失去了所有易于维护的外表。)

归根结底,您想要传递的所有数据都可以通过现有数据类型轻松处理。

类是作为精神拐杖而创建的,不提供实际的额外功能,而且从长远来看,它们创建的过于复杂的代码往往会破坏该拐杖的意义。

编辑:7 年后更新... 最近,编码领域的一项新运动验证了我提出的这一观点。这是用函数式编程取代面向对象编程 (OOP) 的运动,它基于 OOP 的许多具体问题。有很多研究论文展示了函数式编程相对于面向对象编程的优势。除了我提到的几点之外,它还使代码的重用变得更加容易,使错误修复和单元测试更快更容易。老实说,虽然有很多好处,但选择 OOP 而不是函数式的唯一原因是与尚未更新的遗留代码的兼容性。


Max*_*ant 15

就像Amber在她的回答中所说:创造一个功能.事实上,如果你有类似的东西,你不必上课:

class Person(object):
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2

    def compute(other):
        """ Example of bad class design, don't care about the result """
        return self.arg1 + self.arg2 % other
Run Code Online (Sandbox Code Playgroud)

在这里,您只需要在类中封装一个函数.这只会使代码的可读性降低,效率降低.实际上,函数compute可以像这样写:

def compute(arg1, arg2, other):
     return arg1 + arg2 % other
Run Code Online (Sandbox Code Playgroud)

只有当你有多个函数并且保持内部状态(带属性)才有意义时,才应该使用类.否则,如果要重新组合函数,只需在新.py文件中创建一个模块.

你可能会看这个视频(Youtube,大约30分钟),这解释了我的观点.Jack Diederich展示了为什么在这种情况下类是邪恶的,为什么它是如此糟糕的设计,特别是在像API这样的东西.
这很长,但必须看到

  • 如果您需要100个功能,请编写100个功能.我根本没有看到课程的需要或好处.除非你陷入OOP的思维中. (3认同)
  • 感谢您发布视频:这就是我脑海中的想法:不要创建一个只有两个方法且其中之一是 __init__ 的类 (2认同)

Ben*_*Ben 6

类(或者更确切地说是它们的实例)用于表示事物.类用于定义特定对象类(其实例)支持的操作.如果您的应用程序需要跟踪人员,那么Person可能是一个类; 此类的实例代表您正在跟踪的特定人员.

函数用于计算事物.它们接收输入并产生输出和/或具有效果.

类和函数不是真正的替代品,因为它们不是同一个东西.考虑将课程"计算给出他/她的生日年和当年的年龄"是没有意义的.您可能会或可能不会有类以表示任何的概念Person,Age,Year,和/或Birthday.但即使Age是一个阶级,也不应该将其视为计算一个人的年龄; 而是计算一个人的年龄会导致一个Age班级的实例.

如果您在应用程序中为人员建模并且您有一个Person类,那么将年龄计算作为该类的方法可能是有意义的Person.方法基本上是一个被定义为类的一部分的函数; 这就是你如前所述"定义特定类对象支持的操作"的方法.

因此,您可以在您的人员类上创建一个方法来计算人的年龄(它可能会从人物对象中检索生日年并将当前年份作为参数接收).但是计算仍然由一个函数完成(只是一个碰巧是类上方法的函数).

或者你可以简单地创建一个独立的函数来接收参数(从中检索出生年份的人物对象,或者仅仅是出生年份本身).如你所知,如果你还没有这个方法自然属于的类,这就简单多了!你永远不应该创建一个简单的类来进行操作; 如果这是所有有到类,则操作应该只是一个独立的功能.


Bak*_*riu 5

这取决于场景。如果计算一个什么人的年龄,那么既然你想实现一个使用功能单一的特定行为。

但是,如果您要创建一个对象,其中包含一个人的出生日期(可能还有其他数据),并允许对其进行修改,那么计算年龄可能是与该人相关的许多操作之一,使用一个类代替。

类提供了一种将某些数据和相关操作合并在一起的方法。如果您仅对数据执行一项操作,则使用一个函数并将数据作为参数传递,您将获得等效的行为,而代码却不那么复杂。

请注意此类:

class A(object):
    def __init__(self, ...):
        #initialize
    def a_single_method(self, ...):
        #do stuff
Run Code Online (Sandbox Code Playgroud)

实际上不是一个类,它只是一个(复杂的)函数。一个合法的类应该至少有两个方法(不计数__init__)。


ulf*_*ulf 5

我知道这是一个有争议的话题,而且现在我可能会很生气。但是这是我的想法。

对于我自己,我认为最好是尽可能避免上课。如果我需要复杂的数据类型,则可以使用简单的struct(C / C ++),dict(python),JSON(js)或类似的方法,即没有构造函数,没有类方法,没有运算符重载,没有继承等。使用类时,您可以被OOP自己所迷惑(什么设计模式,什么应该是私有的,等等),而将注意力集中在您想首先编写的基本内容上。

如果您的项目变得又大又混乱,那么OOP就变得有意义了,因为需要某种直升机视图系统架构。“功能与类别”还取决于您要完成的任务。

功能

  • 目的:处理数据,操纵数据,创建结果集。
  • 何时使用:如果要执行此操作,请始终对函数进行编码:“ y = f(x)”

struct / dict / json / etc(而不是类)

  • 目的:存储属性/参数,维护属性/参数,重用属性/参数,使用属性/参数。后来。
  • 何时使用:如果您要处理一组属性/参数(最好是不可变的)
  • 不同的语言是同一件事:结构(C / C ++),JSON(js),字典(python)等。
  • 总是比复杂的类更喜欢简单的struct / dict / json / etc(保持简单!)

类(如果是新的数据类型)

  • 一个简单的角度:是带有附加方法的struct(C),dict(python),json(js)等。
  • 该方法仅应与存储在类中的数据/参数结合使用才有意义。
  • 我的建议:永远不要在类方法中编写复杂的东西(而是调用外部函数)
  • 警告:请勿将类误用作函数的伪命名空间!(这种情况经常发生!)
  • 其他用例:如果您想进行很多运算符重载,请使用类(例如,您自己的矩阵/向量乘法类)
  • 问自己:这真的是一种新的“数据类型”吗?(是=>类|否=>您可以避免使用类)

数组/向量/列表(用于存储大量数据)

  • 目的:存储许多相同数据类型的同类数据,例如时间序列
  • 建议#1:只使用您的编程语言已经拥有的。不要重新发明
  • 建议#2:如果您真的想要“ mysupercooldatacontainer类”,请重载现有的array / vector / list / etc类(例如“ class mycontainer:public std :: vector…”)

枚举(枚举类)

  • 我只是提
  • 建议#1:使用枚举加开关盒而不是过于复杂的OOP设计模式
  • 建议#2:使用有限状态机