Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if an object is created with `with` statement?

I would like to ensure that the class is only instantiated within a "with" statement.

i.e. this one is ok:

with X() as x:
 ...

and this is not:

x = X()

How can I ensure such functionality?

like image 911
vpas Avatar asked Feb 14 '15 15:02

vpas


People also ask

How will you check when the object is created?

The checking of a value, if it was created by the Object constructor, can simply be done by comparing the object's constructor property value with the corresponding Object constructor function reference.

How do you check object is created or not in Java?

In the main method, we created an object of the User2 class using the new keyword and called the getUser1Object() method. It returns an object of class User1 , which we later store in getUser1Object . To check if it is null, we call the isNull() method and pass the object getUserObject as a parameter.


2 Answers

All answers so far do not provide what (I think) OP wants directly.
(I think) OP wants something like this:

>>> with X() as x:
 ...  # ok

>>> x = X()  # ERROR

Traceback (most recent call last):
  File "run.py", line 18, in <module>
    x = X()
  File "run.py", line 9, in __init__
    raise Exception("Should only be used with `with`")
Exception: Should only be used with `with`

This is what I come up with, it may not be very robust, but I think it's closest to OP's intention.

import inspect
import linecache

class X():
    
    def __init__(self):
        if not linecache.getline(__file__,
            inspect.getlineno(inspect.currentframe().f_back)).lstrip(
        ).startswith("with "):
            raise Exception("Should only be used with `with`")

    def __enter__(self):
        return self
    
    def __exit__(self, *exc_info):
        pass

This will give the exact same output as I showed above as long as with is in the same line with X() when using context manager.

like image 132
laike9m Avatar answered Oct 06 '22 01:10

laike9m


There is no straight forward way, as far as I know. But, you can have a boolean flag, to check if __enter__ was invoked, before the actual methods in the objects were called.

class MyContextManager(object):

    def __init__(self):
        self.__is_context_manager = False

    def __enter__(self):
        print "Entered"
        self.__is_context_manager = True
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print "Exited"

    def do_something(self):
        if not self.__is_context_manager:
            raise Exception("MyContextManager should be used only with `with`")

        print "I don't know what I am doing"

When you use it with with,

with MyContextManager() as y:
    y.do_something()

you will get

Entered
I don't know what I am doing
Exited

But, when you manually create an object, and invoke do_something,

x = MyContextManager()
x.do_something()

you will get

Traceback (most recent call last):
  File "/home/thefourtheye/Desktop/Test.py", line 22, in <module>
    x.do_something()
  File "/home/thefourtheye/Desktop/Test.py", line 16, in do_something
    raise Exception("MyContextManager should be used only with `with`")
Exception: MyContextManager should be used only with `with`

Note: This is not a solid solution. Somebody can directly invoke __enter__ method alone, before calling any other methods and the __exit__ method may never be called in that case.

If you don't want to repeat that check in every function, you can make it a decorator, like this

class MyContextManager(object):

    def __init__(self):
        self.__is_context_manager = False

    def __enter__(self):
        print "Entered"
        self.__is_context_manager = True
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print "Exited"

    def ensure_context_manager(func):
        def inner_function(self, *args, **kwargs):
            if not self.__is_context_manager:
                raise Exception("This object should be used only with `with`")

            return func(self, *args, **kwargs)
        return inner_function

    @ensure_context_manager
    def do_something(self):
        print "I don't know what I am doing"
like image 20
thefourtheye Avatar answered Oct 06 '22 01:10

thefourtheye