Creating an instance when the argument is already an instance.

Discussion in 'Python' started by Olive, Jul 5, 2012.

  1. Olive

    Olive Guest

    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.[color=blue][color=green][color=darkred]
    >>> a=complex(2,3)
    >>> b=complex(a)
    >>> a is b[/color][/color][/color]
    True
    
    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
     
    Olive, Jul 5, 2012
    #1
    1. Advertising

  2. On Thu, Jul 5, 2012 at 8:29 PM, Olive <> 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
     
    Chris Angelico, Jul 5, 2012
    #2
    1. Advertising

  3. 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
     
    Steven D'Aprano, Jul 5, 2012
    #3
  4. Olive

    Hans Mulder Guest

    On 5/07/12 12:47:52, Chris Angelico wrote:
    > On Thu, Jul 5, 2012 at 8:29 PM, Olive <> 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
     
    Hans Mulder, Jul 5, 2012
    #4
  5. Olive

    Olive Guest

    On 05 Jul 2012 11:55:33 GMT
    Steven D'Aprano <> 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
     
    Olive, Jul 6, 2012
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Karl Heinz Buchegger
    Replies:
    6
    Views:
    2,295
    Karl Heinz Buchegger
    Jun 26, 2003
  2. Bhushit Joshipura

    defaulting argument to previous argument

    Bhushit Joshipura, Dec 29, 2003, in forum: C++
    Replies:
    5
    Views:
    428
  3. Mike
    Replies:
    5
    Views:
    498
    Ben Finney
    Dec 28, 2003
  4. John Salerno
    Replies:
    10
    Views:
    493
    John Salerno
    Jun 16, 2008
  5. Strato
    Replies:
    6
    Views:
    343
Loading...

Share This Page