当前位置: 首页 > 知识库问答 >
问题:

为什么类大多通过函数实例化?

游勇军
2023-03-14

为了科学目的,我已经使用python好几年了。最近我对类的编写更加熟悉了,但我觉得我缺少了一些关于实例化类的标准方法。

假设我定义了一个类MyClass

class MyClass:
    def __init__(self):
        pass

然后我知道我可以用

x = MyClass()

这很好,完全符合我的预期。

然而,在我看来,当我使用标准库或numpyscipy中的代码时,我不会以相同的方式创建对象:据我所知,我通常不会使用类的名称来实例化它。据我所知,这意味着我既不使用类方法,也不使用类的默认构造函数,而是使用在类之外定义的其他函数。

例如,numpyrandom模块使用类生成器来生成随机数。但是,numpy明确建议不要使用类构造函数来获取生成器实例,而是使用随机模块中的默认函数。所以如果我想生成随机数,我使用

rng = numpy.random.default_rng()

创建Generator实例。这是在没有显式使用类的名称的情况下完成的。

在我看来,我使用的大多数代码都是用后一种方式编写的。为什么会这样?直接调用默认类构造函数是否被认为是不好的做法?在模块中使用单独的函数来创建类实例是否被认为是更好的做法?这仅仅是因为在创建类的实例之前通常必须进行一些预处理吗?(我想不会,因为那样的话,为什么不在初始化类时这样做呢?)


共有2个答案

段干玺
2023-03-14

我想是np。数组调用来创建np。ndarray可能是通过调用另一个函数来创建对象的最常见方式之一。下面是一个解释。

在numpy中,ndarray和array有什么区别?

我不能回答所有我们使用函数来“包装”对象构造的情况,但是我在许多情况下使用这样的函数来简化对象创建,从而产生更干净的代码。我可以谈论这样的情况。

例如,基础类定义可能会公开很多参数。在99.9%的情况下(比如说),要求用户为类的所有参数提供参数值可能没有意义。这些“虚假”参数可能是固定的,或者在大多数情况下可以从其他参数值推断出来(例如,在大多数情况下,参数b是2x参数a)。在这99.9%的情况下,显式地为这些参数提供值的代码变得很难处理,因此编写了一个包装函数以使其更简洁。

可以使用默认参数来处理许多这样的情况,但将参数值的推断推到类的init函数本身可能没有意义。例如,虽然像b=2*a如果a不是其他的b这样的东西似乎合理地放在init函数中,其中a,b是参数,但实际上可能不是那么简单(例如,b可能与a,c,d,f等有复杂的关系,或者它可能是类对象本身),或者可能需要进行1000个这样的参数推断。因此,合理的做法是将这种“粘合”代码(这是一种易于使用的定制)分离到另一个函数中,并保持基本代码(实现特定功能)干净、切中要害。

我们想编写另一个类包装器而不是函数包装器吗?在这种情况下,新的类包装器将呈现一个简化的接口。但是在这种情况下编写一个类包装器是不必要的,因为类意味着许多事情,而函数意味着只是程序执行。

请注意,这种情况主要发生在库类型代码的情况下,这些代码有最多的用例,您希望使大多数人使用起来最容易。大多数“用户”代码不存在这样的问题,因为我们只是为特定的应用程序编写类。所以在实践中,当我们编写应用程序时,我们应该尽可能直接使用构造函数创建类。

还有一种流行的工厂设计模式,一些@ekhumoro在上面提到过,与此非常相似。但根据教科书的定义,工厂设计模式似乎仅限于超级/子类(我可能错了,这可能是无用的语义)。

冯德佑
2023-03-14

不,使用普通构造函数是不错的做法,但有时使用替代构造函数会很有用。

(并非一份完整的清单,亦无先后次序)

  • 将对象的创建与其实现分离<解耦通常是面向对象编程的目标
  • 隐藏复杂性
    构造函数可以有许多参数,但通常需要一个默认对象
  • 更容易读/写和理解
    numpy。随机的默认值(vsnumpy)。随机的生成器(numpy.random.PCG64())
  • 一个工厂,根据有时复杂的条件创建并返回一个(不同的)对象
    例如,python的open()为文本文件和二进制文件返回不同的对象

在其他一些语言中,它们将被实现为它们实例化的类的类方法,甚至是一个新类的类方法
这也可以在python中完成,但如果它们在模块级实现为函数,则通常会更短,使用更方便。

 类似资料:
  • 问题内容: 在开发Java时,您始终了解到最好使用List接口作为存储列表的变量的类型来创建ArrayList。 但是,通过查看捆绑包中包含的许多android示例,他们使用Class创建了列表。 有什么理由要这样做吗?是显式设置Class的速度更快,更轻便还是其他? 问题答案: 在资源受限的环境(如Android设计的手机)中,最好避免使用Interface,因为它涉及额外的虚函数调用。

  • 什么是MySQL的多实例? 简单的说多实例就是在一台机器上开启多个不同的服务端口(如3306,3307),运行多个MySQL服务进程,这些服务进程通过不同的socket监听不同的服务端口来提供各自的服务. 这些MySQL多实例共用一套MySQL安装程序,使用不同(也可以是相同,建议不同)的my.cnf配置文件,启动程序,数据文件.在提供服务时,多实例MySQL在逻辑上看是各自独立的,多个示例自身是

  • 本文向大家介绍Java通过匿名类来实现回调函数实例总结,包括了Java通过匿名类来实现回调函数实例总结的使用技巧和注意事项,需要的朋友参考一下 在C语言中,函数名可以当做函数指针传递给形参从而实现回调 在C++11中,实现回调还可以通过函数模板和lambda表达式的方式 而假如回调函数的代码实现较为复杂,且具有重用价值,lambda表达式这种一次性的方案就不太适合,在C++11之前,是通过函数对象

  • 我在Rust中尝试函数指针魔术,最后得到了一个代码片段,我完全无法解释它为什么要编译,甚至无法解释它为什么要运行。 我无法解释为什么调用的方法是在

  • 我正在阅读每个程序员都应该知道的内存https://people.freebsd.org/~lstewart/articles/cpumemory.pdf,它说内联函数使你的代码更可优化 例如 :特别是函数的内联允许编译器一次优化更大的代码块,这反过来又可以生成机器代码,从而更好地利用处理器的管道架构。 and: 当程序的较大部分可以被视为单个单元时,代码和数据的处理(通过死代码消除或值范围传播等

  • 问题内容: 我似乎在使用样式语法实例化嵌套类类型的空数组时遇到问题: 这是我误会的东西吗(早在我喝咖啡之前,但我已经查看了发行说明,并且我认为您应该能够引用这样的嵌套类)或Beta 7中的错误? 这可以作为一种解决方法: 问题答案: 这肯定看起来像是编译器中的错误,尤其是 允许 您实例化嵌套类的空数组就好了。它根本不适用于初始化程序语法。 我会提出一个错误。同时,对于遇到问题的任何人,都可以通过使