简体   繁体   中英

Python Classes: turn all inherited methods private

Class Bar inherits from Foo:

class Foo(object):
      def foo_meth_1(self):
          return 'foometh1'
      def foo_meth_2(self):
          return 'foometh2'
class Bar(Foo):
      def bar_meth(self):
          return 'bar_meth'

Is there a way of turning all methods inherited from Foo private?

class Bar(Foo):
      def bar_meth(self):
          return 'bar_meth'
      def __foo_meth_1(self):
          return 'foometh1'
      def __foo_meth_2(self):
          return 'foometh2'

Python doesn't have privates, only obfuscated method names. But I suppose you could iterate over the methods of the superclass when creating the instance, removing them from yourself and creating new obfuscatingly named method names for those functions. setattr and getattr could be useful if you use a function to create obfuscated names.

With that said, it's a pretty cthuhlu-oid thing to do. You mention the intent is to keep the namespace cleaner, but this is more like mixing ammonia and chlorine. If the method needs to be hidden, hide it in the superclass. The don't create instances of the superclass -- instead create a specific class that wraps the hidden methods in public ones, which you could name the same thing but strip the leading whitespace.

Assuming I understand your intent correctly, I would suggest doing something like this:

class BaseFoo(object):
    def __init__(self):
        raise NotImplementedError('No instances of BaseFoo please.')
    def _foo(self):
        return 'Foo.'
    def _bar(self):
        return 'Bar.'

class HiddenFoo(BaseFoo):
    def __init__(self): pass

class PublicFoo(BaseFoo):
    def __init__(self): pass
    foo = BaseFoo._foo
    bar = BaseFoo._bar

def try_foobar(instance):
    print 'Trying ' + instance.__class__.__name__
    try:
        print 'foo: ' + instance.foo
        print 'bar: ' + instance.bar
    except AttributeError, e:
        print e

foo_1 = HiddenFoo()
foo_2 = PublicFoo()
try_foobar(foo_1)
try_foobar(foo_2)

And if PublicFoo.foo would do something more than BaseFoo.foo , you would write a wrapper that does whatever is needed, and then calls foo from the superclass.

This is only possible with Pyhtons's metaclasses. But this is quite sophisticated and I am not sure if it is worth the effort. For details have a look here

Why would you like to do so?

You can use metaclasses, but Boo will no longer be an actual subclass of Foo, unless you want Foo 's methods to be both 'private' and 'public' in instances of Bar (you cannot selectively inherit names or delattr members inherited from parent classes). Here is a very contrived example:

from inspect import getmembers, isfunction

class TurnPrivateMetaclass(type):
    def __new__(cls, name, bases, d):
        private = {'__%s' % i:j for i,j in getmembers(bases[0]) if isfunction(j)}
        d.update(private)

        return type.__new__(cls, name, (), d)

class Foo:
    def foo_meth_1(self): return 'foometh1'
    def foo_meth_2(self): return 'foometh2'

class Bar(Foo, metaclass=TurnPrivateMetaclass):
    def bar_meth(self): return 'bar_meth'

b = Bar()
assert b.__foo_meth_1() == 'foometh1'
assert b.__foo_meth_2() == 'foometh2'
assert b.bar_meth() == 'bar_meth

If you wanted to get attribute access working, you could create a new Foo base class in __new__ with all renamed methods removed.

Since foo() and __foo() are completely different methods with no link between them, Python is unable to understand what you want to do. So you have to explain to it step by step, meaning (like sapth said) to remove the old methods and add new ones.

This is an Object Oriented Design flaw and a better approach would be through delegation:

class Basic:
    def meth_1(self):
        return 'meth1'

    def meth_2(self):
        return 'meth2'


class Foo(Basic):
    # Nothing to do here
    pass


class Bar:
    def __init__(self):
        self.dg = Basic()

    def bar_meth(self):
        return 'bar_meth ' + self.__meth_1()

    def __meth_1(self):
        return self.dg.meth_1()

    def __meth_2(self):
        return self.dg.meth_2()

While Foo inherits the Basic class because he wants the public methods from him, Bar will only delegate the job to Basic because he doesn't want to integrate Basic 's interface into its own interface.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM