Writing an immutable object in python

M

Mapisto

Hi,

I've noticed that if I initialize list of integers in the next manner:

It works just fine, even if I'll try to assign one element:
id( my_list[4] ) 10900116
id( my_list[6] ) 10900116
my_list[4] = 6
id( my_list[4] ) 10900044
id( my_list[6] )
10900116

The change in the poision occurs becouse int() is an immutable object.

if I will do the same with a user-defined object, This reference
manipulating will not happen. So, every entry in the array will refer
to the same instance.

Is there a way to bypass it (or perhaps to write a self-defined
immutable object)?
 
D

Diez B. Roggisch

The change in the poision occurs becouse int() is an immutable object.
if I will do the same with a user-defined object, This reference
manipulating will not happen. So, every entry in the array will refer
to the same instance.

Is there a way to bypass it (or perhaps to write a self-defined
immutable object)?

This has nothing to do with int being mutable or not. It only has to do
with _list_ being mutable, and of course teh semantics of the

_ * _ : list x int -> list

operator, which simply shallow copies the list. So assigning to some

l


will replace that entry - regardless of what is stored there. And that
is all you do. The mutablity of an object only comes into place if you
try and do

l.some_mutating_op()

That catches many people by surprise - but you don't do such a thing :)

And besides: making an object immutable would mean that the only way to
create an instance would be the constructor - rendering the purpose of
the whole exercise somewhat moot - as then you'd have to call the
constructor individually for each index you want to alter anyway. Which
you have to do in the case of mutable objects, too. So - no gain there.

Regards,

Diez
 
M

Magnus Lycka

Mapisto said:
Hi,

I've noticed that if I initialize list of integers in the next manner:



It works just fine, even if I'll try to assign one element:

id( my_list[4] )
10900116
id( my_list[6] )
10900116
my_list[4] = 6
id( my_list[4] )
10900044
id( my_list[6] )

10900116

The change in the poision occurs becouse int() is an immutable object.

No, it happens because you assign my_list[4] to a different object.
Obviously, 0 and 6 can't be located in the same place in RAM.

The difference lies in doing something like "my_list[n] = X" rather
than changing the state of a shared existing object as in something
like "my_list[n].f(X)".
if I will do the same with a user-defined object, This reference
manipulating will not happen.
Really?
.... pass
....
>>> my_list = [C()]*30
>>> id(my_list[4]) 1003056
>>> id(my_list[6]) 1003056
>>> my_list[4] = C() # Another instance
>>> id(my_list[4]) 986048
>>> id(my_list[6])
1003056
 
D

Donn Cave

"Mapisto said:
I've noticed that if I initialize list of integers in the next manner:

It works just fine, even if I'll try to assign one element:
id( my_list[4] ) 10900116
id( my_list[6] ) 10900116
my_list[4] = 6
id( my_list[4] ) 10900044
id( my_list[6] )
10900116

The change in the poision occurs becouse int() is an immutable object.

if I will do the same with a user-defined object, This reference
manipulating will not happen. So, every entry in the array will refer
to the same instance.

Not at all. If you do the same thing,
class C:
pass
c = C()
a = [c]*12

.... etc., you should observe the same pattern with respect to
object identities. Mutability doesn't really play any role here.
Is there a way to bypass it (or perhaps to write a self-defined
immutable object)?

Bypass what? What do you need?

Donn Cave, (e-mail address removed)
 
M

Mapisto

Ok, I've understood my mistake.

Now, my list contains a shared entry of an empty object. When an entry
is needed to be changed, I check if the entry is the shared empty
object; in that case I create a new unique instance. If the entry is
already a unique instance, I use it, so the empty object isn't touched.


Thanks,
Guy.
 
M

Magnus Lycka

Mapisto said:
Ok, I've understood my mistake.

Now, my list contains a shared entry of an empty object. When an entry
is needed to be changed, I check if the entry is the shared empty
object; in that case I create a new unique instance. If the entry is
already a unique instance, I use it, so the empty object isn't touched.

It's probably less confusing if you make a list
of None, instead of a list of references to an
instance object you don't use anyway.
 
M

Magnus Lycka

Mapisto said:
Ok, I've understood my mistake.

Now, my list contains a shared entry of an empty object. When an entry
is needed to be changed, I check if the entry is the shared empty
object; in that case I create a new unique instance. If the entry is
already a unique instance, I use it, so the empty object isn't touched.

If you know that you'll use all list entries, you
might as well do it right from the start. Instead
of:

l = [C()] * n

you can do:

l = [C() for i in range(n)]
 

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

Forum statistics

Threads
474,001
Messages
2,570,254
Members
46,849
Latest member
Fira

Latest Threads

Top