Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #104518 > unrolled thread

Encapsulation in Python

Started byBen Mezger <me@benmezger.nl>
First post2016-03-10 10:41 -0300
Last post2016-03-13 00:42 +1100
Articles 6 — 5 participants

Back to article view | Back to comp.lang.python


Contents

  Encapsulation in Python Ben Mezger <me@benmezger.nl> - 2016-03-10 10:41 -0300
    Re: Encapsulation in Python Steven D'Aprano <steve@pearwood.info> - 2016-03-11 20:28 +1100
      Re: Encapsulation in Python Rick Johnson <rantingrickjohnson@gmail.com> - 2016-03-11 16:45 -0800
        Re: Encapsulation in Python dieter <dieter@handshake.de> - 2016-03-12 10:42 +0100
          Re: Encapsulation in Python Rick Johnson <rantingrickjohnson@gmail.com> - 2016-03-12 07:03 -0800
        Re: Encapsulation in Python Chris Angelico <rosuav@gmail.com> - 2016-03-13 00:42 +1100

#104518 — Encapsulation in Python

FromBen Mezger <me@benmezger.nl>
Date2016-03-10 10:41 -0300
SubjectEncapsulation in Python
Message-ID<mailman.132.1457617425.15725.python-list@python.org>

[Multipart message — attachments visible in raw view] — view raw

Hi all,

I've been studying Object Oriented Theory using Java. Theoretically, all
attributes should be private, meaning no one except the methods itself
can access the attribute;

public class Foo {
    private int bar;
    ...

Normally in Java, we would write getters and setters to set/get the
attribute bar. However, in Python, we normally create a class like so;

class Foo(object):
    bar = 0
    ...

And we usually don't write any getters/setters (though they exist in
Python, I have not seen much projects making use of it).

We can easily encapsulate (data hiding) Foo's class using the '_'
(underscore) when creating a new attribute, however, this would require
all attributes to have a underscore.
According to this answer [1], it's acceptable to to expose your
attribute directly (Foo.bar = 0), so I wonder where the encapsulation
happens in Python? If I can access the attribute whenever I want (with
the except of using a underscore), what's the best way to encapsulate a
class in Python? Why aren't most of the projects not using
getters/setters and instead they access the variable directly?

Regards,

Ben Mezger

[1] - http://stackoverflow.com/q/4555932

[toc] | [next] | [standalone]


#104601

FromSteven D'Aprano <steve@pearwood.info>
Date2016-03-11 20:28 +1100
Message-ID<56e28fbe$0$1584$c3e8da3$5496439d@news.astraweb.com>
In reply to#104518
On Fri, 11 Mar 2016 12:41 am, Ben Mezger wrote:

> Hi all,
> 
> I've been studying Object Oriented Theory using Java. Theoretically, all
> attributes should be private, meaning no one except the methods itself
> can access the attribute;

(Note: in the following, when I say "encapsulation", I am actually referring
to *data hiding*.)

That's one theory. Another theory is: no they shouldn't, all attributes
should be public. That most accurately models actual physical objects and
maximises the usefulness of the attribute.

People over-use private, and if you google, you will find many people
asking "how can I access private variables and methods?". You will also
learn that encapsulation is the enemy of test-drive development:

https://jasonmbaker.wordpress.com/2009/01/08/enemies-of-test-driven-development-part-i-encapsulation/

and also of good user-interfaces:

https://ayende.com/blog/4375/encapsulation-is-the-enemy-of-the-user-interface

Some might say that encapsulation is a waste of time:

http://c2.com/cgi/wiki?EncapsulationIsaWasteOfTime

See also:

http://c2.com/cgi/wiki?MethodsShouldBePublic
http://c2.com/cgi/wiki?ForgetAboutWritingAccessors


Python offers a middle ground: where encapsulation is important for safety,
use it, otherwise rely on trust and a gentleman's agreement. We're all
adults here: if you use my internals, that's your choice, and you can live
with the consequences.

In practice this means that internal details of classes written in C are
completely hidden from Python code unless explicitly made public. Why?
Because if the caller messes with the internal data of a C class, they can
cause a segmentation fault, which can execute arbitrary code. This is a
serious problem, and Python has a philosophy of Absolutely No Seg Faults.
It should be impossible to cause the Python interpreter to seg fault or
dump core (except via ctypes, which is special). That means that classes
written in C are hide their internals.

But what about Python classes? You can't cause a seg fault in Python code.
So Python's philosophy is:

- trying to *enforce* private data is a waste of time, people will find a
way around it, even if it is a horrible nasty hack;

- so instead, rely on trust: we mark "private" attributes with a leading
underscore, and trust that users won't abuse them;

- if they do, the consequences are on their head, not ours: you have no
responsibility to users who misuse your private attributes.

Furthermore, are you *sure* that you need private attributes? That will, of
course, depend on the size of the project you are working on. If it is a
small class in a small program, then it is probably a waste of time and
effort: You Ain't Going To Need It.

Python gives you five levels of enforcement of encapsulation:

1. None what so ever. YAGNI, so just use a regular attribute and 
   don't over-engineer your simple class.

2. Trust the user to obey the naming convention: name the 
   attribute with a leading underscore to make it private by
   convention.

3. If you need to offer a public interface which differs from 
   your internal implementation, you can use properties or 
   custom-made descriptors to implement getters and setters 
   which look like ordinary attribute access. (This often 
   relies on #2 as well.)

4. The encapsulation offered by closures is even harder to 
   break, but it applies to functions, not classes.

5. For the strongest level of encapsulation, move your code
   into a C extension class.



For most users, 1 through 3 is more than enough.



> public class Foo {
>     private int bar;
>     ...
> 
> Normally in Java, we would write getters and setters to set/get the
> attribute bar. However, in Python, we normally create a class like so;
> 
> class Foo(object):
>     bar = 0
>     ...

No, normally we wouldn't. The above makes bar shared by all instances.
Normally, if you want each instance to get their own value of bar, you
would assign it in the constructor/initialiser:

class Foo(object):
    def __init__(self):
        self.bar = 0


For ints, this isn't much of a practical difference, but it makes a very big
difference for mutable classes like lists.


> And we usually don't write any getters/setters (though they exist in
> Python, I have not seen much projects making use of it).

Correct. YAGNI: don't use getters/setters until you have proof that you need
it, not just "well my professor tells me I should do this".

As a Java developer, you might sometimes feel that (by Java standards)
Python code is awfully slap-dash and sloppy. That's okay -- by Python
standards, Java code is awfully "bondage and discipline", strict and
pedantic.

See here:

http://dirtsimple.org/2004/12/python-is-not-java.html
http://dirtsimple.org/2004/12/java-is-not-python-either.html



> We can easily encapsulate (data hiding) Foo's class using the '_'
> (underscore) when creating a new attribute, however, this would require
> all attributes to have a underscore.

Well, if you really want them to be private, that's the way to do it. But
why are they all private? Private attributes have both a benefit and a
cost. Are you sure the benefit is worth it?

Sometimes, rather than make each attribute private, it is easier to just
make the whole class private.


> According to this answer [1], it's acceptable to to expose your
> attribute directly (Foo.bar = 0), so I wonder where the encapsulation
> happens in Python? If I can access the attribute whenever I want (with
> the except of using a underscore), what's the best way to encapsulate a
> class in Python? Why aren't most of the projects not using
> getters/setters and instead they access the variable directly?

Despite what your Java teacher may have said, encapsulation is not the most
important thing about classes. A lot will depend on the size of your
project, of course: in an extremely large project, you will see Python code
written a lot more like Java code. But for small projects, not so much.

In fact, a lot of Python code doesn't even use classes.

Stop Writing Classes: http://www.youtube.com/watch?v=o9pEzgHorH0

http://steve-yegge.blogspot.com.au/2006/03/execution-in-kingdom-of-nouns.html


On the other hand, sometimes we should write more classes:

http://lucumr.pocoo.org/2013/2/13/moar-classes/


> 
> Regards,
> 
> Ben Mezger
> 
> [1] - http://stackoverflow.com/q/4555932

-- 
Steven

[toc] | [prev] | [next] | [standalone]


#104663

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2016-03-11 16:45 -0800
Message-ID<5e1d2cff-3e92-4efd-9d48-573e365a8577@googlegroups.com>
In reply to#104601
On Friday, March 11, 2016 at 3:28:40 AM UTC-6, Steven D'Aprano wrote:

> That's one theory. Another theory is: no they shouldn't, all attributes
> should be public. That most accurately models actual physical objects and
> maximizes the usefulness of the attribute.
> 
> People over-use private, and if you google, you will find many people
> asking "how can I access private variables and methods?".

If "people" are trying to access private variables, then one, or both, 
of these  has occurred: (1) The interface was poorly
written, and/or (2) The user of the interface is hell bent
on shooting himself in the foot!

> Python offers a middle ground: where encapsulation is important for safety,
> use it, otherwise rely on trust and a gentleman's agreement. We're all
> adults here: if you use my internals, that's your choice, and you can live
> with the consequences.
> 
> In practice this means that internal details of classes written in C are
> completely hidden from Python code unless explicitly made public. Why?
> Because if the caller messes with the internal data of a C class, they can
> cause a segmentation fault, which can execute arbitrary code. This is a
> serious problem, and Python has a philosophy of Absolutely No Seg Faults.

First you go off blabbing about how all attributes should be
public, then you do an about face, and admit that very bad
things can happen when internals are exposed. Does anyone
else find this argument to be absurd?

> It should be impossible to cause the Python interpreter to seg fault or
> dump core (except via ctypes, which is special). 

SPECIAL CASES ARE *NOT* SPECIAL ENOUGH TO BREAK THE RULES!

> But what about Python classes? You can't cause a seg fault in Python code.

Are you sure about that? Heck, i posted code quite a few
years back that "seg faulted like a mutha". Do you want to
retract your statement, or will i need to search the
archives, and then stuff the link down your big fat mouth?

> So Python's philosophy is:
> 
> - trying to *enforce* private data is a waste of time, people will find a
> way around it, even if it is a horrible nasty hack;
> 
> - so instead, rely on trust: we mark "private" attributes with a leading
> underscore, and trust that users won't abuse them;
> 
> - if they do, the consequences are on their head, not ours: you have no
> responsibility to users who misuse your private attributes.

I theory, that is a great philosophy, but in practice, it
encourages people to be lazy, and they end up writing
horrible interfaces. Why spend the time to write a proper
interface, when, in the back of your mind, you know you can
reach into that public cookie jar *ANYTIME* you want to.
It's like when an overweight person goes on a diet, but still 
has cookies, cakes and ice-cream in the kitchen -- the
temptation to be a slob is just too great!

Imagine if indention were optional in Python, or if Python
allowed braces... Even with all the benefits of indention
over braces, quite a few idiots would still use the damn
braces! Heck, i knew this one Ruby coder, who was a longtime
C coder, and at the end of every line, he religiously placed
a semicolon there. And i told him, "dude, you're *NOT*
writing C code anymore, so stop putting those damn trailing
semicolons in your source!". But the arrogant bassturd
refused to stop. So i thought: "Hmm, maybe it's just a bad
habit", but no, he freely admitted that he conscientiously
placed them in hos source because: "he liked them".

There are two main methods that a language can ruin you as a
programmer. One method is to encourage you to be a "Lazy
Larry", and the other is to mold you into a "habitual
Harry". Python has mostly eradicated the "habitual Harry"
disease, but it still actively promotes the "lazy Larry"
disease. Yes, pure OOP is onerous to the programmer, but it
is onerous for a reason. And that *REASON* is to create
rigid interfaces!

Anytime a standard is handed down, people are going to
whine.

 "WAH, standards are hard!"
 
 "WAH, it takes too long!" 
 
 "WAH, my fingers hurt!"
 
But what these whiners don't realize, is that, either they
put in the effort of writing solid interfaces *NOW*, or they
will be forced to debug, explain, and repair the awful
interfaces *LATER*.  In the end, there is no shortcut to
excellence. Which brings me back to my motto: "Great
interfaces *NEVER* happen by accident --shite happens,
interfaces don't!"

Yes, creating proper interfaces requires a lot of thought, a
lot of testing, and yes, a whoooole lot of typing. But if
thinking, and testing, and typing are not your thing, then
perhaps you'd be happier smoking marijuana and working as
sales associate at your local GAP store.

[toc] | [prev] | [next] | [standalone]


#104680

Fromdieter <dieter@handshake.de>
Date2016-03-12 10:42 +0100
Message-ID<mailman.29.1457775786.12893.python-list@python.org>
In reply to#104663
Rick Johnson <rantingrickjohnson@gmail.com> writes:
> On Friday, March 11, 2016 at 3:28:40 AM UTC-6, Steven D'Aprano wrote:
> ...
> Are you sure about that? Heck, i posted code quite a few
> years back that "seg faulted like a mutha". Do you want to
> retract your statement, or will i need to search the
> archives, and then stuff the link down your big fat mouth?
                                    ^^^^^^^^^^^^^^^^^^^^^^^

What happened that you use language like this?

Obviously, you disagree with Steven - but this should not make you so angry
to use agressive language.

[toc] | [prev] | [next] | [standalone]


#104707

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2016-03-12 07:03 -0800
Message-ID<b559daba-3c05-46dc-96c3-f283ca689f8d@googlegroups.com>
In reply to#104680
On Saturday, March 12, 2016 at 3:43:16 AM UTC-6, dieter wrote:

> > archives, and then stuff the link down your big fat mouth?
>                                     ^^^^^^^^^^^^^^^^^^^^^^^
> 
> What happened that you use language like this? Obviously,
> you disagree with Steven - but this should not make you so
> angry to use aggressive language.

Yes, i did go too far here, and for that, i do humbly
apologize to Steven and all the members of this group. There
is no excuse for aggressive, or fowl language here.

Steven has a bad habit of playing devils advocate, and he
has on many occasions, made contradictory statements. When
he does this, it angers me, because i know he's too
intelligent to do these things by accident. In fact, all the
members of this group are highly intelligent, and that is
why i censor my language when I post here. When i am posting
in other groups, groups which have set the "intelligence
bar" far lower, i don't censor my words at all, because
ignorant people don't deserve any decency from me.

Intelligence is a rarity in this world, and much less so in
many of the Usenet groups out there. Most of which seem to
be nothing more than arenas for personal attacks, fowl
language, and a contest to see who has the *LEAST* amount of
intelligence. Very sad. I come here not only because of
Python, but to engage my equals in civil discourse, and to
soak up the vast amounts of general knowledge that are
shared generously on a daily basis.

Python-list an an oasis of intelligence in a sea of
ignorance. And as such, demands that we maintain a high
level of decency and mutual respect in our posts. I don't
always agree with everyone here, and i may never agree with
some, but I will always carry a deep respect for each and
every member of this fine group.

[toc] | [prev] | [next] | [standalone]


#104705

FromChris Angelico <rosuav@gmail.com>
Date2016-03-13 00:42 +1100
Message-ID<mailman.40.1457790141.12893.python-list@python.org>
In reply to#104663
On Sat, Mar 12, 2016 at 8:42 PM, dieter <dieter@handshake.de> wrote:
> Rick Johnson <rantingrickjohnson@gmail.com> writes:
>> On Friday, March 11, 2016 at 3:28:40 AM UTC-6, Steven D'Aprano wrote:
>> ...
>> Are you sure about that? Heck, i posted code quite a few
>> years back that "seg faulted like a mutha". Do you want to
>> retract your statement, or will i need to search the
>> archives, and then stuff the link down your big fat mouth?
>                                     ^^^^^^^^^^^^^^^^^^^^^^^
>
> What happened that you use language like this?
>
> Obviously, you disagree with Steven - but this should not make you so angry
> to use agressive language.

You're responding to someone who calls himself "Ranting Rick". Don't
bother expecting courtesy or civility. He's a resident troll,
tolerated because he does make good points now and then, but generally
ignored because of his irksome style.

ChrisA

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web