为什么要使用Python类而不是函数模块?

4
我是一名有用的助手,可以为您翻译文本。
我正在自学Python(3.x),并尝试理解类的使用情况。我开始理解它们实际上所做的事情,但我很难理解为什么要使用类,而不是创建一个带有函数的模块。
例如,如何:
class cls1:
    def func1(arguments...):
    #do some stuff


obj1 = cls1()
obj2 = cls1()

obj1.func1(arg1,arg2...)
obj2.func1(arg1,arg2...)

与...不同:

#module.py contents
    def func1(arguments...):
        #do some stuff

import module

x = module.func1(arg1,arg2...)
y = module.func1(arg1,arg2...)

这可能很简单,但我就是理解不了。

到目前为止,我已经成功编写了一些Python程序,但都比较过程化,并且只导入基本的模块函数。类是我接下来要克服的最大障碍。


2
它并不会。当您想要存储有关对象的状态时,类非常有用。 - Daniel Roseman
这是面向对象编程的绝对基本概念。更多信息请参阅:https://docs.python.org/3/tutorial/classes.html - infotoni91
我知道这一点,这就是为什么我正在努力理解如何使用对象 :) 我是一名工程师,所以编程是我正在尝试掌握的第二技能,因此请耐心等待,让我尝试弄清楚这些基础知识。 - Kierran Purden
4个回答

13

如果你需要多个实例并且希望这些实例彼此不干扰,则可以使用类(class)。

模块(module)的行为类似于单例类,因此您只能拥有其中一个实例。

编辑说明:例如,如果您有一个名为example.py的模块:

    x = 0
    def incr():
           global x
           x = x + 1

    def getX():
           return x

如果您尝试两次导入这些模块:

    import example as ex1
    import example as ex2

    ex1.incr()
    ex1.getX()
    1
    ex2.getX()
    1

这就是为什么该模块只被导入了一次,因此 ex1 和 ex2 指向同一个对象。


你能否举个例子来说明多次调用模块函数会如何“干扰”彼此?我理解为什么obj1和obj2是独立的实例,但x和y为什么不是隔离的呢? - Kierran Purden
x和y不是模块的变量。 - Mattia Tomeo
啊,好的,我明白了。谢谢。 - Kierran Purden
您的示例虽然简单,但确实帮助我更好地形象化了事物。再次感谢! - Kierran Purden

2
只要你仅使用纯函数(仅对它们的参数进行操作,对于相同的参数集始终返回相同的结果,不依赖于任何全局/共享状态,并且不更改任何东西 - 即没有任何副作用的函数),那么类的使用确实相当有限。但这是functional programming,虽然 Python 在技术上可以以函数式风格使用,但可能不是最佳选择。
一旦你需要在函数之间共享状态,特别是如果其中一些函数应该更改此共享状态,你就需要使用面向对象的概念了。共享状态的主要两种方式是从一个函数传递状态到另一个函数,或者使用全局变量。
第二种解决方案——全局状态——已知会带来麻烦,首先因为它使程序流程的理解(因此调试)更加困难,而且因为它防止你的代码成为可重入的,这对于许多常见用例(多线程执行、大多数服务器端 Web 应用程序代码等)是绝对不可取的。实际上,除了短小简单的一次性脚本之外,它几乎使你的代码无法使用或难以使用……

第二种解决方案通常意味着使用半正式的复杂数据结构(带有一组键的字典,通常包含其他字典、列表、字典列表、集合等),正确初始化它们并将它们从函数传递到函数——当然还要有一组在给定数据结构上工作的函数。换句话说,你实际上正在定义新的复杂数据类型(一个数据结构和一组对该数据结构进行操作的操作),只使用语言提供的最低级别工具。

类实际上是一种在更高层次上定义数据类型的方式,将数据和操作分组。它们还提供了更多功能,特别是 多态性,这使得代码更加通用、可扩展,并且更容易进行单元测试。

谢谢你的回答!到目前为止,我的程序都非常实用。我是一名工程师,主要工作是“设置仪器,读取数据,将结果写入文件,进入下一个测试...”,因此到目前为止,我还没有真正需要使用对象。 - Kierran Purden
@KierranPurden 你的使用情况实际上仍然可以从面向对象编程(OOP)中受益 - 事实是,一旦你在编写Python代码,你就正在使用一些面向对象的特性,因为在Python中,一切都是对象。 - bruno desthuilliers
我明白了。我会再做一些实验,看看能找出什么。 - Kierran Purden

2
考虑你有一个包含产品信息的文件或数据库,每个产品都有产品ID、价格、库存、折扣、发布状态以及其他属性。另外还有一个包含数千个产品新价格、库存和折扣的文件。你想要更新这些值,并控制有多少产品会被更改以及其他统计信息。你可以使用过程式编程和函数式编程,但你很可能会发现自己在尝试解决问题时需要使用许多技巧并且很容易陷入许多不同的列表和集合中。
另一方面,使用面向对象编程,你可以创建一个类Product,其实例变量包括产品ID、旧价格、旧库存、旧折扣、旧发布状态和一些新值的实例变量(新价格、新库存、新折扣、新发布状态)。然后,你只需读取第一个文件/数据库,为每个产品创建一个类Product的新实例。接下来,你可以读取第二个文件,找到产品对象的新值。最终,第一个文件/数据库中的每个产品都将成为一个对象,并带有旧值和新值。这样做更容易跟踪更改、进行统计和更新数据库。
再举一个例子,如果你使用tkinter,你可以为顶级窗口创建一个类,每次你想要出现一个消息窗口或关于窗口(具有自定义颜色背景和尺寸),你只需创建这个类的一个新实例即可。
对于简单的事情,不需要使用类。但对于更复杂的问题,有时使用类可以让解决方案变得更加容易。

1
我认为最好的答案是取决于你的目标对象应该是什么/做什么。但总的来说,类和导入的模块之间存在一些区别,这将使它们在当前模块中具有不同的功能。最重要的是,类已被定义为对象,这意味着它们有很多选项可以像对象一样运作,而模块则没有。例如一些特殊属性,如__getattr____setattr____iter__等。以及创建许多实例甚至控制它们创建方式的能力。但对于模块,文档完美地描述了它们的用例:
如果你退出 Python 解释器并重新进入,你所定义的函数和变量将会丢失。因此,如果你想要编写一个稍微长一些的程序,最好使用文本编辑器准备输入并使用该文件作为输入运行。这就是所谓的创建脚本。随着程序越来越长,你可能需要将其拆分成多个文件以便于维护。你也可能想要在多个程序中使用一个方便的函数而不必将其定义复制到每个程序中。
为了支持这一点,Python 提供了一种方法来将定义放入文件中,并在脚本或交互式解释器实例中使用它们。这样的文件称为模块;来自模块的定义可以导入到其他模块或主模块(在顶层执行的脚本和计算器模式中可以访问的变量集合)中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接