473,383 Members | 1,813 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,383 software developers and data experts.

Easy immutability in python?

Is there an *easy* way to make an object immutable in
python? Or perhaps I should say "one obvious way to do it"?
Oughtn't there to be one?

I've found a thread on how to do this[1], which essentially
says something like "redefine __setattr__, __delattr__,
__hash__, __eq__, __setitem__, delitem__ ... and probably
some other stuff too".

[1]

Yet, what you have to do is pretty mechanical (e.g. all the
mutators have to raise NotImplementedError and the hashes
and comparisons seem like they have obvious defaults).

Given that I have some kind of container, like an overloaded
list, and I just say "oh, I need that to be immutable, like
a tuple" -- it would be nice to just be able to declare it
so. I just want this for QA purposes -- I have a pretty
complex system, and I want the programmer to be warned when
he accidentally tries to change an immutable enumeration or
redefine a symbol.

I know a (hard and error-prone) way to do it, but I'm
thinking there must be a "smart" way to do it.

Is there some way to do that with, e.g. decorators?

(I haven't really figured out why I should want decorators,
is this a use case?).

Or maybe I should make an "Immutable" class, and just
inherit from it last so it overloads everything else with
the null interfaces?

--
Terry Hancock (ha*****@AnansiSpaceworks.com)
Anansi Spaceworks http://www.AnansiSpaceworks.com

Mar 4 '06 #1
3 6349
Since this is a container that needs to be "immutable, like a tuple",
why not just inherit from tuple? You'll need to override the __new__
method, rather than the __init__, since tuples are immutable:

class a(tuple):
def __new__(cls, t):
return tuple.__new__(cls, t)

cheers,
Jess

Mar 4 '06 #2
To be clear, in this simple example I gave you don't have to override
anything. However, if you want to process the values you place in the
container in some way before turning on immutability (which I assume
you must want to do because otherwise why not just use a tuple to begin
with?), then that processing should take place in a.__new__.

cheers,
Jess

Mar 4 '06 #3
On 4 Mar 2006 10:14:56 -0800
je*********@gmail.com wrote:
Since this is a container that needs to be "immutable,
like a tuple", why not just inherit from tuple? You'll
need to override the __new__ method, rather than the
__init__, since tuples are immutable:

class a(tuple):
def __new__(cls, t):
return tuple.__new__(cls, t)


The reason this is undesireable, is because in the typical
use-case, I want to have TWO kinds of objects, one mutable,
and one immutable. Just like tuple / list. I would prefer
not to have to implement them completely separately. So
far, it's usually simpler to implement the mutable type
first -- the need for immutability semantics usually arises
after you have a mutable version.

But undoing mutability apparently is like making a sieve
watertight -- it would've been easier to design a ladle and
then put holes in it, than to design a sieve and then stop
up the holes.

In fact, my particular case wants to subclass Set and
ImmutableSet -- their contents, though, are also immutables
in principle. In fact the elements are similar to "int" or
"str", but I don't want to subclass those, because I don't
want them to have math methods or string methods.

I've considered several different approaches to this. One is
to create a "BaseVocabulary" as an abstract class, from
which the mutable and immutable types are drawn, and then
mix it in with Set and ImmutableSet:

class BaseVocabulary(object):
def __init__(self, values):
self._data = values
# (or something like that)
# other functionality

class Vocabulary(Set, BaseVocabulary):
# stuff appropriate for the "open" vocabulary
pass

class Enumeration(ImmutableSet, BaseVocabulary):
# stuff appropriate for the "closed" enumeration
pass

This is bad, both aesthetically and practically.
Aesthetically, because "abstract classes stink of Java" and
pragmatically because the __init__ from BaseVocabulary
will generally not work for the immutable case.

So I either have to rewrite it special, or go back in
time and fix the original, knowing that I'm going to want
an immutable variant.

Again with the aesthetics, it's just ugly that I can't
mutate an object in its __init__ and then make it immutable
after I'm done setting it up. The approach with __new__ and
using the superclass's __setattr__ to set values is nasty
boilerplate-rich cruft which forces me to go back and
completely re-implement the same functionality in a
completely different way, just because of something that
seems like a simple conceptual change (i.e. "don't overwrite
or extend this thing -- make a new one if you need a
change").

I even tried defining __setattr__ at the end of the
__init__, but that doesn't seem to work (or I'm doing it
wrongly).

Right now I'm leaning towards making a class "Immutable"
with all the mutator methods raising NotImplementedError,
and then subclass from this so that it overrides the
necessary methods. It's still going to mess with me, though,
because it will not allow the __init__ to work as planned,
and I'll have to go back and redesign the base class to work
with or without immutability.

Alternatively, I could just decide to change my practice and
implement ALL objects on the assumption that they will be
immutable, and add *mutability* after-the-fact. But that
seems like extraordinarily bad practice, since mutability is
usually the better default.

I'm going to dig through the sets module code to see how it
does this, but what little I've seen gives me a bad feeling
that this simple idea is hard to implement simply in Python
-- and that strikes me as a "wart", yes.

So, I'm wondering if there is a simple way after all.

1) Is there an idiom for this that I just don't know?

2) Have recent changes to the language made it easier?
(__new__ for example, is apparently new, or at least
newly documented -- but as I say, I'm not sure it's
the most practical solution for this problem).

3) Is there a "remarkably clever" way that I can tack
on, even if it isn't exactly simple?

and only in the unlikely event that answers 1-3 are all
"no", would I ask:

4) And as a last resort, if it really is hard, why?
Shouldn't a simple idea to express in English be easy to
express in Python? If it's really impossibly difficult,
maybe Python should provide a means to implement it.

Cheers,
Terry

--
Terry Hancock (ha*****@AnansiSpaceworks.com)
Anansi Spaceworks http://www.AnansiSpaceworks.com

Mar 4 '06 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: javac | last post by:
for better or worse, my free time is consumed by two Java series books from Sun: Java Platform Performance, 2000, by Wilson and Kesselman Effective Java, 2001, by Bloch 1.) opinions on these...
4
by: rb | last post by:
Hi This is a sample code I am working on. string a = "rb" string b = a Console.WriteLine(Object.ReferenceEquals(a,b)) In the above code, its printing true. I have a doubt on this output....
37
by: Nick Maclaren | last post by:
The way that I read it, Python allows only values (and hence types) to be immutable, and not class members. The nearest approach to the latter is to use the name hiding conventions. Is that...
0
by: Tommy | last post by:
Our application uses BigDecimal, and BigDecimal is immutable. Immutability is certainly a good thing, but it also means that there are a lot more memory allocations (and collections). That's ok, we...
0
by: Roy Smith | last post by:
In article <mailman.2119.1219612653.922.python-list@python.org>, "Hendrik van Rooyen" <mail@microcorp.co.zawrote: Reminds me of that great old song from "Saturday Night Hacker": Oh, oh, oh,...
0
by: Simon Brunning | last post by:
2008/8/25 Hendrik van Rooyen <mail@microcorp.co.za>: You can indeed use ctypes to modify the value of a string - see <http://tinyurl.com/5hcnwl>. You can use it to crash the OS, too. My advice...
0
by: Hendrik van Rooyen | last post by:
"Gabriel Genellina": Thanks Gabriel – looks like I really have to spend more time with that excellent document. Patrick Maupin:
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.