1

In Python, how can I get the containing context of an object (a function, in my case), so I can modify it? For example, if it's a method, its context is the class; if it's a free function, its context is the module.

Related question:
Can a Python decorator of an instance method access the class?

Community
  • 1
  • 1
Paul Manta
  • 30,618
  • 31
  • 128
  • 208
  • 3
    __Wrong__. The context of a class method is __not__ the class. This is not C++. In Python a class method just gets passed the self parameter automatically. The context of a class method is the context of the class itself (the place where the class gets created). – orlp Dec 28 '11 at 11:16
  • @nightcracker Yes, I know, methods get their names mangled and placed in the same scope as the class (essentially becoming free functions). – Paul Manta Dec 28 '11 at 11:22
  • show some meta-code to clarify what you want – Don Question Dec 28 '11 at 11:35
  • @Paul Manta Could you confirm, please, that you want to get the context of an entity from the inside of the concerned entity. Because there may be several levels in the outside, in the case of nested functions for example. – eyquem Dec 28 '11 at 11:59
  • @eyquem That's not what I want. I am given an object (passed by parameter, for example) and I want to access the context in which that object was defined. – Paul Manta Dec 28 '11 at 12:13
  • func(obj) and now you want to access the object or have a magical function which gives you the "context" by which you really mean the "context" enviroment of the caller-function func? so you can introspec which object/method the caller function itself was called and acces those variables/attributes? – Don Question Dec 28 '11 at 12:53
  • @Paul Manta OK, I see. So what do you call "accessing the context" and to do what ? I think you will be interested by the special attributes of functions, explained in the "user-defined function" section here (http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy) – eyquem Dec 28 '11 at 12:53
  • @eyquem By that I mean the a handle to the very first object (eg, module, class, etc) that contains my function. What I'm trying to do is [make a function overload decorator](http://stackoverflow.com/q/8654666/627005). In particular, see my first three [comments on this answer](http://stackoverflow.com/a/8655544/627005) to get an idea of the exact problem I'm trying to solve. – Paul Manta Dec 28 '11 at 13:27
  • @Paul Manta Could you express what is the motivation of your search ? The technical processes involved in your aim are exceeding my knowledge of Python and I can't see beyond to understand the grounding motivation of all that – eyquem Dec 28 '11 at 13:53
  • @eyquem The motivation for what? The overload decorator or the getting of the context? If it's the latter, my intent is not set in stone; I was just exploring all possible solutions to my decorator problem, to see which one is better. Now, it might seem that the solution with modifying the context is not the best one. I'm still interested if it's possible, in case I need it in the future. :) – Paul Manta Dec 28 '11 at 13:57
  • @Paul Manta The motivation of crafting a decorator allowing to overload. By the way, what kind of objects do you want to overload via a decorator ? – eyquem Dec 28 '11 at 14:07
  • @eyquem I want to overload functions of any kind. I don't _need_ this decorator, but there are a few cases where I can't make my functions ignore the types of their arguments, and I don't like having to manually check `isinstance` a few times to determine what code I should execute -- I think it's clearer if each type is handled separately in its own function. – Paul Manta Dec 28 '11 at 14:12
  • @Paul Manta OK, you want to overload functions. I still don't perceive completely the necessity to do so. It seems to me that you try to achieve a complex aim that will allow to avoid simple "manual" task. By the way, by "manually checking", do you mean that you must chck during the execution ? Isn't it possible to write a function with "if" sections determining different processes according to types of arguments passed ? Or do you want to simplify your efforts at the moment you write the functions ? – eyquem Dec 28 '11 at 14:39
  • @eyquem Yes, I want to simplify writing the functions. – Paul Manta Dec 28 '11 at 14:40
  • @Paul Manta Oh! really ? I was hesitating to ask the question because I couldn't believe that you were doing long effort to simplify actions of writing that are done only one time and rapidly for each function. Now I don't see any other reason for you to try to do that than having functions to write frequently every day. In this case, I would personally write a program that would add snippets giving differentiated behaviours to a function according the types of arguments in a script, not trying to include this behaviour programmatically by using the possibilities of Python. – eyquem Dec 28 '11 at 15:03
  • @Paul Manta I'm not sure to be understandable with my poor english. Sorry – eyquem Dec 28 '11 at 15:06
  • @eyquem Consider it a fun project that's going to help me in the future. :) Kinda like the [PEP 354 implementation of Enum](http://pypi.python.org/pypi/enum/) -- it wasn't really necessary, but that robust implementation is really helpful now that it exists. – Paul Manta Dec 28 '11 at 15:10

2 Answers2

1

I think you're going to need to roll your own version, but the standard-library inspect module will get you most of what you need here.

inspect.ismethod() and inspect.isfunction() will help determine if the function is bound (defined in a class) or not, and thus whether you're looking for a class or a module (you hope... cause a function might be defined in another scope than a module... e.g. as a locally defined function within scope of another function or method, or as a lambda (same thing really))

Note in particular that the im_class of a method won't retrieve you the class the method was defined in. But you can (using inspect.getmro()) follow the class hierarchy and find the 'most recent' class that the method was defined in.

BTW - I'm wondering whether modifying a module will be what you want... in many cases the names within that module may already be imported elsewhere...) In particular I'd be worried (for you and your future sanity) if you have ruby metaprogramming experience and are trying to replicate that in python - it's very different and best not to try to do rubyish things in python.

Lesmana
  • 25,663
  • 9
  • 82
  • 87
Tim Diggins
  • 4,364
  • 3
  • 30
  • 49
  • What I'm trying to do is [make a function overload decorator](http://stackoverflow.com/q/8654666/627005). In particular, see my first three [comments on this answer](http://stackoverflow.com/a/8655544/627005) to get an idea of the exact problem I'm trying to solve. – Paul Manta Dec 28 '11 at 13:24
  • Ok, if you're only going to use this stuff within a decorator then it is a very different situation: easier for the unbound function defined within a module (because you should be able to work out the current module easily, and add things to it). But with a method, I believe that when the decorator receives the method, it will not yet be in the context of the class... (the binding to the class happens after the method is defined) so you probably need to do some extra stuff within the metaclass of the class. Have you tested this (by printing out result of instance.is_method) – Tim Diggins Dec 28 '11 at 13:46
0

What you mean are the functions globals() and locals(). They both return a dictionary containing respectively the globals and locals. However, you can't do any metaprogramming with them, because changing them is not allowed.

AFAIK there is no way to get the context of anything but the current (the caller of globals/locals).

orlp
  • 112,504
  • 36
  • 218
  • 315
  • Not allowed ? However it is possible. So why is it possible if it isn't allowed ? – eyquem Dec 28 '11 at 12:01
  • @eyquem: read the documentation on `globals()` and `locals()`. It contains a note that changes to the dicts __may__ not be reflected. So if you rely on it you put yourself on very very thin ice. – orlp Dec 28 '11 at 12:11
  • @eyquem Isn't the whole language designed like this? – Paul Manta Dec 28 '11 at 12:12
  • @nightcracker The note exists only in the description of locals(). It is written _"SHOULD not been modified"_ and _"MAY not affect"_ , it isn't said that it is completely illegal. I think that if someone has a thorough comprehension of the data model, namespaces and execution model of Python, he can dare to make tricky use of the possibility to make changes in globals() and locals(). I admit that I have too hot feet to pretend to do that with full confidence – eyquem Dec 28 '11 at 12:22
  • @eyquem: Well, this goes in the quarter that C defines well as "implementation-specific". You can use it, but relying on it is stupid unless you know for sure what version and what interpreter/compiler your product is going to use. – orlp Dec 28 '11 at 12:26
  • @Paul Manta I tend to answer "rather yes". But, though I have not a lot of examples, there are certainly a lot of strict rules that can't be infringed, otherwise the language wouldn't be a language , it would be an unusable elastic stuff. For example it is not allowed to use unhashable keys for dictionaries, and I found this question expressing an other impossibility: (http://stackoverflow.com/q/2223300/551449) – eyquem Dec 28 '11 at 12:40
  • @nightcracker OK, you probably knows Python better than me. It would be interesting to consider concrete cases on examples. However, I have no time to examine the subject deeperly – eyquem Dec 28 '11 at 12:43