4

Is there a way to enter an object's namespace so that I can use its methods as though they were global? I was thinking of something using the with statement.

class Bar():
    
    def methodA(self):
        # do stuff

    def methodB(self):
        # do more stuff

    def __enter__(self):
        # somehow enter object namespace / transfer methods into global namespace

    def __exit__(self, *args):
        # exit object namespace / get rid of globalized methods

foo = Bar()

with foo:
    methodA() # all works fine
    methodB()

methodA() # throws an error

This is just a thought, that might not work at all. Or maybe there's a solution without the with statement.

5
  • Have you read e.g. stackoverflow.com/q/24920220/3001761? Commented Nov 22, 2020 at 20:00
  • Can you clarify why would want to do this? Commented Nov 22, 2020 at 20:13
  • I see where the request comes from (that with construct is used in other languages). I have used it in the past. I don't think this is an advisable Python pattern to follow. This is somewhat related to having to write self inside methods. Commented Nov 22, 2020 at 20:34
  • It was decided you should have to. Commented Nov 22, 2020 at 20:35
  • 1
    @MaximilianPeters I've been playing with the Cairo graphics framework a bit lately, which involves calling different methods on the same object a bunch of times in a row. And I had a "Wouldn't it be great if ..." moment. I thought of writing a wrapper class that reduces Cairo boilerplate and manages different image layers to combine them into one in the end. Commented Nov 22, 2020 at 20:36

3 Answers 3

2

This answers the original question but I suggest don't use it.


Similar to the suggested way of wKavey.

But I'm not sure why I would want to do that. I would need to make sure that there is no variable methodA in the global namespace.

class Bar():
    
    def __init__(self, value=5):
        self.value = value
        
    def methodA(self):
        return self.value

    def methodB(self):
        return -self.value

    def __enter__(self):
        global methodA
        global methodB
        methodA = self.methodA
        methodB = self.methodB

    def __exit__(self, *args):
        global methodA
        del methodA
        global methodB
        del methodB
        pass

foo = Bar()

with foo:
    print(methodA()) # all works fine
    print(methodB())

methodA() # throws an error
Sign up to request clarification or add additional context in comments.

5 Comments

Probably worth checking for a pre-existing global methodA so you can cache it if exists and restore it on exit. Otherwise this has the potential to clobber a name that existed before entering the context manager.
Problem is if some other place is relying on the original global value to work properly. @80KiloMett, While this looks good, I do not think it should be used, not because of the technique per see, but because of affecting globals. And there is no need to even imagine concurrency. You might even call the affected code (in some function call) inside the with block, without noticing.
@progmatico Yeah, it doesn't look great. Especially when you have a few more than two methods you want to make available. Then you start looping through the class dict and find yourself with an object's init method in global space. I don't even know the implications of that. Maybe with some book keeping of the changes one could pull it off half way clean. But that's probably not worth the effort.
@80KiloMett Maybe PEP 555 is of help too. Adding values to a local context (or to the local scope) instead would be less dangerous. Local contexts are thread-safe too.
Guess I'm going to mark this as solved. With the absence of other ways to do this suggestion not to use this one, I guess it can stand as a solution.
0

You can probably use the techniques described here: Insert variable into global namespace from within a function?

I'd imagine it will require some bookkeeping in the __enter__ and __exit__ functions in order to clean up after itself. This isn't really something standard, so there my be some other foot-guns that I'm overlooking.

Comments

0

(oh. Maximilian Peters' answer is doing the same with slightly different syntax and was here first...)

nothing i'd recommend but you could do this (you get in trouble of course if there is already a methodA in the global namespace):

class Bar():

    def methodA(self):
        print("methodA called")

    def methodB(self):
        print("methodB called")

    def __enter__(self):
        g = globals()
        g["methodA"] = self.methodA
        g["methodB"] = self.methodB

    def __exit__(self, *args):
        g = globals()
        del g["methodA"]
        del g["methodB"]

foo = Bar()

with foo:
    methodA()  # all works fine
    methodB()

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.