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.)
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. 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.) The challenge was to find the appropriate globlas dictionary into which to inject these variable definitions. My code wound up looking like this: if inspect.ismethod(func): func_globals = func.im_func.func_globals elif inspect.isfunction(func): func_globals = func.func_globals elif inspect.isbuiltin(func): func_globals = sys.modules[func.__module__].__dict__ elif inspect.ismethoddescriptor(func): raise TypeError("Can't get globals of a method descriptor") What if func is actually an instance of a class with a __call__ method? So I added another branch: elif hasattr(func, "__call__"): func = func.__call__ But now what? This required me to to start the process over again. I also needed an else clause. Let's add that first: else: raise TypeError("Don't know how to find globals from %s objects" % type(func)) 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: for _i in (0, 1): if inspect.ismethod(func): func_globals = func.im_func.func_globals elif inspect.isfunction(func): func_globals = func.func_globals elif inspect.isbuiltin(func): func_globals = sys.modules[func.__module__].__dict__ elif inspect.ismethoddescriptor(func): raise TypeError("Can't get globals of a method descriptor") elif hasattr(func, "__call__"): func = func.__call__ # Try again... continue else: raise TypeError("Don't know how to find globals from %s objects" % type(func)) break else: raise TypeError("Don't know how to find globals from %s objects" % type(func)) 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: class C1(object): def __call__(self): print "called" class C2(object): __call__ = C1() If you instantiate C2 and call the instance, it works as you would expect: >>> o = C2() >>> o() called >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? Skip
-- https://mail.python.org/mailman/listinfo/python-list