2

Apologies in advance for conflating functions and methods, I don't have time at the moment to sort out the terminology but I'm aware of the distinction (generally).

I'm trying to control what functions are run by my script via command-line arguments. After a lot of reading here and elsewhere, I'm moving in the direction of the following example.

# After connecting to a database with MySQLdb and defining a cursor...

cursor.execute(some_query_stored_earlier)
for row in cursor:
    for method_name in processing_methods:    # ('method1','method2', ...)
        globals()[method_name](row)

(Clarification: processing_methods is a tuple of user-defined strings via command-line argument(s) with nargs='*'.)

However, I'm running into problems with print (no surprise there). I would like print to be:

  • among the methods that MIGHT be specified from the command line;
  • the default method when NO methods are specified from the command line;
  • not performed if ONLY OTHER methods are specified from the command line.

Let me acknowledge that I can make things easier on myself by eliminating the first and third criteria and simply doing:

for row in cursor:
    print row
    for method_name in processing_methods:
        globals[method_name](row)

But I really don't want to ALWAYS print every row in what will sometimes be a several-million-rows result. I did a future import, hoping that would solve my problem - no such luck. So I did a little exploring:

>>> from __future__ import print_function
>>> print
<built-in function print>

>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, 'print_function': _Feature((2, 6, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0), 65536), '__package__': None}

>>> a = "Hello, world!"
>>> print(a)
Hello, world!
>>> globals()['print'](a)

Traceback (most recent call last):
  File "<pyshell#33>", line 1, in <module>
    globals()['print'](a)
KeyError: 'print'              # Okay, no problem, obviously it's...

>>> globals()['print_function'](a)

Traceback (most recent call last):
  File "<pyshell#34>", line 1, in <module>
    globals()['print_function'](a)
AttributeError: _Feature instance has no __call__ method    # ...huh.

So then I did a little more reading, and this Q&A prompted some more exploring:

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']
>>> __builtins__
<module '__builtin__' (built-in)>
>>> 'print' in dir(__builtins__)
True                                  # now we're getting somewhere!
>>> __builtins__.print something
SyntaxError: invalid syntax           # fair enough.
>>> __builtins__.print('something')
SyntaxError: invalid syntax           # wait, what?
>>> dir(__builtins__.print)
SyntaxError: invalid syntax           # -_-

Something is going on here that I just don't understand, and this other Q&A hasn't made it any clearer. I think the easy solution to my particular issue is going to be a mildly awkward wrapper like:

def printrows(row):
    print row             # assuming no future import, of course

But it's driving me crazy: Why can't I access print via the globals dictionary? Am I doing it wrong, or is it just something you can't do with built-in functions?

Community
  • 1
  • 1
Air
  • 8,274
  • 2
  • 53
  • 88
  • 1
    What is a `processing_methods`? A white list of global methods? Why wouldn't you convert it into dictionary of 'method_name' -> 'implementation'? This way would be a bit more typing, but you would be able to support a broader range of use cases and keep global scope clean – J0HN Jun 27 '13 at 20:11
  • Something like this: http://ideone.com/qu6u4o – J0HN Jun 27 '13 at 20:17
  • @J0HN `print_function` is wrong, as one OP's snippets shows it is an instance of `__future__._Feature` which is a piece of metadata, not a function. Try it with `method = 'print'` and see it fail. –  Jun 27 '13 at 20:18
  • what exact version of python are you using? as delnan says, `__builtins__.print('something')` works in 2.7.3 on linux. – andrew cooke Jun 28 '13 at 00:06
  • @J0HN: I hadn't thought of that, but I like it. I'll edit the question to clarify `processing_methods`. – Air Jun 28 '13 at 15:27

2 Answers2

2

Did you forget to repeat from __future__ import print_function when you opened a new shell for your second try (where you got all those syntax errors)? It works for me: https://ideone.com/JOBAAk

  • Bingo. I didn't exactly "forget" as I was trying to suss out the behavior without the future import. For some reason I neglected to investigate `__builtins__` again with the future import. – Air Jun 28 '13 at 15:32
2

If you do an otherwise seemingly useless assignment, it works the way I think you expected. I'm not an expert in the internals at work here, so I can't explain WHY this works, but it does.

>>> from __future__ import print_function
>>> row="Hello world"
>>> print = print
>>> globals()['print'](row)
Hello world
brechin
  • 569
  • 4
  • 7
  • Very interesting! It added `'print' : ` to the globals dict. How did you come across this behavior? – Air Jun 28 '13 at 15:19
  • I just played around with the code. Like I said, I can't really claim to know the inner reason why this works. It seemed that there was a print function that would be referenced when called, but the 'print' in the global namespace was still the builtin. The assignment seems to replace the builtin in the global space with the imported function. – brechin Jul 08 '13 at 02:22