Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a non-instantiable class?

For one of the project I am currently working I was thinking of creating a class that could not be instantiate by a client and only be supplied an instance of through a particular interface i.e. the client would not be able create further instance out of it by some hackery such as:

>>> try:
...     raise WindowsError
... except:
...     foo = sys.exc_info()
... 
>>> foo
(<type 'exceptions.WindowsError'>, WindowsError(), <traceback object at 0x0000000005503A48>)
>>> type(foo[2])()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot create 'traceback' instances

once he has one.

I was successfully able to create a class that couldn't be instantiated. i.e.

>>> class Foo():
...     def __init__(self):
...         raise TypeError("cannot create 'Foo' instances")
... 
>>> bar = Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: cannot create 'Foo' instances
>>> bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'bar' is not defined

But how could I use this every same definition to create an instance of the class?

Of course I could do something like this:

>>> class Foo():
...     def __init__(self, instantiate = False):
...         if not instantiate:
...               raise TypeError("cannot create 'Foo' instances")

but I don't find it elegant enough nor does it completely prevent the client from further instantiating it. And no I aint going down the road of building a C++ module for it.

Any suggestions on how to achieve such a thing? import abc?

A brief rational to answer Martijn's question and for completeness:

Actual you could consider the instance of the particular, and related, classes, in question, as nodes in a tree and that both the parent and the children to remain connected, dependent on and cognizant of each other and have a single unique root throughout any instance of python(insured by the use package). Any state changes in a particular node would cause others to update themselves and the database to which they are connect, accordingly. Apart from that I was being curious to know how such a thing could be put in place (the traceback class was teasing me).

like image 516
Bleeding Fingers Avatar asked Apr 23 '13 13:04

Bleeding Fingers


People also ask

What is non-Instantiable?

Adjective. noninstantiable (not comparable) Not instantiable; that cannot be instantiated.

How do you make a class not extendable in Java?

You can use final keyword in java, sealed in C# to make a class non-extendable.

Which keyword is used for non-Instantiable class?

The static keyword is used to make a data item non-instantiable. It can be used with classes, methods, variables, constructors, operators etc.


1 Answers

What you're doing is a bad idea, you shouldn't do it. I'm sure there's an other, better solution. If you do decide to go with your way anyways (you shouldn't), here's how you can create an object without using __init__():


Objects in python are created with the __new__() method. The method __init__() only edits the object which was created by __new__(). For example, __init__() usually initializes some attributes for the object.

When declaring something like x = Foo() what happens is this:

  1. x = object.__new__(Foo) gets called first and creates the object.
  2. Foo.__init__(x) gets called second, it simply initializes some attributes etc. to the already existing object.

This means that you are not required to call Foo() (and as a result, call __init__() too). Instead, you can just call __new__() directly:

class Foo(object):
    def __init__(self):
        raise TypeError("Cannot create 'Foo' instances.")

>>> x = object.__new__(Foo)
>>> x
<__main__.Foo object at 0x02B074F0>

Our x is now an instance of Foo, without any attributes that is, and it can use any methods defined in Foo class.

If you want, you can create your own replacement function of __init__ for initializing attributes:

def init_foo(foo, name):
    foo.name = name

>>> init_foo(x, "Mike")
>>> x.name
'Mike'

This could of course be Foo's instance method too:

class Foo(object):
    def __init__(self):
        raise TypeError("Cannot create 'Foo' instances.")

    def init(self, name):
        self.name = name

>>> x = object.__new__(Foo)
>>> x.init("Mike")
>>> x.name
'Mike'

Going even step further, you can even use a classmethod for creating your object with only one call:

class Foo(object):
    def __init__(self):
        raise TypeError("Cannot create 'Foo' instances.")

    @classmethod
    def new(cls, name):
        obj = object.__new__(cls)
        obj.name = name
        return obj

>>> x = Foo.new("Mike")
>>> x.name
'Mike'
like image 96
Skamah One Avatar answered Oct 11 '22 03:10

Skamah One