3

在一种语言中使用多种不同的数据类型有什么好处?我最近一直在使用 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++ 中需要它们?

4

5 回答 5

4

有几个好处:

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

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

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

于 2011-12-31T09:06:45.193 回答
3

Different types let you check at compile time (at least, in C++) that you're passing the right kinds of things - for instance, if everything took strings, it'd be very easy to accidentally typo 'gray' as, say, 'grey', and possibly confuse the library.

A normal pattern is to do something more like this:

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)

That way you don't wind up repeating yourself if you're using the same kinds of attributes multiple times.

于 2011-12-31T09:04:40.823 回答
1

It's because they are objects if you use this QPen::QPen () then what it does is Construct a default black solid line pen with 0 width. but since it's overloaded you can use parameters for those constructors when you pass a parameter in the QPen class what you send is processed and the result would return. so those are concepts of object orientations. you need to make an instance and that instance will handle the underlying part of it. if you use a string parameter like what you've used in the second example it will just use string type instead Qt.QPen() type. setPen() function asks for an object typed QPen() not string typed variable. the advantage is you don't need to write everything from ground floor. and some parts are predefined like a video game. in video game you can't do a lot of functions. if you shoot at someone he will shoot you or run away so the reaction is depend on the action you make. the action is the parameter and reaction is the return value from one of functions in that class. behind the scene there might a ton of codes which do various tasks. like how he reacts, the timing, whether he runs or walk or fly when you shoot so those are set at default value unless you change them specially. sometimes you don't need to change those default values or it would take time.in that case just pass the action and get the reaction. that's what this does. it's really useful for complex programs.

于 2011-12-31T09:05:42.493 回答
1

Imagine that you make a typo, or a spelling mistake. So for example you write Elipse instead of Ellipse.

If you code with Qwt.QwtSymbol.Elipse the error would be caught before running.

If you code with strings like 'elipse' the error cannot be caught before runtime, and would only be caught when actually calling setSymbol (so if that call appear in an else branch you never take in your particular run, the error will stay unnoticed).

And of course, there are also performance reasons.

There are whole books on this typing question. You could e.g. learn a bit of Ocaml and read Types and Programming Languages by B.Pierce.

See also this question.

于 2011-12-31T09:06:25.893 回答
0

I'm really surprised, that the question got upvotes. Why? Does it show research effort? No! Maybe the OP did research, but he didn't make it obvious.Is it useful? Is it clear? It's clear he has a problem with passing anonymous objects. But why should his personal struggle in gaining knowledge be useful?

You are wondering why you have to take so much "effort" in typing superfluos code, just to make a simple dotted gray ellipse. First you must keep in mind, that with "Qt" you are using an object-oriented framework. So terminology and conceptual wise you are using a set of classes from which you instantiate objects. What you would call types are the classes.

In your example you don't do the following:

grid.setPen(Qt.Pen)

Which would pass to setPen the TYPE Qt.Pen, but you define an object. Contrary to classes objects contains individual values: 5(=Qt.gray), 0, 3(=Qt.DotLine). This is an oversimplification, but it's just to drive the point home.

Like the "type" integer says, that every object of this type (class) can contain whole-number values it doesn't contain the individual values itself. But it defines that every instance of the type (class) integer MUST hold whole-number values. The integer-variables hold instances (objects) of the class with individual values.

Back to your example, you create an object of the class (type) QtPen, which the method setPen does know to handle:

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

Your object just happens to be of the class(type) Qt.Pen. So you are not just passing a TYPE but you are passing the three values you explicitly mentioned as arguments PLUS a TON of other useful stuff implicitly with the object (e.g. CapStyle, MiterLimit, JoinStyle ...)

In python there is no implicit type-checking of arguments. So you could pass, what you proposed:

grid.setPen('gray', 0 ,'dotted')

BUT the method expects some objects which it's familar with and knows how to handle them. A string-OBJECT it doesn't know to handle. So it would be YOUR job to explain what it should do. So you would either have to subclass Qt.Pen with a constructor which can handle your strings, or modify the Qt.Pen class directly and recompiling QT afterwards.

I concede the Qt.Pen class is not the optimal example. So we could create a better example to illustrate the underlying concepts and where you are under false assumptions.

But first i would claim that your "surrogate" question originates from a major confusion to understand the object-oriented paradigm, but couldn't discern the source of your confussion in the lack of greater insight - it's the chicken/egg problem.

There are many roads to rome, which you take is yours to decide. But with the decision to use "Qt" you already decided on a general set of roads. And those are build for objects.

Let us assume we want to draw some houses. So we define a method draw_house using the magical_drawing_routine (which by the way is exactly what you were looking for at your original question):

def draw_house(house):
        magical_drawing_routine(house)

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

Now we got exactly two identical drawn houses without doors, windows or the lovely chimney of our parent's home. (And we are completely ignoring how the magical_drawin_routine knows how to interprete the string-values)

Back to the drawing board we would correct the lack of these:

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)

Now we got exactly two identical drawn houses with doors, windows and the lovely chimney of our parent's home.But wait, the windows and doors have the exact same shape. Back to the drawing board...

after some cylces you would have something like:

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

or we could define classes: class House, class Window, class Door, class Chimney with reasonable default-values.

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)

if your using the door for your parent only one time, you can forgoe the pdoor definition and instantiate the object on-the-fly while passing the arguments, by gerenating an anonymous object (no variable attached): parentshome = House(Door(...), ...)

So the simple answer is: you don't pass types! You pass objects, which normaly encapsulte complexities. But for awful simple objects it might look like your overcomplicating simple stuff - but that is just how it looks like.

于 2011-12-31T09:20:03.917 回答