Wednesday, April 27, 2011

Public and Private in Python?

I've just finished refactoring an awful C# class. I had been delaying the job for a while because I didn't want to do it.

Then, while staring at the code, I realised I could simply delete all the private methods and fields, leaving the public interface intact, and then re-implement the class in a much cleaner way. Great idea! I finished the job in a few hours, with a brand new class that doesn't give me a headache.

This is the first time I've actually seen a real value in having private and public scope for methods and variables. It makes refactoring much safer and easier! So... why don't we have them in Python?

17 comments:

Lennart Regebro said...

We do.

It's just that if you *need* to, you can access the private classes too. If you do that with your own library, then you probably need to refactor it. If you do it with somebody elses, you have to count on it breaking when he refactors the code.

The lack of an actual "private" keyword doesn't stop you from separating your code into a public API and internal implementation.

Michael Foord said...

Just use the standard Python convention that attributes / methods starting with an underscore are private.

elarson said...

In addition to the under and dunder, you can use things like properties to refactor a seemingly public variable to act like a method.

I agree that the model is helpful.

duraid said...

I know it's helpful. So is static typing, it's extremely helpful when refactoring legacy code. But that's not what python is about which simplicity and minimalism.

If you want to be able to refactor python code easily you need to make sure you have good unit tests.

Anonymous said...

Please see the tutorial at http://docs.python.org/tutorial/classes.html#tut-private for more information about this.

Adam said...

>>> class A:
... def __private(self):
... return 2
... def public(self):
... return self.__private()
...
>>> a = A()
>>> a.__private()
Traceback (most recent call last):
File "", line 1, in
AttributeError: A instance has no attribute '__private'
>>> a.public()
2

Simon Wittber said...

Right, I had forgotten about the underscore prefix system. I guess it fell from memory due to lack of use, because it is so ugly!

Anonymous said...

Then you should have forgotten all of your C# because it's so ugly.

Actually, it's so much more readable and explicite than a keyword in the declaration.

Arttu said...

I must agree with Simon, underscore prefix is ugly. I can't understand why there isn't "real" private scope, it feels so fundamental when thinking about encapsulation.

Though I don't have much experience with procedural languages.

duraid said...

if you have private and public then you should add protected and internal and there are still situations when all the 4 options are not good enough. It just adds a lot of complexity in order to get more control. Learn give up control you control freaks!

Anonymous said...

First: Python is not only procedural...
Second: Python has a philosophie, and it defined the language. Thats the main reason to avoid the use of keywords like private, static, etc.

Arttu said...

Good points. I'm thinking this completely from the Java point of view so I missed this Python philosophy.

Anonymous said...

__slots__ ?

But until today, nobody convinced me why make attributes and methods really private

eryksun said...
This comment has been removed by the author.
Sean said...

This isn't about keywords on implementations, this is about interfaces, right? Most Python software doesn't need explicit public interfaces. And those that do use zope.interface. I don't mean to be so blunt, but after years of using one of the following two strategies, it seems a non-problem; either: (1) duck-type and use data-normalization decorators around your public methods (e.g. guarantee your REST API can give your method that needs strings a unicode value without issue; move the EAFB and normalization into a decorator for more elegant, readable methods); (2) use zope.interface and zope.component. You can use both.

Sean said...

s/EAFB/EAFP

Daniel said...

You can separate interface and implementation using closures. To me this seems much less natural in Python compared to JavaScript where it's the norm. I would like a better syntax for this.

def make_class():
global X

def private_method(self): pass

class X(object):
def public_method(self):
private_method(self)

Popular Posts