username
username

Reputation: 19630

Replace instance with a float from within instance method?

I'm writing a Python script to parse some data. At the moment I'm trying to make a Class which creates "placeholder" objects. I intend to repeatedly pass each "placeholder" variables, and finally turn it into a dict, float, list or string. For reasons that would take a while to describe, it would be a lot easier if I could replace the instance by calling a method.

Here's a simplified example

class Event( dict ):

    def __init__( self ):

        self.sumA = 0.0
        self.sumB = 0.0

    def augmentA( self, i ):

        self.sumA += i

    def augmentB( self, i ):

        self.sumB += i

    def seal( self ):

        if self.sumA != 0 and self.sumB != 0:
            self = [ sumA, sumB ]

        elif self.sumA != 0:
            self = float( sumA )

        elif self.sumB != 0:
            self = float( sumB )

And what I want to do is:

e = Event()
e.augmentA( 1 )
e.augmentA( 2 )
e.seal()

...and have 'e' turn into a float.

What I am hoping to avoid is:

e = Event()
e.augmentA( 1 )
e.augmentA( 2 )
e = e.getSealedValue()

I totally understand that "self" in my "seal" method is just a local variable, and won't have any effect on the instance outside scope. I'm unsure however how to achieve what I want, from within the instance, where it would be most convenient for my code. I also understand I could override all the bulit-ins ( getItem, toStr ) but that complicates my code a lot.

I'm a Python noob so I'm unsure if this is even possible. Indulge me, please :)

Upvotes: 2

Views: 1222

Answers (3)

Amber
Amber

Reputation: 527238

No, you cannot have an variable value replace itself by calling a method on it. The normal way to do this would be what you stated: e = e.getSealedValue()

You can make an object change behavior, but that's generally considered a bad idea and is likely to result in highly unmaintainable code.

Upvotes: 2

mgibsonbr
mgibsonbr

Reputation: 22007

Under some circunstances, Python allows you to change the class of an object on the fly. However, not any object can be converted to any class, as the example below demonstrates (newlines added for readability):

>>> class A(object):
...   pass
...
>>> class B(object):
...   pass
...
>>> a = A()
>>> type(a)
<class '__main__.A'>

>>> a.__class__ = B
>>> type(a)
<class '__main__.B'>

>>> a.__class__ = int
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: only for heap types

(I don't know the exact rules from the top of my head, but if your classes uses __slots__ for instance they must be compatible for the conversion to be possible)

However, as other answerers pointed out, in general it's a very bad idea to do so, even if there was a way to convert every reference to one object to a reference to another. I wouldn't go as far as saying never do that though, there might be legitimate uses of this technique (for instance, I see it as an easy way of implementing the State Design Pattern without creating unnecessary clutter).

Upvotes: 2

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 799230

Even if there was some sane way to make it work, I would avoid going down this path simply because it changes the type of the object to something completely incompatible with its existing contract.

Now, one could say "but I'm only using it in one place, other code paths won't ever see the old contract", but unfortunately that isn't an argument for this mechanism since you could simply only make the value available for the other code paths once you have the final object.

In short, don't do this and don't even try.

Upvotes: 2

Related Questions