As you mentioned, Python doesn't really enforce data-hiding in the way that you mention. Remember that Python is a dynamic language and that you can add attributes or methods dynamically on an object. class A: pass a = A() a.x = "something new" Python's sense of encapsulation means that you don't have to worry about implementation details, not whether or not an attribute has public or private access. Although python doesn't explicitly support access modifiers, you can "fake" it. A leading double underscore means that an attribute is private in the sense that if you try to access the attribute directly (via it's name), you won't be able to. Python does this by secretly name-mangling the variable with a leading underscore, the name of the class, and then the name of the variable. For example, if you have something like: class Example: def __init__(self): self.__hidden = "Don't access me directly" def get__hidden(self): return self.__hidden e = Example() e.__hidden Traceback (most recent call last): File "<input>", line 1, in <module> AttributeError: Example instance has no attribute '__hidden' e.get__hidden() "Don't access me directly" dir(e) ['_Example__hidden', '__doc__', '__init__', '__module__', 'get__hidden'] A single leading underscore is simply an indicator to other programmers that they really shouldn't be directly accessing a variable (or method). It also means that when you do a 'from mymodule import *', anything with a single leading underscore doesn't get imported. Python has a feature similar to .Net Properties (and in fact, python calls them Properties also). If you are using new-style classes (ie, inheriting directly or indirectly from object, or use __metaclass__ = type somewhere in your module), then you can use the property protocol. Basically what this means is that python will use accessor and mutator methods that you define, but they are called implicitly for you depending on the context. You can sort of implement your own protection scheme by using the magic methods of __getattr__ and __setattr__ respectively. If these magic methods are implemented, whenever someone accesses (any of) a class's attributes, then these magic methods are called. class Example: def __init__(self): self.__hidden = "Don't access me directly" def get__hidden(self): return self.__hidden def __getattr__(self, name): if name == "__hidden": print """You really shouldn't be using me directly""" else: raise AttributeError e.__hidden You really shouldn't be using me directly The larger lesson here is that python does things differently. For example, instead of having interfaces like Java or C# that are bonafide types, python uses what is called "duck-typing". If it walks like a duck and talks like a duck, it is a duck. It took me a little while to get used to dynamic programming, but now I love it. Granted, it does require a little more diligence, but I find that this enforces documentation (and docstrings are cool). And when things are dynamically typed, it actually forces you to think more polymorphically, because you may not exactly know what might get thrown in (or out). There are ways to check this at runtime through introspection, or using functions like callable (which is to be deprecated btw), but this is as ugly as using RTTI in C++.