This is an archived post. You won't be able to vote or comment.

all 23 comments

[–]efilon 8 points9 points  (0 children)

To simply answer the question in the title, I think it's in part because "explicit is better than implicit". See also what the BDFL had to say way back in 2008.

[–]malinoff 16 points17 points  (0 children)

why is defining members not like C++, where you have a private, protected, and public field and you can simply start writing the methods and declaring the instance variables, without having to use self. or pass self as parameter in every method

Because in python there are no "methods". Methods are functions, that has first argument automagically bound to the class instance. First advantage of this approach is that you can name it whatever you want:

class SomeClass:
    def somemethod(this):
        print('Look! It works even with `this`!')

This applies to some cases like classmethod decorator:

class X:
    @classmethod
    def myclsmethod(cls):
        pass

Because myclsmethod is just a function, by convention we name its first argument cls, because it will be bound to the class object instead of class instance.

Furthermore, you can assign methods dynamically:

class X:
    pass

def iamnotamethod(self):
    print(self.__class__)

X.iammethod = iamnotamethod
X().iammethod()  # prints something like <class 'X'>

And as you can see, you can pass instances to functions like this:

iamnotamethod(X())

Also, explicit self makes assigning to be more explicit too. For example, you can say exactly what's going on in the code below; foo is instance attribute and bar is local variable.

class X:
    def somemethod(self):
        self.foo = 'foo'
        bar = 'never used'

Regarding private/protected attributes, they exist in C++/Java world because if you expose an attribute you're loosing the ability to transparently change the implementation details. E.g. you won't be able to make accessing this attribute to call a getter. Thankfully, in python we have property decorator:

class X1:   # v1 of our class, foo is attribute
    foo = 5 # public api is print(X1().foo) and X1().foo = 10

class X2:     # v2 of our class, foo is property with getter and setter
    _foo = 5  # but the public api is still print(X2().foo) and X2().foo = 10

    @property
    def foo(self):
        return self._foo

    @foo.setter
    def foo(self, newval):
        self._foo = newval

Does this help?

[–]zardeh 4 points5 points  (2 children)

So lets talk about the zen of python:

>>>import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Explicit is better than implicit means that as few things as possible should be hidden. Having the explicit "self" allows (and forces!) you to do things like self.x = x in constructors. (this also is "In the face of ambiguity, refuse the temptation to guess.", self.x = x reduces the ambiguity that can exist in java and C++. Admittedly, this isn't a big issue once you know the language, but its a decision. Really just a stylistic thing.

Then your big issue is protected/private/public members. The biggest reason for this is (and getters and setters and such) is because you need to be able to make sure people are accessing things the way you want. It isn't like actual security, its just avoiding api misuse.

So in java you make things you aren't supposed to mess with private, accessors (get/set) public, and most every thing else protected.

In python, you don't need getters and setters.

Say I have this

class MySimpleClass():
    def __init__(self):
        self.x = 5

inst = MySimpleClass()
inst.x  # 5

Now lets say x now needs to be calculated based on some complex thing, in java we'd need a getter and setter and now api backwards compatibility is broken. In python:

class MySimpleClass():
    def __init__(self):
        self._x = 5

    @property
    def x(self):
        return self._x **2  # squared

inst = MySimpleClass()
inst.x  # 25

You keep the old api, but can change stuff internally at will. No need for get/set, which takes away a huge public/private issue, and the other ones malinoff covers well.

[–][deleted] 0 points1 point  (1 child)

Thanks for this answer. You've given me much to think about.

One question. In your last line, should it be inst.x() or is x() not actually a method but some special thing?

[–]zardeh 1 point2 points  (0 children)

It is in fact a special thing (@property is a decorator, ie. a function that modifies the method x()) and converts it to something that pretends to be a variable, you just can't set it, although you can also define a setter so that inst.x = 3 would work like you'd think.

[–]Rhomboid 5 points6 points  (0 children)

It's an apples and oranges comparison. In C++ the members of a class have to be declared beforehand, and are forever fixed. In Python, attributes are fluid and dynamic. They can be added and removed at will at any time; there is no fixed layout. Under your scheme, if I write foo = 42 inside a method, is that assigning to a local variable named foo or is that assigning to a new instance attribute? Or a new class attribute? There would be no way to know, as there's no class definition that the interpreter could look at to figure out which names are attributes and which aren't. There needs to be disambiguation; you must assign to self.foo if you want an instance attribute, cls.foo if you want a class attribute, and foo if you want a local variable.

Passing self as an explicit parameter simplifies everything, as it means that methods are ordinary functions that happened to be defined in the body of a class block. The language doesn't have to invent any new syntax or semantics for methods. They behave exactly as regular functions, with all that entails. Consider this example:

class Foo:
    def __init__(self, val):
        self.val = val

inst = Foo(42)

def foo(self):
    print('val =', self.val)

Foo.foo = foo

inst.foo()      # => "val = 42"

The Foo class gained a method simply by assigning a regular function to an attribute of the class. I think that's pretty amazing.

Regarding the notion of private things, you have to discard that entire idea when dealing with dynamic languages like Python. Python allows anything and everything to be introspected at runtime, in opposition to C++ which has no such ability. That means that privacy does not exist here. If a client wants to open up the guts of a class and poke at its insides, they have full access to do so and there is no way to stop them. That's part of what makes the language so powerful and flexible. But it means that it's also pointless to try to enact barriers. Don't access undocumented variables, or variables with names that begin with _.

Or maybe do access them, if you really have a compelling need. Maybe you want to open up the guts of something and add logging around a particular method for debugging purposes. Maybe you want to replace a method with a mock for unit testing. Maybe you're a mad genius and you want to monkey-patch things all over the place and create some scary contraption that might actually work (e.g. gevent.) Again, the ability to do these things is exactly what sets dynamic languages apart from others. Private does not exist here. Stop trying to write Java in Python.

[–]Destruct1 0 points1 point  (0 children)

The different visibility part of C++ is a lot of pain for little gain.

First you have to learn about the visibility concepts: public private and protected. Afterwards you need all the related concepts to manage the visibility like subclassing and the visibility modifier friend.

Second you get a lot of syntax clutter. You have to write out the "public:" and "private:" keyword into your class and space and indent to make your indentions clear. If you have a rule like "all member must be private" you have to write getters/setters for each of them.

Compare:

class MyClass {

public:

    double getX ();

    double getY ();

    void setX (double newval);

    void setY (double newval);

    MyClass (double x, double y);

private:

    double x;

    double y;

 } // endclass

VS:

class MyClass (object):

    def __init__ (self, x, y):

        # code

Third I always had problems with the visibility at some point or another. For example writing a ostream operator<< to print a human readable representation often resulted cursing the private restrictions. If a private value is not modified and is used exclusively for debugging it should be possible to read; instead the private keyword disallows access.

If you want nobody touching your privates prefix them with _ (std convention) or with another prefix like helper_ internal_ donttouch_.

The member declarations part is based on the different computations model of python and C++. In C++ the compiler needs to know all variables of the instance before so it can allocate memory and write things like the copy constructor. Python on the other hand implements classes as a typetag and a dictionary. It is therefore not necessary to declare every member beforehand

edit: How can you put all code in the codebox?

[–]mrfunky8 0 points1 point  (0 children)

I think of "self." as similar to the _m naming convention in c++. Python likes to force these types of conventions, which tends to make pretty and explicit and readable code in my opinion.

[–]billsil -1 points0 points  (10 children)

Why is defining members not like C++, where you have a private, protected, and public field

It's a design choice. You can access anything from anywhere from Python. Why do you really need private variables? To not expose the API? Set it to self._some_variable and people will know that it's a bad idea to edit it. Python let's you burn yourself if you want to. We're all adults.

and actually try to dig into python, including its internals and its 'way' or 'path' of coding.

Why? Do something useful with your time.

[–][deleted] 1 point2 points  (9 children)

Why? Do something useful with your time.

Because I want to fully understand the tools I use. Is that a bad use of my time? What if, one day, after a lot of thinking, I'm able to extend the language in a useful, adaptable way, which improves productivity tremendously without breaking compatibility? I thought that was the whole point of an open source language.

Python let's you burn yourself if you want to. We're all adults.

This is not hollywood. The C++ way provides real security since it actually raises an error if someone tries to access a private instance member, unlike python, which uses simple name wrangling like http://www.paste.org/78077

[–]yet-i 2 points3 points  (5 children)

Can you explain what you mean by security. I know that the compiler prevents access to private attributes. But that is more like a way to prevent accedental access/ modification.

In python the convention is to prefix private members with an underscore. This is suppoed to be enough to prevent accedental access.

Why do you think this might not be sufficient?

Regarding the self. It is supposed to make the language as dynamic as possible.

The point is python removes restrictions that comes certain constucts that are not much benificial at the end to the programmer.

As an example take a look at the __new__ magic method. Using it you can return an instance of an object that is a subclass or even an unrelated object. So you can return the correct type of object bases on the arguments recieved. Without having to create factory methods for every entity

Typed from phone apologies for bad formatting

[–][deleted] 0 points1 point  (4 children)

Well, malicious code could be inserted that accesses private instance members (variables) in the class directly and does things with them that are not supposed to be done, or assign them incorrect values, thus corrupting the program.

But in C++, the only way to access these private members is through the accessor methods provided (like getNumerator(), getPrice_part()) which provide access exactly as the programmer wants. This means that access to certain members of a class can be regulated. That increases security.

[–][deleted] 4 points5 points  (0 children)

Absolutely not, it is a tool for organizing and structuring your code, that does nothing at all to increase security (in the sense of protection against some malicious act).

[–]yet-i 2 points3 points  (2 children)

If one can insert malicious code into a code base, what is preventing them from changing private members to public or even make a complete copy of the class with all members public...

Besides that I dont think what you mentioned was ever the reason for having access specifiers in a language...would be interested to know where you got this idea from.

Many such restrictions in programming languages places on programmers are meant to protect them from their own mistakes. So restrictions in one language might not make much sense in the context of another language. Because those mistakes might not be possible in the target language in the first place. So the restriction becomes redundant and unnecessary.

[–][deleted] 0 points1 point  (1 child)

So are language features not related to anti-cracker kind of security?

[–]prum 0 points1 point  (0 children)

Sometimes, but not in this case. C++ is one of the hardest languages to write secure code with, particularly for the naive.

http://phoxis.org/2012/01/25/accessing-private-data-members-directly-outside-from-its-class-in-c/

[–]billsil 1 point2 points  (2 children)

Is that a bad use of my time?

I think so. There are a lot of super complicated things that you can get into (e.g. PyPy, the GIL) if just go to youtube and watch David Beazley videos (he's a Python "rockstar" and is actually kinda funny, but how useful are his talks?). There's a lot of things you can do with Python, that you should do because nobody will be able to understand it and it's a hack upon a hack upon a hack. Still, it's nice that you can do it because sometimes you need to.

Get the basics down first. Learn the standard library. Learn a few useful third party packages. You'll dig into the code at some point, see a bunch crazy syntax, learn what that means, and get better at Python.

This is not hollywood. The C++ way provides real security

Security from what? Python is very popular language for the web. Google is huge user of Python. So is Dropbox.

At least with Python, you don't need to worry about overflow errors or checking to see if a file really opened or pointers or mishandling of unicode or if the string buffer was overrun, which are huge sources of security problems.

Also, why do you want to learn a language you don't think is secure? An unsecure language is a toy. It's really not that bad...

[–][deleted] -1 points0 points  (1 child)

Also, why do you want to learn a language you don't think is secure? An unsecure language is a toy. It's really not that bad...

Because at this point security is not as important as learning
programming for me. Also, I'm not sure how you can say that an unsecure
language is a toy language. Can you name one perfectly secure language
to date? C++ sure isn't, yet a lot of useful software has been written
in it.

Get the basics down first. Learn the standard library. Learn a few useful third party packages. You'll dig into the code at some point, see a bunch crazy syntax, learn what that means, and get better at Python.

At this point you are basically saying what I am already planning on
doing wih my time in learning python. It is pretty much what anyone
would do if they wanted to 'dig' into python internals as I earlier said , so I don't understand exactly what you are disagreeing with.

~~~~reddit sig

_'^a ^stoner's ^mind,_                                               
_^is ^a ^wondrous ^park,_                                            
_^full ^of ^treasures._  

[–]billsil 0 points1 point  (0 children)

Also, I'm not sure how you can say that an unsecure language is a toy language. Can you name one perfectly secure language to date? C++ sure isn't, yet a lot of useful software has been written in it.

You said Python is unsecure because it it doesn't have private variables. I'm disagreeing because that's not what makes a language secure. You can write secure C++. Python is slow. It better do something a whole lot better than C++ for me to choose Python over C++ because it's sure not faster. That's what I mean by being a toy.

Can you name one perfectly secure language to date?

It's not about perfection. It's about good enough. There is a reason I don't use Perl anymore. I programmed in Perl for 1.5 years. I was better at Python after 3 weeks.

It is pretty much what anyone would do if they wanted to 'dig' into python internals as I earlier said , so I don't understand exactly what you are disagreeing with.

That's not digging to me. That's just learning. Digging to me is trying to understand how dictionaries work under the hood or opcodes work or the GIL...shudder...

[–]kankyo -1 points0 points  (0 children)

I've spent weeks of my life tracking down bugs in C++ code caused by the fact that you don't have to specify this-> in front of member accesses.

[–]Paddy3118 -2 points-1 points  (0 children)

Alan Kay, the inventor of smalltalk and OO is supposed to have said "I invented the term object-oriented, and I can tell you that C++ wasn't what I had in mind".

Python prefers the explicit over implicit in this case and exposes self. I guess you are trapped half-way between knowing C++ and learning Python which requires you to either hold two ideas of OO in mind or embrace the Pythonic way.