group several methods under a attribute

J

jelle

Hi,

I'm working on a pretty large class and I'd like to group several
methods under a attribute.
Its not convenient to chop up the class in several smaller classes,
nor would mixins really solve the issue.
So, what is a pythonic way of grouping several methods under a
attribute?

Many thanks in advance,

-jelle
 
G

Gerhard Häring

jelle said:
Hi,

I'm working on a pretty large class

Can you describe what its purpose is?
and I'd like to group several methods under a attribute.

That doesn't work in Python without bending the Python.
Its not convenient to chop up the class in several smaller classes,

But that's almost certainly the right thing to do.
nor would mixins really solve the issue.
So, what is a pythonic way of grouping several methods under a
attribute?

Whatever it is, you should find a better way instead of cramming
everything into a single class. That smells of the God Object
antipattern (http://en.wikipedia.org/wiki/God_object).

-- Gerhard
 
A

Aaron Brady

Hi,

I'm working on a pretty large class and I'd like to group several
methods under a attribute.
Its not convenient to chop up the class in several smaller classes,
nor would mixins really solve the issue.
So, what is a pythonic way of grouping several methods under a
attribute?

Many thanks in advance,

-jelle

Hi jelle,

I disagree with Gerhard that you 'should find a better way' and
another way 'almost certainly the right thing', unless his reason is
merely that it's an advanced technique that will get you into problems
down the road. There's nothing 'un-object-oriented' about it. The
link to the God pattern alleges that it fails to 'divide and conquer',
but you are dividing. I think Python opens some beautiful doors in
this regard.

Here is some code which I understand accomplishes what you sought.

class ClsA( object ):
def __init__( self ):
self.inst= None
def __get__( self, instance, owner ):
self.inst= instance
return self
def submethA( self, arg ):
print( 'submethA %r, instance %r'% ( arg, self.inst ) )

class ClsB( object ):
A= ClsA( )
def methA( self, arg ):
print( 'methA %r'% arg )

b= ClsB( )
b.methA( 'this' )
b.A.submethA( 'that' )

#Output:
'''
methA 'this'
submethA 'that', instance <__main__.ClsB object...>
'''

In Python 3, you don't need 'ClsA' and 'ClsB' to inherit from 'object'
explicitly. If you call 'b.A' from a class, 'ClsB.A', you will get a
'ClsA' object with a None 'inst' attribute, which is a big hole
waiting for you to step in. Perhaps you want a wrapper for your
methods of 'ClsA' to check that 'inst' is set, or merely throw an
exception in '__get__' if 'instance' is 'None'. Python after all
requires that a method's first argument be an instance of an improper
subclass of the class it was defined for.
 
A

Aaron Brady

Hi jelle,

I disagree with Gerhard that you 'should find a better way' and
another way 'almost certainly the right thing', unless his reason is
merely that it's an advanced technique that will get you into problems
down the road. snip
class ClsA( object ):
    def __init__( self ):
        self.inst= None
    def __get__( self, instance, owner ):
        self.inst= instance
        return self
snip

There's a potential conflict in the above, which may have contributed
to Gerhard's advice.

If you have:

bA= ClsB( )
bB= ClsB( )
bA.A.submethA( 'what' )

then the ClsA instance will think it's being accessed from 'bA' until
it's accessed again! This may cause problems such as if you store a
reference to it, because bB could access it, and it won't think it's
being accessed from bA anymore. To get around this, you probably want
'__get__' to create a new object that is specifically dedicated to the
instance of ClsB that's calling it. bA.A and bB.A return new objects,
separate from each other. However, then two calls to bA.A won't
return the same object; they'll return new every time.

Another detail is that ClsA can't store instance information. It
should be stored in ClsB instances, and the methods merely go
somewhere else. Otherwise, the right place for 'A= ClsA( )' is in the
constructor:

class clsB:
def __init__( self ):
self.A= ClsA( )

Then, every ClsB instance has its own instance of ClsA, and it can
store instance information, and doesn't create new instances when you
call it. The creation of 'ClsA' merely goes in the initializer, not
the class statement.
 
J

jelle

Hi Aaron,

Thanks a lot for your suggestions.
I wasnt familiar with the __get__ magic, which seems interesting.

So, finally it seems that the cleanest pattern is:

class ClsA( object ):
def __init__( self, other ):
self.inst= other

def submethA( self, arg ):
print( 'submethA %r, instance %r'% ( arg, self.inst ) )

class ClsB( object ):
def methA( self, arg ):
self.A= ClsA( self )
print( 'methA %r'% arg )

b= ClsB( )
b.methA( 'this' )
b.A.submethA( 'that' )


Many thanks,


-jelle
 
A

Aahz

You'll note that this is, all Aaron's protests to the contrary,
splitting your class up into multiple cooperating classes.
Ayup.

If you're set on doing it like this, doing it this way avoids polluting
your namespace so much:

class ClsB(object):
class ClsA(object):
def do_something(self):
print "Here's A doing something"

def __init__(self):
self.A = ClsB.ClsA()

def do_something(self):
print "Here's B doing something"

Blech. The pollution caused by a separate class is minimal, and nested
class definitions are likely to have problems (the most obvious is that
pickling will break).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top