dynamic type changing
Bruno Desthuilliers
bdesth.quelquechose at free.quelquepart.fr
Sun May 28 14:58:10 EDT 2006
andychambers2002 at yahoo.co.uk a écrit :
>>>I'm working on a "TempFile" class that stores the data in memory until
>>>it gets larger than a specified threshold (as per PEP 42). Whilst
>>>trying to implement it, I've come across some strange behaviour. Can
>>>anyone explain this?
>
>
>>>The test case at the bottom starts a TempFile at size 50 and prints its
>>>type. It then increases the size to the threshold at which point
>>>"self" is changed to being a TemporaryFile.
>
>>Changed how ?-)
>
> Just by being assigned with a TemporaryFile object.
>
> I thought that if
> you do
>
> instance = TempFile()
>
> that "instance" and "self" defined in the Class
They are not defined "in the class".
> were the same thing so
> that if you changed the class of self,
> the class of instance would also
> change.
Yes, of course - but you didn't change the class of 'self' !-)
Python's "variable" are really just names "bound to" (referring to)
objects. Rebinding (ie: assignment) does not impact the object (well,
not directly), it just associate the name to another object. This is
totally different from changing the state of the object.
There's nothing magical about the name 'self' - FWIW, you could replace
it by any other valid python identifier. In Python, a method is just a
plain function that takes the instance as the first argument. This
function is wrapped into a method descriptor (google for python's
descriptor protocol - it's the same thing that is used for properties)
that takes care of feeding the function with the instance.
FWIW, given:
class Obj(object):
def someMethod(self):
pass
obj = Obj()
then
obj.someMethod()
is the same as
Obj.someMethod(obj)
or also:
obj.someMethod.im_func(obj)
So, inside someMethod's code, normal scoping rules apply. This means
that 'self' is a *local* name, and rebinding it only affect the local
scope. And it doesn't "change the type" of the object (previously) bound
to 'self', it really re-bind 'self' to another object (IOW: makes 'self'
a reference to another object). Just like it does in any other Python code.
As I wrote, to dynamicall change the class of an object, you must rebind
obj.__class__ to another class, ie:
class Other(object):
def __init__(self, name):
self.name = name
obj = Obj()
print type(obj)
obj.__class__ = Other
print type(obj)
Now a big warning : this is not garanteed to work seamlessly ! 'obj'
will keep it's original instance attributes, and the instance attributes
normally set up by the new class (here, 'Other') won't exist since the
class initializer won't be called.
So, while this may not be a problem if the original and new classes are
designed to be used that way (which makes a very straightforward
implementation of the state pattern), it's usually not a good idea to do
such a thing. FWIW, it's usually simpler and safer - evn if a bit less
elegant - to implement the state pattern just like I did in the example:
by using composition/delegation.
> Thanks very much for your example.
<reverence>votre humble serviteur, Messire</reverence>
> It has solved my problem and helped
> me understand a new pattern at the same time.
<ot>
FWIW, there's no clear, well defined boudary between State and Strategy
- the main difference depends mostly on the intention. Your use case
could also be viewed as a State pattern, with 2 states : buffer <
capacity, and buffer >= capacity. But the intention is not to know in
which state is the object - on the contrary, you're trying to hide away
the chosen implementation (StringIO or TemporayFile) - so it's really a
Strategy IMHO.
</ot>
More information about the Python-list
mailing list