简体   繁体   English

为什么要在具有功能的模块上使用python类?

[英]Why use python classes over modules with functions?

Im teaching myself python (3.x) and I'm trying to understand the use case for classes. 我正在自学python(3.x),我正在尝试了解类的用例。 I'm starting to understand what they actually do, but I'm struggling to understand why you would use a class as opposed to creating a module with functions. 我开始理解它们的实际作用,但是我正在努力理解为什么要使用类而不是创建带有函数的模块。

For example, how does: 例如,如何:

class cls1:
    def func1(arguments...):
    #do some stuff


obj1 = cls1()
obj2 = cls1()

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

Differ from: 与......不同:

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

import module

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

This is probably very simple but I just can't get my head around it. 这可能很简单,但是我无法理解。

So far, I've had quite a bit of success writing python programs, but they have all been pretty procedural, and only importing basic module functions. 到目前为止,我在编写python程序方面已经取得了相当大的成功,但是它们都具有相当的程序性,并且仅导入基本模块功能。 Classes are my next biggest hurdle. 上课是我的下一个最大障碍。

You use class if you need multiple instance of it, and you want that instances don't interfere each other. 如果需要一个类的多个实例,并且希望这些实例不会互相干扰,则可以使用该类。

Module behaves like a singleton class, so you can have only one instance of them. 模块的行为类似于单例类,因此您只能有一个实例。

EDIT: for example if you have a module called example.py: 编辑:例如,如果您有一个名为example.py的模块:

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

    def getX():
           return x

if you try to import these module twice: 如果您尝试两次导入这些模块:

    import example as ex1
    import example as ex2

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

This is why the module is imported only one time, so ex1 and ex2 points to the same object. 这就是为什么仅一次导入模块,所以ex1和ex2指向同一对象的原因。

As long as you're only using pure functions (functions that only works on their arguments, always return the same result for the same arguments set, don't depend on any global/shared state and don't change anything - neither their arguments nor any global/shared state - IOW functions that don't have any side effects), then classes are indeed of a rather limited use. 只要您仅使用纯函数(仅对它们的参数起作用的函数,对于相同的参数集始终返回相同的结果,不依赖于任何全局/共享状态并且不更改任何内容 ,也不更改其参数)也不是任何全局/共享状态-没有任何副作用的IOW函数),那么类的使用确实是有限的。 But that's functional programming , and while Python can technically be used in a functional style, it's possibly not the best choice here. 但这是函数式编程 ,尽管Python在技术上可以以函数样式使用,但在这里可能不是最佳选择。

As soon has you have to share state between functions, and specially if some of these functions are supposed to change this shared state, you do have a use for OO concepts. 一旦您必须在功能之间共享状态,并且特别是如果其中某些功能应该更改此共享状态,则您确实可以使用OO概念。 There are mainly two ways to share state between functions: passing the state from function to function, or using globals. 在函数之间共享状态的方法主要有两种:在函数之间传递状态,或使用全局变量。

The second solution - global state - is known to be troublesome, first because it makes understanding of the program flow (hence debugging) harder, but also because it prevents your code from being reentrant , which is a definitive no-no for quite a lot of now common use cases (multithreaded execution, most server-side web application code etc). 第二种解决方案-全局状态-麻烦,首先是因为它使对程序流的理解(因此调试)更加困难,而且还因为它使您的代码无法重新进入 ,这在很多情况下是肯定的当前常见的用例(多线程执行,大多数服务器端Web应用程序代码等)。 Actually it makes your code practically unusable or near-unusable for anything except short simple one-shot scripts... 实际上,它使您的代码几乎无法使用或几乎无法使用,除了简短的简单一枪脚本之外的任何事情……

The second solution most often implies using half-informal complex datastructures (dicts with a given set of keys, often holding other dicts, lists, lists of dicts, sets etc), correctly initialising them and passing them from function to function - and of course have a set of functions that works on a given datastructure. 第二种解决方案通常暗示使用半非正式的复杂数据结构(具有给定键集的字典,通常包含其他字典,列表,字典列表,集合等),正确地初始化它们并将它们从一个函数传递到另一个函数-当然具有在给定数据结构上工作的一组功能。 IOW you are actually defining new complex datatypes (a data structure and a set of operations on that data structure), only using the lowest level tools the language provide. IOW您实际上是在定义新的复杂数据类型(一个数据结构和对该数据结构的一组操作)时,仅使用该语言提供的最低级别的工具。

Classes are actually a way to define such a data type at a higher level, grouping together the data and operations. 类实际上是在更高级别上定义此类数据类型的一种方法,将数据和操作分组在一起。 They also offer a lot more, specially polymorphism , which makes for more generic, extensible code, and also easier unit testing. 它们还提供了更多的功能,特别是多态性 ,它使代码更通用,可扩展,并且使单元测试更加容易。

Consider you have a file or a database with products, and each product has product id, price, availability, discount, published at web status, and more values. 假设您有一个包含产品的文件或数据库,并且每个产品都有产品ID,价格,可用性,折扣,以网络状态发布以及更多值。 And you have second file with thousands of products that contain new prices and availability and discount. 您将拥有包含数千个包含新价格,新产品和折扣的产品的第二个文件。 You want to update the values and keep control on how many products will be change and other stats. 您想更新值并控制要更改的产品数量和其他统计信息。 You can do it with Procedural programming and Functional programming but you will find yourself trying to discover tricks to make it work and most likely you will be lost in many different lists and sets. 您可以使用过程编程和函数式编程来做到这一点,但是您会发现自己试图找到使之起作用的技巧,并且很可能您会迷失在许多不同的列表和集合中。

On the other hand with Object-oriented programming you can create a class Product with instance variables the product-id, the old price, the old availability, the old discount, the old published status and some instance variables for the new values (new price, new availability, new discount, new published status). 另一方面,通过面向对象的编程,您可以创建一个具有实例变量的产品类,该实例变量包括产品ID,旧价格,旧可用性,旧折扣,旧发布状态以及一些新值(新价格)的实例变量。 ,新的可用性,新的折扣,新的发布状态)。 Than all you have to do is to read the first file/database and for every product to create a new instance of the class Product. 您要做的就是读取第一个文件/数据库,并为每个产品创建Product类的新实例。 Than you can read the second file and find the new values for your product objects. 比您可以阅读第二个文件并找到产品对象的新值。 In the end every product of the first file/database will be an object and will be labeled and carry the old values and the new values. 最后,第一个文件/数据库的每个产品都将是一个对象,并将被标记并带有旧值和新值。 It is easier this way to track the changes, make statistics and update your database. 这种方式可以更轻松地跟踪更改,进行统计和更新数据库。

One more example. 再举一个例子。 If you use tkinter, you can create a class for a top level window and every time you want to appear an information window or an about window (with custom color background and dimensions) you can simply create a new instance of this class. 如果使用tkinter,则可以为顶级窗口创建一个类,并且每次您想要显示信息窗口或关于窗口(具有自定义颜色背景和尺寸)时,都可以简单地创建此类的新实例。

For simple things classes are not needed. 对于简单的事情,不需要类。 But for more complex things classes sometimes can make the solution easier. 但是对于更复杂的事情,类有时可以使解决方案更容易。

I think the best answer is that it depends on what your indented object is supposed to be/do. 我认为最好的答案是,这取决于缩进对象应该/应该做什么。 But in general, there are some differences between a class and an imported module which will give each of them different features in the current module. 但是通常,类和导入的模块之间存在一些差异,这将使它们在当前模块中具有不同的功能。 Which the most important thing is that class has been defined to be objects, this means that they have a lot of options to act like an object which modules don't have. 最重要的是,该类已被定义为对象,这意味着它们具有很多选项,可以像模块所没有的对象一样工作。 For example some special attributes like __getattr__ , __setattr__ , __iter__ , etc. And the ability to create a lot of instances and even controlling the way that they are created. 例如,一些特殊属性,如__getattr____getattr__ __setattr__ __iter____getattr__ __setattr__等,并且具有创建大量实例甚至控制其创建方式的能力。 But for modules, the documentation describes their use-case perfectly: 但是对于模块,文档很好地描述了它们的用例:

If you quit from the Python interpreter and enter it again, the definitions you have made (functions and variables) are lost. 如果从Python解释器退出并再次输入,则所做的定义(函数和变量)将丢失。 Therefore, if you want to write a somewhat longer program, you are better off using a text editor to prepare the input for the interpreter and running it with that file as input instead. 因此,如果要编写更长的程序,最好使用文本编辑器为解释器准备输入,然后使用该文件作为输入来运行它。 This is known as creating a script. 这称为创建脚本。 As your program gets longer, you may want to split it into several files for easier maintenance. 随着程序时间的延长,您可能需要将其拆分为多个文件,以便于维护。 You may also want to use a handy function that you've written in several programs without copying its definition into each program. 您可能还想使用在多个程序中编写的便捷功能,而无需将其定义复制到每个程序中。

To support this, Python has a way to put definitions in a file and use them in a script or in an interactive instance of the interpreter. 为此,Python提供了一种将定义放入文件中并在脚本或解释器的交互式实例中使用它们的方法。 Such a file is called a module; 这样的文件称为模块; definitions from a module can be imported into other modules or into the main module (the collection of variables that you have access to in a script executed at the top level and in calculator mode). 可以将模块中的定义导入其他模块或主模块中(您可以在顶层和计算器模式下执行的脚本中访问的变量集合)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM