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


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

Nice solution wanted: Hide internal interfaces

Started byJohannes Bauer <dfnsonfsduifb@gmx.de>
First post2012-10-29 17:33 +0100
Last post2012-10-30 14:15 +0000
Articles 15 — 10 participants

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


Contents

  Nice solution wanted: Hide internal interfaces Johannes Bauer <dfnsonfsduifb@gmx.de> - 2012-10-29 17:33 +0100
    Re: Nice solution wanted: Hide internal interfaces andrea crotti <andrea.crotti.0@gmail.com> - 2012-10-29 16:41 +0000
    Re: Nice solution wanted: Hide internal interfaces Benjamin Kaplan <benjamin.kaplan@case.edu> - 2012-10-29 09:41 -0700
    Re: Nice solution wanted: Hide internal interfaces Chris Angelico <rosuav@gmail.com> - 2012-10-30 03:47 +1100
      Re: Nice solution wanted: Hide internal interfaces Johannes Bauer <dfnsonfsduifb@gmx.de> - 2012-10-29 17:58 +0100
        Re: Nice solution wanted: Hide internal interfaces Paul Rubin <no.email@nospam.invalid> - 2012-10-29 10:03 -0700
        Re: Nice solution wanted: Hide internal interfaces Grant Edwards <invalid@invalid.invalid> - 2012-10-29 18:00 +0000
        Re: Nice solution wanted: Hide internal interfaces Ian Kelly <ian.g.kelly@gmail.com> - 2012-10-29 13:09 -0600
    Re: Nice solution wanted: Hide internal interfaces Grant Edwards <invalid@invalid.invalid> - 2012-10-29 16:52 +0000
      Re: Nice solution wanted: Hide internal interfaces Johannes Bauer <dfnsonfsduifb@gmx.de> - 2012-10-29 18:01 +0100
        Re: Nice solution wanted: Hide internal interfaces Peter Otten <__peter__@web.de> - 2012-10-29 18:17 +0100
    Re: Nice solution wanted: Hide internal interfaces Peter Otten <__peter__@web.de> - 2012-10-29 18:06 +0100
    Re: Nice solution wanted: Hide internal interfaces Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-10-29 22:37 +0000
    Re: Nice solution wanted: Hide internal interfaces alex23 <wuwei23@gmail.com> - 2012-10-29 18:37 -0700
      Re: Nice solution wanted: Hide internal interfaces andrea crotti <andrea.crotti.0@gmail.com> - 2012-10-30 14:15 +0000

#32393 — Nice solution wanted: Hide internal interfaces

FromJohannes Bauer <dfnsonfsduifb@gmx.de>
Date2012-10-29 17:33 +0100
SubjectNice solution wanted: Hide internal interfaces
Message-ID<k6mb4k$5v3$1@news.albasani.net>
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>

[toc] | [next] | [standalone]


#32394

Fromandrea crotti <andrea.crotti.0@gmail.com>
Date2012-10-29 16:41 +0000
Message-ID<mailman.3027.1351528920.27098.python-list@python.org>
In reply to#32393
2012/10/29 Johannes Bauer <dfnsonfsduifb@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..

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


#32395

FromBenjamin Kaplan <benjamin.kaplan@case.edu>
Date2012-10-29 09:41 -0700
Message-ID<mailman.3028.1351529114.27098.python-list@python.org>
In reply to#32393
On Mon, Oct 29, 2012 at 9:33 AM, Johannes Bauer <dfnsonfsduifb@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.

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


#32398

FromChris Angelico <rosuav@gmail.com>
Date2012-10-30 03:47 +1100
Message-ID<mailman.3030.1351529244.27098.python-list@python.org>
In reply to#32393
On Tue, Oct 30, 2012 at 3:33 AM, Johannes Bauer <dfnsonfsduifb@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

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


#32400

FromJohannes Bauer <dfnsonfsduifb@gmx.de>
Date2012-10-29 17:58 +0100
Message-ID<k6mcjm$99m$1@news.albasani.net>
In reply to#32398
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?

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>

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


#32402

FromPaul Rubin <no.email@nospam.invalid>
Date2012-10-29 10:03 -0700
Message-ID<7xpq41w6q2.fsf@ruckus.brouhaha.com>
In reply to#32400
Johannes Bauer <dfnsonfsduifb@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.

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


#32411

FromGrant Edwards <invalid@invalid.invalid>
Date2012-10-29 18:00 +0000
Message-ID<k6mg8q$sen$1@reader1.panix.com>
In reply to#32400
On 2012-10-29, Johannes Bauer <dfnsonfsduifb@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!

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


#32417

FromIan Kelly <ian.g.kelly@gmail.com>
Date2012-10-29 13:09 -0600
Message-ID<mailman.3042.1351537835.27098.python-list@python.org>
In reply to#32400
On Mon, Oct 29, 2012 at 10:58 AM, Johannes Bauer <dfnsonfsduifb@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.

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


#32399

FromGrant Edwards <invalid@invalid.invalid>
Date2012-10-29 16:52 +0000
Message-ID<k6mc88$qbu$1@reader1.panix.com>
In reply to#32393
On 2012-10-29, Johannes Bauer <dfnsonfsduifb@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            

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


#32401

FromJohannes Bauer <dfnsonfsduifb@gmx.de>
Date2012-10-29 18:01 +0100
Message-ID<k6mcp7$9ub$1@news.albasani.net>
In reply to#32399
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>

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


#32407

FromPeter Otten <__peter__@web.de>
Date2012-10-29 18:17 +0100
Message-ID<mailman.3035.1351531083.27098.python-list@python.org>
In reply to#32401
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__'])

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


#32404

FromPeter Otten <__peter__@web.de>
Date2012-10-29 18:06 +0100
Message-ID<mailman.3032.1351530395.27098.python-list@python.org>
In reply to#32393
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.

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


#32432

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2012-10-29 22:37 +0000
Message-ID<508f050d$0$29967$c3e8da3$5496439d@news.astraweb.com>
In reply to#32393
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

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


#32451

Fromalex23 <wuwei23@gmail.com>
Date2012-10-29 18:37 -0700
Message-ID<761032ae-6c92-4b80-b287-e158ece7582e@kt16g2000pbb.googlegroups.com>
In reply to#32393
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.

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


#32492

Fromandrea crotti <andrea.crotti.0@gmail.com>
Date2012-10-30 14:15 +0000
Message-ID<mailman.3092.1351606518.27098.python-list@python.org>
In reply to#32451
2012/10/30 alex23 <wuwei23@gmail.com>:
> 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.
> --
> 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)

[toc] | [prev] | [standalone]


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


csiph-web