Creating an instance when the argument is already an instance.

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu Jul 5 07:55:33 EDT 2012


On Thu, 05 Jul 2012 12:29:24 +0200, Olive wrote:

> I am learning python -:)
> 
> I am creating a new class: package (to analyse the packages database in
> some linux distros). I have created a class package such that
> package("string") give me an instance of package if string is a correct
> representation of a package. I would like that if pack is already an
> instance of package then package(pack) just return pack.

The built-in types only do this for immutable objects, those which cannot 
be modified.

py> a = float('42.5')
py> b = float(a)
py> a is b
True


But note carefully that this is not a guarantee of the language. Other 
versions of Python may not do this.

Also note carefully that it is only immutable objects which do this. 
Mutable objects do not behave this way:

py> a = ['a', 1, None]
py> b = list(a)
py> a is b
False


By default, most custom-made classes are mutable, and so re-using 
instances is the wrong thing to do. Unfortunately, it is moderately 
tricky to make mutable classes in Python. One way is described here:

http://northernplanets.blogspot.com.au/2007/01/immutable-instances-in-python.html

You can also look at the source code for Decimal (warning: it's BIG) or 
Fraction:

http://hg.python.org/cpython/file/2.7/Lib/decimal.py
http://hg.python.org/cpython/file/2.7/Lib/fractions.py


But suppose you make your class immutable. Then it's quite safe, and 
easy, to get the behaviour you want:


class Package(object):
    def __new__(cls, argument):
        if isinstance(argument, Package):
            return argument
        return object.__new__(cls, argument)


or similar, I haven't actually tested the above. But the important trick 
is to use __new__, the constructor, rather than __init__, which runs 
after the instance is already created, and to use an isinstance test to 
detect when you already have an instance.


Good luck!



-- 
Steven



More information about the Python-list mailing list