1

I have a class that I want it to accept an instance of that same class as initialization; in such case, it will simply return that instance.

The reason is that I want this class to accept a myriad of initialization values and then the proceeding code can use this as an object with known properties, independent on how it was initialized.

I have thought of something like:

class c(object):
  def __new__(cls, *args, **kwargs):
    if isinstance(args[0], c):
      return args[0]
    else:
      return super(c, cls).__new__(cls, *args, **kwargs)

The problem is that I don't want __init__() to be called when initialized in this manner. Is there any other way?

Thanks!

4
  • Why don't you want __init__() to be called? Would it be OK if __init__() were called, but didn't do anything? Commented Jul 25, 2016 at 17:27
  • __init__() should be called only when args[0] is not of the class Commented Jul 25, 2016 at 21:56
  • Yes, you already stated that in your question. But I am asking you: Why is that important? How important is it that you avoid the call? You can easily make the call do nothing when initializing with an instance, or do something when initializing with other values. Commented Jul 25, 2016 at 22:30
  • Hmmm, you are right... for some reason at first it did not look too pythonic to have the if clause checked twice in two different functions, but it could look better than factory or initializing in __new__, and simpler than metaclassing. Thanks everyone! Commented Jul 25, 2016 at 23:20

3 Answers 3

1

You probably want to use a factory (f.e. see this question for details or google). Or just use a class method for what you want, f.e.:

class C(object):
    @classmethod
    def new(cls, *args, **kwargs):
        if isinstance(args[0], cls):
            return args[0]
        else:
            return cls(*args, **kwargs)

obj = C.new()
obj2 = C.new(obj)
Sign up to request clarification or add additional context in comments.

Comments

1

The standard way to do this is to simply not do your initialization in __init__. Do it in __new__.

Comments

1

You can use a metaclass

class InstanceReturnMeta(type):  # You should probably think of a better name
    def __call__(cls, *args, **kwargs):
        if args and isinstance(args[0], cls):
            return args[0]
        instance = cls.__new__(cls, *args, **kwargs)
        instance.__init__(*args, **kwargs)
        return instance


class Test(object):
    __metaclass__ = InstanceReturnMeta
    def __init__(self, value):
        self.value = value

Let's test it

In [3]: instance1 = Test(0)
In [4]: instance2 = Test(instance1)
In [5]: print id(instance1) == id(instance2)
Out[5]: True

The ids are identical, hence both variables reference the same instance.

P.S. I assume you are on Python 2, since your class explicitly inherits from object.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.