Not possible to hide local variables

Chris Angelico rosuav at gmail.com
Thu Apr 30 08:01:18 CEST 2015


On Thu, Apr 30, 2015 at 3:10 PM, Marko Rauhamaa <marko at pacujo.net> wrote:
> Steven D'Aprano <steve+comp.lang.python at pearwood.info>:
>
>> If you have a Java background, you might find this useful:
>>
>> http://dirtsimple.org/2004/12/python-is-not-java.html
>>
>> http://dirtsimple.org/2004/12/java-is-not-python-either.html
>
> Unfortunately, I didn't find those articles all that insightful.
>
> The one big difference between Java and Python is interfaces vs
> ducktyping. In Java, you do everything through formal interfaces. In
> Python, you do nothing through formal interfaces.

The other big difference between C++/Java and Python is that the
former have everything hidden by default, and the latter has
everything public by default. Compare:

class Point {
    int x, y;
public:
    Point(int _x, int _y): x(_x), y(_y) {}
    int get_x() {return x;}
    void set_x(int newx) {x = newx;}
    int get_y() {return y;}
    void set_y(int newy) {x = newy;}
};

void interpolate_points(Point from, Point to, Point **target, int count)
{
    int delta_x = to.get_x() - from.get_x();
    int delta_y = to.get_y() - from.get_y();
    for (int i=0;i<count;++i)
        target[i] = new Point(from.get_x() + delta_x*i/count,
from.get_y() + delta_y*i/count);
}


class Point(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

def interpolate_points(from, to, count):
    delta_x = to.x - from.x
    delta_y = to.y - from.y
    return [Point(from.x + delta_y*i/count, from.y + delta_y*i/count)
for i in range(count)]

Okay, part of the improvement is the list comp rather than C-style
array return, and you could improve on that some in C++ even; but the
rigmarole of getters and setters is a completely unnecessary bug
magnet. (There's one in the above code. I was going to fix it, but
it's more indicative to leave it there.) Most classes do not need that
overhead. In the rare cases where they do, Python lets you smoothly
shift from a simple member to a property, so you can add logging or
whatever. (Though... don't abuse that. I've seen code that puts
@property on functions that do *network operations*, I kid you not.
This completely violates the expectation that attribute lookup is
simple and cheap.) As a small side benefit, there's no hassles about
naming ("get_x" vs "_x" vs "x"); you could avoid _x by using a
Python-style "this->x" everywhere in the C++ code, but that won't fix
get_x.

So clearly Python has the advantage, right? Well, not so clear. The
philosophical abhorrence of remote mutation in C++ makes it a lot
easier to reason about the code - you can look at the class definition
itself and guarantee you can see every change to a private member.
(Aside from naughty pointer manipulation and stuff. But in Python, we
have to say "Aside from fiddling with ctypes", so this is like the
Mistform Ultimus disclaimer[1].) In Python, you have to balance that
in application code; is it safe to change some object's member? Can
you just reach in and change the "read_callback" member to be a new
function reference, or might it have been referenced somewhere else?
Will you cause problems for yourself by replacing this actual file
with a StringIO file-like object? How can you know?

So the freedom is there, but it has to be used intelligently.

ChrisA

[1] eg http://archive.wizards.com/Magic/Magazine/Article.aspx?x=mtg/daily/arcana/1370
and http://archive.wizards.com/Magic/magazine/article.aspx?x=mtg/daily/arcana/1300



More information about the Python-list mailing list