拥有许多不同的数据类型有啥好处?

Posted

技术标签:

【中文标题】拥有许多不同的数据类型有啥好处?【英文标题】:What is the benefit of having many different data types?拥有许多不同的数据类型有什么好处? 【发布时间】:2011-12-31 08:48:57 【问题描述】:

在一种语言中使用多种不同的数据类型有什么好处?我最近一直在使用 pyqt 和 pyqwt,我发现自己不断输入这样的行:

grid.setPen(Qt.QPen(Qt.Qt.gray, 0, Qt.Qt.DotLine))
curve.setSymbol(Qwt.QwtSymbol(Qwt.QwtSymbol.Ellipse,
                              Qt.QBrush(),
                              Qt.QPen(Qt.Qt.black),
                              Qt.QSize(5, 5)))

如果上面的行改为以下行会丢失什么?:

grid.setPen('gray', 0 ,'dotted')
curve.setSymbol('ellipse', 'k', (5,5))

即使出于某种技术原因需要特定类型,字符串是否不能在需要它们的方法内转换为那些类型?

这是因为 pyqt 和 pyqwt 只是 C++ 库的绑定吗?如果是这样,为什么在 C++ 中需要它们?

【问题讨论】:

这是不可能的,表明你没有考虑周全。按照您提出的方式,每个功能都必须了解所有内容。重新考虑你的问题,这样很有趣。 如果这个问题太搞笑了,我深表歉意,我是自学编程,不太懂理论。你能解释一下为什么它这么笨吗?我学的第一个编程语言是 Matlab,它可以让你完全按照我说的去做:plot(x, 'r-') en.wikipedia.org/wiki/Data_type 已经包含了一些答案,即使没有接受过正规的计算机科学教育,您也可以轻松找到它。另见我的回复。 您应该评估并接受一些答案。 @DonQuestion 这不是搞笑恕我直言。那么函数和方法的正常 python 格式是什么? 【参考方案1】:

有几个好处:

    类型安全语言(如 C++)具有在编译时(相对于运行时)发现许多错误的优点。这意味着使用 Qt.grey(注意 e)将无法编译,因为未定义类型。

    更好的性能和更少的内存。幕后Qt.gray是一个数字,数字运算比字符串快很多。

在 pyqt 案例中,因为该库包装了一个 C++ 库,所以它看起来更像 c++ 而不是 Python 代码。

【讨论】:

既然 python 不是编译语言,这是否意味着唯一的好处是更好的性能? 从技术上讲,Python 中的许多字符串也是幕后的数字 (en.wikipedia.org/wiki/String_interning)。 Python 解释器正在解析脚本,并且正在解释与文件不同的东西(通常是某种抽象语法树...),因此在解析脚本时会发现一些错误。 【参考方案2】:

不同的类型可以让你在编译时检查(至少在 C++ 中)你传递了正确类型的东西——例如,如果所有东西都带字符串,那就很容易了不小心将'gray' 拼写成'grey',可能会混淆图书馆。

一个正常的模式是做更多这样的事情:

greypen = Qt.QPen(Qt.Qt.gray, 0, Qt.Qt.DotLine)
blackpen = Qt.QPen(Qt.Qt.black, 0, Qt.Qt.DotLine)
# ...
grid.setPen(greypen)
# ...
grid.setPen(blackpen)

这样,如果您多次使用相同类型的属性,您就不会重复自己。

【讨论】:

为什么'grey' -> 'gray' 错字比 Qt.Qt.grey -> Qt.Qt.gray 更糟糕?两者看起来都一样容易制作。由于 python 被解释,这两个错误是同时捕获的吗? 不,因为解释会在脚本文件加载后立即将其更改为某种内部表示 - 在运行它之前 - 并且在该更改期间(您可以称之为解析)会发生一些错误检测。 @jminardi 不,一个会在方法调用中被捕获,一个会被提前捕获。此外,它将依赖方法调用本身来进行所有转换——并且每个方法调用都必须执行相同的转换。通过在整个代码中定义一个可用的常量值,方法变得更简单,错别字可以被 IDE 捕获等等。【参考方案3】:

因为它们是对象 如果你使用这个 QPen::QPen () 那么它的作用是构造一个默认的黑色实线笔,宽度为 0。 但由于它已重载,您可以为这些构造函数使用参数 当您在 QPen 类中传递参数时,您发送的内容将被处理并返回结果。所以这些是面向对象的概念。你需要做一个实例 并且该实例将处理它的基础部分。如果您使用第二个示例中使用的字符串参数,它将只使用字符串类型而不是 Qt.QPen() 类型。 setPen() 函数要求一个对象类型为 QPen() 而不是字符串类型的变量。 优点是您不需要从底层编写所有内容。有些部分是预定义的,就像视频游戏一样。在电子游戏中你不能做很多功能。如果您向某人开枪,他会向您开枪或逃跑,因此反应取决于您所做的动作。 action 是参数,reaction 是该类中某个函数的返回值。在幕后可能有大量的代码可以完成各种任务。比如他的反应,时机,当你射击时他是跑还是走还是飞,所以这些都设置为默认值,除非你特别改变它们。有时您不需要更改这些默认值,否则会花费一些时间。在这种情况下,只需传递操作并获得反应。这就是它的作用。它对于复杂的程序非常有用。

【讨论】:

【参考方案4】:

假设您打错字或拼写错误。所以例如你写 Elipse 而不是 Ellipse.

如果您使用Qwt.QwtSymbol.Elipse 编码,则会在运行之前捕获错误。

如果您使用'elipse' 之类的字符串进行编码,则无法在运行前捕获错误,并且只会在实际调用setSymbol 时捕获(因此,如果该调用出现在else 分支中,则您永远不会在特定运行中使用,错误将不会被注意到)。

当然,还有性能方面的原因。

关于这个typing 问题的书籍有很多。你可以例如学习一点 Ocaml 并阅读 B.Pierce 的 Types and Programming Languages

另见this question。

【讨论】:

【参考方案5】:

我真的很惊讶,这个问题得到了赞成。为什么?它是否显示了研究努力?不!也许OP做了研究,但他没有说出来。有用吗?清楚吗?很明显,他在传递匿名对象方面存在问题。但是,他个人在获取知识方面的努力为什么会有用呢?

您想知道为什么要花这么多“精力”输入多余的代码,只是为了制作一个简单的灰色虚线椭圆。 首先你必须记住,使用“Qt”你正在使用一个面向对象的框架。因此,在术语和概念方面,您正在使用一组从中实例化对象的类。您所说的类型是类。

在您的示例中,您没有执行以下操作:

grid.setPen(Qt.Pen)

这将传递给 setPen TYPE Qt.Pen,但您定义了一个 object。与类相反,对象包含单独的值:5(=Qt.gray)、0、3(=Qt.DotLine)。这是过于简单化了,但这只是为了说明问题。

就像“typeinteger 所说的那样,这种类型(类)的每个对象都可以包含整数值,它本身不包含单个值。但它定义了type(类)integer 的每个实例都必须保存整数值。整数变量包含具有单独值的类的实例(对象)。

回到你的例子,你创建了一个类(类型)QtPen 的对象,setPen 方法确实知道要处理它:

grid.setPen(Qt.QPen(Qt.Qt.gray, 0, Qt.Qt.DotLine))

您的对象恰好属于Qt.Pen 类(类型)。因此,您不仅传递了 TYPE,而且还传递了 您明确提及的三个值作为参数加上一吨其他有用的东西隐含对象(例如 CapStyle、MiterLimit、JoinStyle ...)

在 python 中没有隐式的参数类型检查。所以你可以通过你提出的建议:

grid.setPen('灰色', 0 ,'dotted')

但是该方法需要一些它熟悉并知道如何处理它们的对象。它不知道处理的字符串对象。所以你的工作就是解释它应该做什么。因此,您要么必须使用可以处理字符串的构造函数子类化Qt.Pen,要么直接修改 Qt.Pen 类,然后重新编译 QT。

我承认Qt.Pen 类不是最佳示例。因此,我们可以创建一个更好的示例来说明基本概念以及您处于错误假设的位置。

但首先我会声称您的“代理”问题源于对面向对象范式的理解的重大困惑,但由于缺乏更深入的洞察力而无法辨别出您困惑的根源 - 这是鸡/蛋问题.

通往罗马的道路有很多,走哪条路由你自己决定。但是随着使用“Qt”的决定,您已经决定了一套通用的道路。这些是为对象构建的。

假设我们要画一些房子。因此,我们使用magical_drawing_routine 定义了一个方法draw_house(顺便说一句,这正是您在原始问题中所寻找的):

def draw_house(house):
        magical_drawing_routine(house)

draw_house('parentshome')
draw_house('myhome')

现在,我们得到了完全相同的两栋房屋,没有门、窗,也没有我们父母家的可爱烟囱。 (而且我们完全忽略了magical_drawin_routine 知道如何解释字符串值)

回到绘图板上,我们将纠正缺少的这些:

def draw_house(door, window, chimney):
    magical_drawing_routine(door, window, chimney)

parentshome = ['oak', 'green', 'yes']
myhome = ['beech', 'red', 'no']
draw_house(parentshome)
draw_house(myhome)

现在我们得到了两个完全相同的房子,有门、窗和我们父母家的可爱烟囱。但是等等,门窗的形状完全相同。回到绘图板...

经过一些循环后,你会得到类似的东西:

def draw_house(doormaterial, doorcolor, doorshape, doorwithglass, doorglassparts, windowsnumber, widnowsdistributionpattern, windowsencassing, windowmaterial, windowshape, windowpattern, windowdecoration, chimney):
   ...

或者我们可以使用合理的默认值定义类:class House, class Window, class Door, class Chimney

pdoor, mdoor = Door(a,b), Door(a,Z) 
pwin, mwin = Window(e,f,g), Window(e,f,Y)
pchimney, mchimney = Chimney(h), Chimney(X)

parentshome = House(pdoor, pwin, pchimney)
myhome = House(mdoor, mwin, mchimney)

如果您只为您的父母使用门一次,您可以放弃 pdoor 定义并在传递参数时即时实例化对象,方法是生成一个匿名对象(不附加变量): 父母之家 = 房子(门(...),...)

所以简单的答案是:你不传递类型您传递对象,这通常包含复杂性。但是对于非常简单的对象,它可能看起来像你过于复杂的简单东西——但这就是它的样子。

【讨论】:

我不确定这是不是正确的答案,因为被调用的函数(例如setPen)必须知道(或至少必须处理)其参数的所有变化。一些脚本语言(例如我不喜欢的 Tcl)主要接受字符串。

以上是关于拥有许多不同的数据类型有啥好处?的主要内容,如果未能解决你的问题,请参考以下文章

C语言中各种数据类型有啥区别?

使用抽象类而不是特征有啥好处?

java中基本数据类型和引用数据类型在内存分配上有啥不同

在 SQL 数据库中创建视图有啥好处? [复制]

数据结构与数据类型有啥区别?

将 ref 关键字与引用类型参数一起使用有啥好处?