Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #24906 > unrolled thread

Creating an instance when the argument is already an instance.

Started byOlive <diolu@bigfoot.com>
First post2012-07-05 12:29 +0200
Last post2012-07-06 16:01 +0200
Articles 5 — 4 participants

Back to article view | Back to comp.lang.python


Contents

  Creating an instance when the argument is already an instance. Olive <diolu@bigfoot.com> - 2012-07-05 12:29 +0200
    Re: Creating an instance when the argument is already an instance. Chris Angelico <rosuav@gmail.com> - 2012-07-05 20:47 +1000
      Re: Creating an instance when the argument is already an instance. Hans Mulder <hansmu@xs4all.nl> - 2012-07-05 16:43 +0200
    Re: Creating an instance when the argument is already an instance. Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-07-05 11:55 +0000
      Re: Creating an instance when the argument is already an instance. Olive <diolu@bigfoot.com> - 2012-07-06 16:01 +0200

#24906 — Creating an instance when the argument is already an instance.

FromOlive <diolu@bigfoot.com>
Date2012-07-05 12:29 +0200
SubjectCreating an instance when the argument is already an instance.
Message-ID<20120705122924.481a546b@bigfoot.com>
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.

This is exactly the behaviour of many of the built-in types. For
example:

[code]
[oesser@pcolivier ~]$ python2
Python 2.7.3 (default, Apr 24 2012, 00:06:13) 
[GCC 4.7.0 20120414 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a=complex(2,3)
>>> b=complex(a)
>>> a is b
True
[/code]

I note here that b is not a new instance of complex, it is another name
for a (as we can see with a is b). I would like to implement such
behaviour but I do not not how.

Olive

[toc] | [next] | [standalone]


#24907

FromChris Angelico <rosuav@gmail.com>
Date2012-07-05 20:47 +1000
Message-ID<mailman.1820.1341485274.4697.python-list@python.org>
In reply to#24906
On Thu, Jul 5, 2012 at 8:29 PM, Olive <diolu@bigfoot.com> wrote:
> 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.

One way would be to make the name "package" actually a wrapper
function, not the class itself:

>>> class _package:
	def __init__(self,arg):
		# blah blah
		self.asdf=arg

>>> def package(arg):
	if isinstance(arg,_package): return arg
	return _package(arg)

>>> a=package("Test")
>>> b=package(a)
>>> a is b
True

The leading underscore is a common convention meaning "private
implementation detail".

Chris Angelico

[toc] | [prev] | [next] | [standalone]


#24923

FromHans Mulder <hansmu@xs4all.nl>
Date2012-07-05 16:43 +0200
Message-ID<4ff5a820$0$6982$e4fe514c@news2.news.xs4all.nl>
In reply to#24907
On 5/07/12 12:47:52, Chris Angelico wrote:
> On Thu, Jul 5, 2012 at 8:29 PM, Olive <diolu@bigfoot.com> wrote:
>> 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.
> 
> One way would be to make the name "package" actually a wrapper
> function, not the class itself:
> 
>>>> class _package:
> 	def __init__(self,arg):
> 		# blah blah
> 		self.asdf=arg
> 
>>>> def package(arg):
> 	if isinstance(arg,_package): return arg
> 	return _package(arg)
> 
>>>> a=package("Test")
>>>> b=package(a)
>>>> a is b
> True
> 
> The leading underscore is a common convention meaning "private
> implementation detail".

I think using a factory function is the right idea, but the
code above doesn't solve the problem as stated.  Olive needs
a factory function that takes a string argument and returns
a _package object.

Maybe:

class _package:
    def __init__(self, name):
        self.name = name
         # etc.

packages = dict()

def package(name):
    if name not in packages:
        packages[name] = _package(name)
    return packages[name]


Hope this helps,

-- HansM

[toc] | [prev] | [next] | [standalone]


#24909

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2012-07-05 11:55 +0000
Message-ID<4ff580b4$0$29988$c3e8da3$5496439d@news.astraweb.com>
In reply to#24906
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

[toc] | [prev] | [next] | [standalone]


#24970

FromOlive <diolu@bigfoot.com>
Date2012-07-06 16:01 +0200
Message-ID<20120706160124.1fa7f5e0@bigfoot.com>
In reply to#24909
On 05 Jul 2012 11:55:33 GMT
Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:

> 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.
> 

Yes the trick with the __new__ works. We have to test afterwards i the
__init__ if the instance is already initialised and otherwise do
nothing. Thanks! I am learning and I didn't know the __new__ feature.

Olive

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web