2 May 2011, 1:00am
Programming:
by

14 comments

Praise for Python

Coming from a C/C++ background I really appreciate the following about Python:
  • Simplified Memory management
    I am so much more productive when I am not having to worry about pointer related errors e.g. pointer math or sweat the subtleties of memory management e.g. memory alignment while writing code.
  • Less structural syntax
    After using Python for a while I really appreciate it’s use of indentation to give a program structure, as it makes python source code much more concise than C/C++.
  • No compiling or linking
    It is so much easier to stay in the flow when your not waiting 5-30 minutes for compilation and linking.  I’ve recently taken to running PyLint when I miss the feedback from a compiler/linker on my program structure and to learn the coding style outlined in the Python Style Guide.
  • Selective imports
    Having worked on large scale C/C++ projects for most of my career I really appreciate the ability to only import what I want from modules and the option to also rename (or alias) what I’ve imported.
  • Batteries included philosophy
    The sheer scope of the library of modules included in Python means I can spend more time writing the interesting parts of my programs, as most of the time the utility functionality I need is just an import away.
  • Package management
    The Python Package Index (PyPi) and Setup Tools module make installing most python modules as simple as ‘easy_install <module_name>’.
  • Duck typing
    Python’s use of Duck Typing emphasizes interfaces over types which makes it so much easier to supply my own classes to standard library functions, as I only have to implement as much of the interface as is required.
2 May 2011, 4:21am
by Adam Skutt


Python still has pointers. If you’re routinely doing pointer math in C++, then you’re writing your code wrong and you need to change the way you’re writing code. In C, pointer math is unfortunately much less avoidable but there are still ways to avoid the pitfalls.

I’m not exactly sure what the space-saving part of indentation-based syntax is supposed to be: it saves typically one-line, two at most, per block. And it makes what would otherwise be useful features, like lambda blocks, difficult to implement.

PyPi is great for developers, OK for system integrators, and a nightmare for administrators. Also, the assumption of the various scripts that everyone has an Internet connection is both preposterous and insulting.

C++ has duck-typing too, through templates. It’s not an accident that the STL and large portions of the library use templates.

Good observation, I totally agree with you Deniel over you points… I am to0 a promoter of python by choice…

Best Wishes
http://www.TechnoBits.net – Latest buzz, tips and tricks in software development.

I didn’t know Python had a pointer type, as I’ve yet to need to use a pointer in Python. From my experience allot of bugs in large scale C++ projects come down to pointers being used incorrectly.

The space saving is two lines per function or control/flow block e.g. if statement or loop. This saving adds up to a good number of lines over even a short program.

PyPi is much better than anything I’ve yet seen for C/C++, easy_install works most of the time and is allot easier than porting C/C++ libraries between platforms.

I hadn’t realised duck typing was possible in C++. Sadly at work we don’t use the standard STL implementation or templates for performance reasons.

To be clear I’m not claiming either language is superior to the other, I’m stating what I like about Python.

2 May 2011, 2:21pm
by Adam Skutt


> I didn’t know Python had a pointer type, as I’ve yet to need to use a pointer in Python.

All variables in Python are pointers. You actually can’t get anything but a pointer type (unlike Java or C#, which do have some primitive types). Pointers have two common properties:
* They are pass-by-value, so mutating a pointer passed as a parameter doesn’t change the pointer’s value in the callee.
* They can be reseated or made to point to another object, unless made immutable.
(You can trivally write some code to test both of these points. I’ve omitted it for brevity).
This is true of C and C+ too; pointer arithmetic is not a fundamental property of all pointers (void* pointers; function pointers). FWIW, they’re not hardware addresses either. (segmented architectures do all sorts of funny thing; member-function pointers are almost always some sort of struct).

Pointer errors are the chief source of bugs in most languages. In C and C++ you get crashes, in Java and C# you get NullPointerException, in Python you get various exceptions related to None appearing where it should not. The difference is that in Java, C#, and Python, pointer errors have language-defined error semantics as opposed to undefined language semantics.

> The space saving is two lines per function or control/flow block e.g. if statement or loop. This saving adds up to a good number of lines over even a short program.

Most people do not write:
if (x)
{
}
in C or C++. GNU is the exception, not the rule. You missed the bigger point though: why should I care? If two lines per block is making a big difference in readability, my code has much bigger problems.

> PyPi is much better than anything I’ve yet seen for C/C++, easy_install works most of the time and is allot easier than porting C/C++ libraries between platforms.

You miss the point: it’s not apparent that what PyPI, distools, and setuptools are trying to solve is inherently a good thing. It’s only advantageous for local development (on the Internet). In every other use case, I end up having to roll my own solution anyway because they’re so incredibly deficient. That’s not especially a great advantage for me: setting up development is the thing I need the least amount of help with.

> To be clear I’m not claiming either language is superior to the other, I’m stating what I like about Python.

I get that, and that’s fine. However, the problem is you’re implying these things are advantageous when in many situations they are not advantageous. C++ either has these features or semi-reasonable replacements.

3 May 2011, 7:33am
by J. Cliff Dyer


Adam:

Python does not have pointers. It has objects. There are similarities, but the coding semantics are different enough that the terminology used deserves to be different as well. Not making that distinction led you into one notable error in describing how python works. It is absolutely not “call by value,” and does not have the behavior you describe.

Variables in python are essentially labels that get tagged to objects. They do not “contain” things, and do not own the thing they refer to. Objects can be mutable or immutable, but that has nothing to do with the name we assign them to. So if I have x = 4, and then I assign y=x, then y becomes a new label on the object 4 (which is an object of type int). If you then assign x=5, y will still be a label on the object 4, not because 4 was passed “by value,” but because the object 4 was not changed. The label x was just applied to a new object.

The significance of this difference becomes clear when you take the case of a mutable object. Say we have a list, [1], and we assign it to p, using p=[1]. Now we assign it to q, q = p. Both p and q now point to the same object, [1]. If I do p.append(2), p will refer to the same list, which will now contain two elements, [1, 2]. If we were passing by value, q would refer to a list [1], but in python, it still points to the same list as p, which has the value [1, 2]. In this case, neither variable has been reassigned, and they both refer to the same object, so changes to one are visible on the other. If you then assign p to a new object, p = [3], q will still refer to [1, 2].

It’s not exactly pointer based, because there is no pointer to look at, and you certainly can’t do pointer arithmetic on them, though there are certainly similarities. It is absolutely not pass by value. It is closer to pass by reference, but calling it that leads to some pedagogical confusion, especially for people coming from real pass-by-reference languages, so pythonistas tend to call it pass-by-object instead.

3 May 2011, 7:47am
by Peter Wang


Adam, you are simply incorrect about a number of things.

1. Python does not have pointers, in the C++ sense. You mean to say that everything in Python is a *reference*. But even this is incorrect, since Python has several literal types (numeric types, strings, None).

2. Python does not have “Null pointer exceptions” in the C++ sense. It is incorrect to equate the use of None and *value* errors related to it with the deeper, more troublesome null pointers of C. The appearance of None in an unexpected place is usually a result of dynamic binding and late dispatch, and is no different than any other kind of value error that can occur with dynamic binding.

3. C++ templates are not the same as the “duck typing” (or, more formally, dynamic dispatch) of Python. Python’s metaprogramming capabilities are vastly beyond what C++ can easily achieve with templates. I know enough C++ to know not to make absolute statements about what’s possible and what’s not with the template system, but most programmers will be able to do far more powerful metaprogramming with Python’s first-class functions, classes, and types, than they will every be able to achieve with C++ templates.

4. Regarding C/C++ syntax, it’s been my experience that a lot of folks put opening braces on a new line, and almost everyone puts closing braces on a new line. The space savings from indentation syntax that Daniel talks is not a point I would ever personally make, since it is small relative to the space savings from Python’s awesome syntax and built-in container types, but your counter to his point is, at best, speculative, and seems to run counter at least to my experience.

5. With regards to setuptools and easy_install, I take it you are trying to say that those are not great mechanisms for distributing Python applications? If so, then you are dismissing a huge use case, which is the people who do web applications and can use setuptools, distribute, and pip to easily deploy their applications. I’ve done a number of rich-client Python applications over the years and those used eggs as well. Even for local development purposes, being able to do “easy_install ” is much simpler than downloading and building C libraries (and their dependencies) from source, by a long shot. I can’t imagine anyone really arguing the opposite.

Overall, I find it telling to look at which of Daniel’s points you chose to counter, and which you ignored:

Countered: pointer errors, shorter code via indentation, package management, duck typing

Ignored: simplified memory management, faster development iteration due to interpreted nature of the language, nice import syntax/features, amazing standard library

I think that most Python programmers would say that the latter list is far more important and compelling than the former, with the exception of duck typing (which you incorrectly characterized as being comparable to C++ templates). All of the speed, power, and fun of Python really comes from that second list, and you have no answer to that.

I don’t mean to write all of the above as some C vs Python holy war thing, but I felt the need to refute your misinformation about Python and how it stands in comparison to C or C++.

3 May 2011, 9:17am
by Adam Skutt


Python most certainly does have pointers, with equivalent semantics to C++. Behold:
class A(object):
pass
def f(x):
print “start f: %d” % id(x)
x = A()
print “leave f: %d” % id(x)

a = A()
print “a: %d” % id(a)
f(a)
print “a: %d” % id(a)

Pointer semantics. You can replace that with int or any other type too, and it’ll still work. In C++:
#include
struct A {};
void f(A* x) {
std::cout << "start f " << x << std::endl;
x = new A(); // Leaky, but ok for demo.
std::cout << "stop f " << x << std::endl;
}

int main() {
A a;
std::cout << "a " << &a << std::endl;
f(&a);
std::cout << "a " << &a << std::endl;
}

The two programs give equivalent outputs. Pointer semantics. It's all Python's got. To say otherwise means you don't really understand the semantics of either language.

3 May 2011, 9:49am
by Adam Skutt


> Python does not have pointers. It has objects.

And the only way to access an object is through a pointer. It is possible to have objects and not have pointers (e.g., C++ value types). I hope you’ll take the time to write the code yourself to validate this before attempting to rebut me further.

> Variables in python are essentially labels that get tagged to objects. They do not “contain” things, and do not own the thing they refer to.

Which is the very definition of a pointer, beyond the “they do ‘contain’ things” part, which is simply absurd! Variables always contain something.

> If we were passing by value, q would refer to a list [1]…

Stop. If they’re in the same scope, then no passing whatsoever took place! Passing means providing the variable as a parameter to a function! Why are you talking about code that doesn’t involving calling functions?

> It’s not exactly pointer based, because there is no pointer to look at,

It is precisely pointer-based. C++ value-types don’t have equivalent semantics (A x; A y; creates two objects) and C++ reference-types don’t have equivalent semantics (they cannot be reseated). We’re left with pointer semantics by mere process of elimination.

3 May 2011, 10:21am
by Adam Skutt


>> You mean to say that everything in Python is a *reference*.

No, I do not, because they lack reference semantics; variables can be reseated to refer to multiple objects. If you mean a reference in the black box, “an object that refers to an another object”, sure, but that’s all pointers are. You are almost certainly imbuing C and C++ pointers with properties they do not actually possess. What do you think C and C++ pointers actually are?

> But even this is incorrect, since Python has several literal types (numeric types, strings, None).

They still obey pointer and not value semantics. The immutability clouds the issue. Again, you can trivially write code to test this out, and I encourage you to do so.

> The appearance of None in an unexpected place is usually a result of dynamic binding and late dispatch, and is no different than any other kind of value error that can occur with dynamic binding.

The reason None appeared when you did not expect it is a coding error, just like NULL appearing when you did not expect it. The fact that None is also the default return from functions doesn’t matter to my point at all, and how could it? You really think there’s zero Python code out there that uses None in the exact same situations and fashion that I would use NULL in C++? Because that’s what it would take to agree with me.

> 3. C++ templates are not the same as the “duck typing” (or, more formally, dynamic dispatch) of Python.

Dynamic dispatch is not duck typing and vice-versa. Duck typing means that the passed object is examined directly to see if supplies the necessary attributes to be compatible with the function, as opposed to examining it’s type hierarchy. It’s plainly possible to do this statically (C++ templates) and dynamically (Python). In statically-typed languages, it’s typically called structural typing; in dynamic languages, duck typing. But the behavior from the programmer’s view is exactly the same. C++ in particular is much closer to the notion of duck typing, due to the way templates are instantiated. The compiler really does examine only the members required to complete the template (allowing other methods that do not even compile to slip-by), which is not true of other structural type systems. This is both a blessing and a curse, obviously.

Dynamic typing has other benefits that C++ templates do not provide, but they have nothing to do with duck typing.

> Regarding C/C++ syntax, it’s been my experience that a lot of folks put opening braces on a new line, and almost everyone puts closing braces on a new line.

See http://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS and others.

> With regards to setuptools and easy_install, I take it you are trying to say that those are not great mechanisms for distributing Python applications?

They’re pretty plainly crap, and even the Python community thinks so! What’s especially appalling is that it took more than one try to get right, in the era of Linux and all the package managers out there. That’s the blind leading the blind (off a cliff). Of course, they’re still missing relatively basic functionality, so I don’t expect progress anytime soon.

> If so, then you are dismissing a huge use case, which is the people who do web applications and can use setuptools, distribute, and pip to easily deploy their applications.

Yeah, like I said, it’s great when the developer does everything. I don’t work in such a world, nor do I wish to.

> Even for local development purposes, being able to do “easy_install ” is much simpler than downloading and building C libraries (and their dependencies) from source, by a long shot. I can’t imagine anyone really arguing the opposite.

Sure, if that’s the only use case you care about. Again, being concerned only with that use case is both preposterous and insulting.

> Ignored: simplified memory management, faster development iteration due to interpreted nature of the language, nice import syntax/features, amazing standard library

Overall, I find it telling (and insulting) that you can’t even list the points I ignored correctly, or even recite them correctly! I ignored them because I didn’t see the need to mention points I generally agree with. You shouldn’t read so deeply into such things. People omit details all of the time, especially with such a small comment box.

3 May 2011, 1:25pm
by Peter Wang


> What do you think C and C++ pointers actually are?

Addresses in memory that can be (and are frequently) clobbered to produce segfaults. Their primary utility to the programmer is because certain operators will take them to produce useful references to semantically interesting things (like values).

You are putting too much of a C++ tint on the word “reference”, what with unseating etc. The reason why I prefer to say that Python variables are references and not pointers is because the latter implies that there is some way to mutate the contents of the pointer variable itself in a lower level way. In my experience, across the literature (not specifically limited to C++ or C books), “pointer” has a specific meaning moreso than “reference”. I have seen the latter used to describe Python and Java values in many instances. Speaking as someone who has taught Python courses, if you tell someone that all Python variables are pointers, they’re much more likely to get the wrong idea than if you tell them that they’re references.

> They still obey pointer and not value semantics.

Really? Python integers don’t obey value semantics? Either I’m way out of the loop, or you misspoke here.

> The reason None appeared when you did not expect it is a coding error, just like NULL appearing when you did not expect it. … You really think there’s zero Python code out there that uses None in the exact same situations and fashion that I would use NULL in C++? Because that’s what it would take to agree with me.

All errors are coding errors; to lump *value errors* with *memory exceptions* into this single term renders the term useless. My original point was that Python does not have anything nearly as fatal as the null pointer exceptions of C and C++. Fatal is a subjective term, and depends somewhat on the skill of the programmer, but the bottom line is that you can’t do arithmetic in Python and end up with a segfault. You can trivially do so in C. Worse, that same type of arithmetic is standard idiomatic practice for much of the programming that happens with C and C++. You may be God’s gift to programmers, but the fellow that wrote the library you depend on might not be.

> Dynamic dispatch is not duck typing and vice-versa. Duck typing means that the passed object is examined directly to see if supplies the necessary attributes to be compatible with the function, as opposed to examining it’s type hierarchy.

This is correct, but dynamic dispatch is the mechanism by which Python achieves duck typing. (There is no object introspection before function application, only at the actual point of attribute lookup.) If the original author’s praise was strictly limited to just duck typing, and not the rest of the power offered by Python’s introspection and dynamic typing system, then you’re right that C++ does offer parity with this via templates, and I cede the point.

> > Regarding C/C++ syntax, it’s been my experience that a lot of folks put opening braces on a new line, and almost everyone puts closing braces on a new line.
> See http://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS and others.

Yes.. did you look at this? “Allman” style is cited by ANSI and is used by Microsoft both internally as well as in all of its documentation/MSDN for C, C++ and C#. That seems to run counter to your claim that “most people do not write [Allman style]; GNU is the exception…”

> They’re pretty plainly crap, and even the Python community thinks so! What’s especially appalling is that it took more than one try to get right, in the era of Linux and all the package managers out there.

Yep, the Python community does have negative sentiments towards setuptools and distutils, the former because of community-related issues and the latter because its architecture is suboptimal for what it’s trying to achieve. However, everyone still uses easy_install and puts their libraries on PyPI. Actions speak louder than words; the continued use of these tools in spite of their crappiness is a testament to their itch-scratching power.

If you feel that Linux package managers are a better solution to this problem, then by all means contribute to the conversation and help push distutils2 or distribute or pip or whatever in the right direction. Be warned, however, that you’ll need to come up with a port of apt or rpm to Win7, Win64, Win32, Win2k, etc., etc. And you’ll have to help the Numpy and Scipy guys out when they ask why your fantastic packaging tool craps out when trying to build 64-bit ATLAS libraries on HP-UX, or why it can’t find their FORTRAN compiler (located on a mapped network share) on 64-bit Windows XP, even though they have local Admin privileges and the cluster’s Active Directory group policy gives them read access.

Armchair packaging is easy.

> > Even for local development purposes, being able to do “easy_install ” is much simpler than downloading and building C libraries (and their dependencies) from source, by a long shot. I can’t imagine anyone really arguing the opposite.
> Sure, if that’s the only use case you care about. Again, being concerned only with that use case is both preposterous and insulting.

I said “even”. You hand-wave away the use case of a large number of users (e.g. people who build web apps), who find eggs to be a very handy way to deploy. Just because it doesn’t suit your particular uses doesn’t mean that it’s completely crap.

The ironic thing is that I personally have argued almost your very same point in the past, namely, that many of these tools do not sufficiently take into account the needs of people building rich-client applications, or who have deployment needs that don’t or can’t dynamically install at runtime. (Of course, we always have an out, which is to merely install the packages flat into our development environment and then use traditionally installer builders.)

However, I never took the viewpoint that the problem they are trying to solve doesn’t exist, or that these tools don’t add value to the Python ecosystem. That seems like a very strange position to take, given that every single Python library I’ve looked at in the last two weeks tells people to run easy_install or download from PyPI.

3 May 2011, 3:35pm
by Adam Skutt


> Addresses in memory that can be (and are frequently) clobbered to produce segfaults.

They are no such thing and the standard is crystal clear that they are no such thing. FFS dude, I even listed concrete of examples of cases where they are no such thing!

Why should I even waste my time responding to you at all when you clearly aren’t reading what I wrote? There’s no point in bothering until you retract such foolishness; as long as you believe their pointers are “memory addresses” you clearly don’t understand the C or C++ languages, by standard or implementation, enough to discuss how they work.

3 May 2011, 6:34pm
by Peter Wang


>> Addresses in memory that can be (and are frequently) clobbered to produce segfaults.
>They are no such thing and the standard is crystal clear that they are no such thing.

Actually, that was the one part of my post that was tongue-in-cheek. I think you are also confusing me with another commenter in this thread, who does seem to be a bit confused about what pointer semantics mean. I can’t really speak for him, but I will respond to your claim that “the standard is crystal clear that” pointers are not addresses in memory. The following are all from my copy of Stroustrup, 3e:

pg. 87: “That is, a variable of type T* can hold the address of an object of type T.”

pg. 88: “The implementation of pointers is intended to map directly to the addressing mechanisms of the machine on which the program runs.”

pg. 88: “It is possible to perform some arithmetic operations on pointers to array elements.”

Feel free to email Bjarne Stroustrup at bs@cs.tamu.edu and let him know that he “clearly doesn’t understand the C or the C++ languages, by standard or implementation.”

4 May 2011, 4:18am
by Adam Skutt


Then show me how to implement a member-function pointer with just an address. I’ll wait. Moreover, go look at how the actual compilers do it (not with a mere address, that’s for certain).

Explain to me how to resolve all of the vtable issues related to multiple inheritance and virtual inheritance with just a memory address.

Explain to me why there’s no direct support for segmentation if pointers are supposed to “map directly to the addressing mechanisms of the machine on which the program runs.”

Explain to me why the aliasing rules differ from essentially all hardware in existence?

If pointers are just memory addresses, then why does memcpy() et al. not work on non-POD objects?

Also explain what an “address” is. I’m 100% certain you’ll get it wrong, because it’s a horribly ill defined concept.

The fact that you don’t recognize the fact the C++ standard is horribly contradictory in multiple places really just reinforces my early comment about your understanding of the language.

(I don’t even know why I’m responding. It’s plainly apparent you’re not just ignorant, but willfully so.)

4 May 2011, 5:04am
by Guy Passing By


> the standard is crystal clear that they are no such thing [addresses]
> pg. 87: “That is, a variable of type T* can hold the address of an object of type T.”
> the C++ standard is horribly contradictory

Good day.

 

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>