Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Nice solution wanted: Hide internal interfaces

37 views
Skip to first unread message

Johannes Bauer

unread,
Oct 29, 2012, 12:33:24 PM10/29/12
to
Hi there,

I'm currently looking for a good solution to the following problem: I
have two classes A and B, which interact with each other and which
interact with the user. Instances of B are always created by A.

Now I want A to call some private methods of B and vice versa (i.e. what
C++ "friends" are), but I want to make it hard for the user to call
these private methods.

Currently my ugly approach is this: I delare the internal methods
private (hide from user). Then I have a function which gives me a
dictionary of callbacks to the private functions of the other objects.
This is in my opinion pretty ugly (but it works and does what I want).

I'm pretty damn sure there's a nicer (prettier) solution out there, but
I can't currently think of it. Do you have any hints?

Best regards,
Joe


--
>> Wo hattest Du das Beben nochmal GENAU vorhergesagt?
> Zumindest nicht �ffentlich!
Ah, der neueste und bis heute genialste Streich unsere gro�en
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos �ber R�diger Thomas in dsa <hidbv3$om2$1...@speranza.aioe.org>

andrea crotti

unread,
Oct 29, 2012, 12:41:57 PM10/29/12
to Johannes Bauer, pytho...@python.org
2012/10/29 Johannes Bauer <dfnson...@gmx.de>:
> Hi there,
>
> I'm currently looking for a good solution to the following problem: I
> have two classes A and B, which interact with each other and which
> interact with the user. Instances of B are always created by A.
>
> Now I want A to call some private methods of B and vice versa (i.e. what
> C++ "friends" are), but I want to make it hard for the user to call
> these private methods.
>
> Currently my ugly approach is this: I delare the internal methods
> private (hide from user). Then I have a function which gives me a
> dictionary of callbacks to the private functions of the other objects.
> This is in my opinion pretty ugly (but it works and does what I want).
>
> I'm pretty damn sure there's a nicer (prettier) solution out there, but
> I can't currently think of it. Do you have any hints?
>
> Best regards,
> Joe
>

And how are you declaring methods private? Because there is no real
private attribute in Python, if you declare them with a starting "_"
they are still perfectly accessible..

Benjamin Kaplan

unread,
Oct 29, 2012, 12:41:56 PM10/29/12
to pytho...@python.org
On Mon, Oct 29, 2012 at 9:33 AM, Johannes Bauer <dfnson...@gmx.de> wrote:
> Hi there,
>
> I'm currently looking for a good solution to the following problem: I
> have two classes A and B, which interact with each other and which
> interact with the user. Instances of B are always created by A.
>
> Now I want A to call some private methods of B and vice versa (i.e. what
> C++ "friends" are), but I want to make it hard for the user to call
> these private methods.
>
> Currently my ugly approach is this: I delare the internal methods
> private (hide from user). Then I have a function which gives me a
> dictionary of callbacks to the private functions of the other objects.
> This is in my opinion pretty ugly (but it works and does what I want).
>
> I'm pretty damn sure there's a nicer (prettier) solution out there, but
> I can't currently think of it. Do you have any hints?
>
> Best regards,
> Joe
>

What do you mean "declare the internal methods private"? Python
doesn't have this notion of restricted access. By convention, names
starting with a leading underscore are private, but it's not enforced
by the language.

Chris Angelico

unread,
Oct 29, 2012, 12:47:21 PM10/29/12
to pytho...@python.org
On Tue, Oct 30, 2012 at 3:33 AM, Johannes Bauer <dfnson...@gmx.de> wrote:
> Hi there,
>
> I'm currently looking for a good solution to the following problem: I
> have two classes A and B, which interact with each other and which
> interact with the user. Instances of B are always created by A.
>
> Now I want A to call some private methods of B and vice versa (i.e. what
> C++ "friends" are), but I want to make it hard for the user to call
> these private methods.

The usual convention for private methods is a leading underscore on the name:

class A:
def foo(self):
print("Fooing!")
def _bar(self):
print("Only my friends may bar me.")

It's only a convention, though; it doesn't make it "hard" to call
them, it just sends the message "this is private, I don't promise that
it'll be stable across versions".

Incidentally, you may want to use a nested class, if the definition of
B is entirely dependent on A. Something like this:

class A:
class B:
def _asdf(self,newval=None):
if newval is not None: self._val=newval
return self._val
def _qwer(self,parent):
parent._bar("My value is: "+self._val)
def foo(self):
self.b=self.B()
self.b._asdf("Hello, world!")
self.b._qwer(self)
def _bar(self,msg):
print("Message from internal: "+msg)

ChrisA

Grant Edwards

unread,
Oct 29, 2012, 12:52:24 PM10/29/12
to
On 2012-10-29, Johannes Bauer <dfnson...@gmx.de> wrote:

> I'm currently looking for a good solution to the following problem: I
> have two classes A and B, which interact with each other and which
> interact with the user. Instances of B are always created by A.
>
> Now I want A to call some private methods of B and vice versa (i.e.
> what C++ "friends" are), but I want to make it hard for the user to
> call these private methods.

The Python way of telling a user not to call certain methods is to
prefix their names with an underscore. The double-underscore thing
that munges the names is just telling that a bit louder -- but they're
still free to ignore that advice.

> Currently my ugly approach is this: I delare the internal methods
> private (hide from user). Then I have a function which gives me a
> dictionary of callbacks to the private functions of the other
> objects. This is in my opinion pretty ugly (but it works and does
> what I want).

By "decleare them privide" do you mean using __ASDF__ name-munging?

It sounds to me like you're just making life hard on yourself.

> I'm pretty damn sure there's a nicer (prettier) solution out there,
> but I can't currently think of it. Do you have any hints?

IMO, the "right" thing to do in Python is to use single underscore
names for methods that you intend to be called by "friend" modules (is
that correct C++ lingo?) but don't intend to be called by the
end-user.

--
Grant Edwards grant.b.edwards Yow! I just had a NOSE
at JOB!!
gmail.com

Johannes Bauer

unread,
Oct 29, 2012, 12:58:30 PM10/29/12
to
On 29.10.2012 17:47, Chris Angelico wrote:

> The usual convention for private methods is a leading underscore on the name:

Yup, that's what I'm using.

> It's only a convention, though; it doesn't make it "hard" to call
> them, it just sends the message "this is private, I don't promise that
> it'll be stable across versions".

Yes, I know. But it's good enough. I don't want to restrict the use
under all circumstances, just make it clear to the user what she is
supposed to use and what not.

> Incidentally, you may want to use a nested class, if the definition of
> B is entirely dependent on A. Something like this:

Ah, that's nice. I didn't know that nested classes could access their
private members naturally (i.e. without using any magic, just with plain
old attribute access).

This makes the source files largish however (they're currently split up
in different files). Can I use the nested class advantage and somehow
include the inner class from another file?

Johannes Bauer

unread,
Oct 29, 2012, 1:01:27 PM10/29/12
to
On 29.10.2012 17:52, Grant Edwards wrote:

> By "decleare them privide" do you mean using __ASDF__ name-munging?
>
> It sounds to me like you're just making life hard on yourself.

Gaaaaaah, you are right. I just noticed that using the single underscore
(as I do) does not restrict usage in any "non-natural" way. I was
actually mixing this up in my head with the __xyz__ name-munging.

Thank you very much for hitting my head with a brick. Much clearer now :-)

Best regards,
Johannes

--
>> Wo hattest Du das Beben nochmal GENAU vorhergesagt?
> Zumindest nicht ᅵffentlich!
Ah, der neueste und bis heute genialste Streich unsere groᅵen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos ᅵber Rᅵdiger Thomas in dsa <hidbv3$om2$1...@speranza.aioe.org>

Paul Rubin

unread,
Oct 29, 2012, 1:03:49 PM10/29/12
to
Johannes Bauer <dfnson...@gmx.de> writes:
> This makes the source files largish however (they're currently split up
> in different files). Can I use the nested class advantage and somehow
> include the inner class from another file?

You could possibly duck-punch class A:

import B

class A:
...

A.B = B.B

Disclaimer: I haven't tested the above and I'd consider it pretty ugly.

Peter Otten

unread,
Oct 29, 2012, 1:06:30 PM10/29/12
to pytho...@python.org
Johannes Bauer wrote:

> Now I want A to call some private methods of B and vice versa (i.e. what
> C++ "friends" are), but I want to make it hard for the user to call
> these private methods.
>
> Currently my ugly approach is this: I delare the internal methods
> private (hide from user). Then I have a function which gives me a
> dictionary of callbacks to the private functions of the other objects.
> This is in my opinion pretty ugly (but it works and does what I want).
>
> I'm pretty damn sure there's a nicer (prettier) solution out there, but
> I can't currently think of it. Do you have any hints?

Maybe you can wrap A into a class that delegates to A:

>>> class A(object):
... def __private(self): print "private A"
...
>>> class Friend(object):
... def __init__(self, obj):
... self.__obj = obj
... self.__prefix = "_%s_" % obj.__class__.__name__
... def __getattr__(self, name):
... return getattr(self.__obj, self.__prefix + name)
...
>>> a = A()
>>> a._A__private() # hard
private A
>>> f = Friend(a)
>>> f._private() # easy
private A

The B instance would refer to A via the Friend instance.

Peter Otten

unread,
Oct 29, 2012, 1:17:56 PM10/29/12
to pytho...@python.org
Johannes Bauer wrote:

> On 29.10.2012 17:52, Grant Edwards wrote:
>
>> By "decleare them privide" do you mean using __ASDF__ name-munging?
>>
>> It sounds to me like you're just making life hard on yourself.
>
> Gaaaaaah, you are right. I just noticed that using the single underscore
> (as I do) does not restrict usage in any "non-natural" way. I was
> actually mixing this up in my head with the __xyz__ name-munging.

Name-munging occurs only if the method name starts but doesn't end with
"__":

>>> class A(object): pass
...
>>> class B(A):
... __before = __between__ = __ = 42
...
>>> set(dir(B)) - set(dir(A))
set(['__', '_B__before', '__between__'])


Grant Edwards

unread,
Oct 29, 2012, 2:00:58 PM10/29/12
to
On 2012-10-29, Johannes Bauer <dfnson...@gmx.de> wrote:
> On 29.10.2012 17:47, Chris Angelico wrote:
>
>> The usual convention for private methods is a leading underscore on the name:
>
> Yup, that's what I'm using.
>
>> It's only a convention, though; it doesn't make it "hard" to call
>> them, it just sends the message "this is private, I don't promise that
>> it'll be stable across versions".
>
> Yes, I know. But it's good enough. I don't want to restrict the use
> under all circumstances, just make it clear to the user what she is
> supposed to use and what not.

The single underscore indicates that the user is not to use the
method.

--
Grant Edwards grant.b.edwards Yow! I am covered with
at pure vegetable oil and I am
gmail.com writing a best seller!

Ian Kelly

unread,
Oct 29, 2012, 3:09:57 PM10/29/12
to Python
On Mon, Oct 29, 2012 at 10:58 AM, Johannes Bauer <dfnson...@gmx.de> wrote:
> Ah, that's nice. I didn't know that nested classes could access their
> private members naturally (i.e. without using any magic, just with plain
> old attribute access).

There is nothing at all special about nested classes that is different
from non-nested classes. All it affects is organization; instead of
classes A and B, you have classes A and A.B.

Steven D'Aprano

unread,
Oct 29, 2012, 6:37:01 PM10/29/12
to
On Mon, 29 Oct 2012 17:33:24 +0100, Johannes Bauer wrote:

> Hi there,
>
> I'm currently looking for a good solution to the following problem: I
> have two classes A and B, which interact with each other and which
> interact with the user. Instances of B are always created by A.
>
> Now I want A to call some private methods of B and vice versa (i.e. what
> C++ "friends" are), but I want to make it hard for the user to call
> these private methods.

In B, name these private methods with a leading underscore, exactly as
you would for any other private name, e.g. B._method.

Do not document the existence of B._method in external documentation
aimed at the user, except to note that all methods with leading
underscores are private, and the use of them is unsupported and subject
to change without notice.

In A, use B._method normally. After all, it's *your* code, you can do
whatever you see fit.


> Currently my ugly approach is this: I delare the internal methods
> private (hide from user). Then I have a function which gives me a
> dictionary of callbacks to the private functions of the other objects.
> This is in my opinion pretty ugly (but it works and does what I want).

Seems to me that this dictionary of callbacks does nothing but add
unnecessary complexity to your code. What's the point of it?

Besides, if your users are foolish enough to use flagged private
_methods, they're foolish enough to access the functions in the callback
dictionary. So you gain nothing but extra work.



--
Steven

alex23

unread,
Oct 29, 2012, 9:37:16 PM10/29/12
to
On Oct 30, 2:33 am, Johannes Bauer <dfnsonfsdu...@gmx.de> wrote:
> I'm currently looking for a good solution to the following problem: I
> have two classes A and B, which interact with each other and which
> interact with the user. Instances of B are always created by A.
>
> Now I want A to call some private methods of B and vice versa (i.e. what
> C++ "friends" are), but I want to make it hard for the user to call
> these private methods.

One approach could be to only have the public interface on B, and then
create a wrapper for B that provides the private interface:

class B:
def public_method(self):
pass

class B_Private:
def __init__(self, context):
self.context = context

def private_method(self):
# manipulate self.context

class A:
def __init__(self):
self.b = B()
self.b_private = B_Private(self.b)

def foo(self):
# call public method
self.b.public_method()

# call private method
self.b_private.private_method()

It doesn't stop a user from accessing the private methods, but it does
separate them so they have to *intentionally* choose to use them.

andrea crotti

unread,
Oct 30, 2012, 10:15:09 AM10/30/12
to alex23, pytho...@python.org
2012/10/30 alex23 <wuw...@gmail.com>:
> --
> http://mail.python.org/mailman/listinfo/python-list



Partly unrelated, but you could also define a clear API and expose it
through your __init__.py.

For example:
package/a.py:
class A: pass

package/b.py:
class B:pass

package/__init__.py
from a import A

so now doing "from package import" will only show A.

This doesn't work on the method-level, but it's useful to know and
commonly done in many projects..


In some projects they even use a file "api.py" to you have to
explicitly import

from package.api import ..
(which I think is overkill since __init__.py does the same)
0 new messages