<div dir="ltr">This is just a pedantic post. It has no real useful application, just something to think about. I apologize that the setup is rather long. The stuff to think about is at the end. (I also apologize for using rich text/html. In this HTML world in which we live nowadays, I'm never certain that mail systems preserve leading whitespace, even in plain text mail.)<div><br></div><div>I have a script which accepts a CSV file as input and the definition of a transform function. It applies the transform function to each row of the CSV file and produces a new CSV file on standard out.<div><br></div><div>One of the things I discovered I needed in certain circumstances was to inject user-defined variables into the system. Since it's a single pass sort of thing (not long-lived), I decided to inject those variables into the function's globals. (I could have added them to builtins, I suppose, but it didn't occur to me when I first wrote the script.)</div><div><br></div><div>The challenge was to find the appropriate globlas dictionary into which to inject these variable definitions. My code wound up looking like this:</div><div><font face="monospace, monospace"><br></font></div><div><div><font face="monospace, monospace">    if inspect.ismethod(func):</font></div><div><font face="monospace, monospace"><span class="" style="white-space:pre">   </span>func_globals = func.im_func.func_globals</font></div><div><font face="monospace, monospace">    elif inspect.isfunction(func):</font></div><div><font face="monospace, monospace"><span class="" style="white-space:pre">  </span>func_globals = func.func_globals</font></div><div><font face="monospace, monospace">    elif inspect.isbuiltin(func):</font></div><div><font face="monospace, monospace"><span class="" style="white-space:pre">   </span>func_globals = sys.modules[func.__module__].__dict__</font></div><div><font face="monospace, monospace">    elif inspect.ismethoddescriptor(func):</font></div><div><font face="monospace, monospace"><span class="" style="white-space:pre">      </span>raise TypeError("Can't get globals of a method descriptor")</font></div></div><div><font face="monospace, monospace"><br></font></div><div>What if func is actually an instance of a class with a __call__ method? So I added another branch:</div><div><font face="monospace, monospace"><br></font></div><div><div><font face="monospace, monospace">    elif hasattr(func, "__call__"):</font></div><div><font face="monospace, monospace"><span class="" style="white-space:pre">      </span>func = func.__call__</font></div></div><div><br></div><div>But now what? This required me to to start the process over again. I also needed an else clause. Let's add that first:</div><div><font face="monospace, monospace"><br></font></div><div><div><font face="monospace, monospace">    else:</font></div><div><font face="monospace, monospace"><span class="" style="white-space:pre">      </span>raise TypeError("Don't know how to find globals from %s objects" % </font><span style="font-family:monospace">type(func))</span></div></div><div><br></div><div>I need to repeat the tests in the case where I found a non-function-like object with a __call__ attribute. I decided to wrap this logic in a for loop which could only run twice:</div><div><br></div><div><div><font face="monospace, monospace">    for _i in (0, 1):</font></div><div><font face="monospace, monospace">        if inspect.ismethod(func):</font></div><div><font face="monospace, monospace">            func_globals = func.im_func.func_globals</font></div><div><font face="monospace, monospace">        elif inspect.isfunction(func):</font></div><div><font face="monospace, monospace">            func_globals = func.func_globals</font></div><div><font face="monospace, monospace">        elif inspect.isbuiltin(func):</font></div><div><font face="monospace, monospace">            func_globals = sys.modules[func.__module__].__dict__</font></div><div><font face="monospace, monospace">        elif inspect.ismethoddescriptor(func):</font></div><div><font face="monospace, monospace">            raise TypeError("Can't get globals of a method descriptor")</font></div><div><font face="monospace, monospace">        elif hasattr(func, "__call__"):</font></div><div><font face="monospace, monospace">            func = func.__call__</font></div><div><font face="monospace, monospace">            # Try again...</font></div><div><font face="monospace, monospace">            continue</font></div><div><font face="monospace, monospace">        else:</font></div><div><font face="monospace, monospace">            raise TypeError("Don't know how to find globals from %s objects" % type(func))</font></div><div><font face="monospace, monospace">        break</font></div><div><font face="monospace, monospace">    else:</font></div><div><font face="monospace, monospace">        raise TypeError("Don't know how to find globals from %s objects" % type(func))</font></div></div><div><br></div><div>I thought about using while True, but thought, "nah, that's never going to happen." Then I wondered if it *could* happen. I constructed a short chain of __call__ attributes which might require the loop to repeat more than twice, but I can't think of a situation where it would actually be useful:</div><div><br></div><div><div><font face="monospace, monospace">    class C1(object):</font></div><div><font face="monospace, monospace">       def __call__(self):</font></div><div><font face="monospace, monospace">           print "called"</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">    class C2(object):</font></div><div><font face="monospace, monospace">       __call__ = C1()<br></font></div></div><div><br></div><div>If you instantiate C2 and call the instance, it works as you would expect:</div><div><br></div><div><div><font face="monospace, monospace">    >>> o = C2()</font></div><div><font face="monospace, monospace">    >>> o()</font></div><div><font face="monospace, monospace">    called</font></div></div><div><br></div><div>From that simple example, it's straightforward to create a chain of classes of any length, thus requiring my for loop to potentially be a while True loop. The question for the esteemed gathering here: have you ever encountered the need for this class-instance-as-a-dunder-call-method before? Perhaps in some sort of code generation situation? Or cleaner functions-with-attributes?</div></div><div><br></div><div>Skip</div><div><br></div></div>