1

My 2.7.5 version of __future__.print_function doesn't allow use of the new argument:

>>> print('hi', end='')
Parsing error SyntaxError: invalid syntax (line 1)

I'll ask about why this is in a separate post if I can't figure that out. For now, I wanted to see what arguments were available in my environment's version of this function.

I looked at this SO post and some related ones, but these do not seem to work when I try:

>>> print.func_code.co_varnames
Parsing error SyntaxError: invalid syntax (line 1)
>>> print_function.func_code.co_varnames
Runtime error 
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AttributeError: _Feature instance has no attribute 'func_code'

I'm guessing that the special nature of __future__ functions is why this standard technique fails.

Is there another way to check what args my version __future__.print_function takes?

Community
  • 1
  • 1
Roland
  • 499
  • 6
  • 16

1 Answers1

3

You are trying to treat a built-in function (implemented in C) as a user-defined function. They are not the same thing. .func_code is only defined for user-defined functions (implemented in Python).

The __future__ module only holds metadata about features, the __future__.print_function object is not the same object as the print() function. Instead, the object tells you more about what version of Python first supported the feature, and in what version the feature becomes mandatory (and the from __future__ import becomes a no-op), as well as a bitfield flag for the compile() function:

>>> import __future__
>>> __future__.print_function
_Feature((2, 6, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0), 65536)
>>> __future__.print_function.optional
(2, 6, 0, 'alpha', 2)
>>> __future__.print_function.mandatory
(3, 0, 0, 'alpha', 0)
>>> __future__.print_function.compiler_flag
65536

In Python 2.7, built-in function objects such as print() simply do not have enough information for you to discover what arguments they support. In Python 3, this is slowly changing as more and more built-in types are given metadata, but the print() function is not yet among them:

>>> import inspect
>>> inspect.signature(print)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mpietre/Development/Library/buildout.python/parts/opt/lib/python3.4/inspect.py", line 2045, in signature
    return _signature_internal(obj)
  File "/Users/mpietre/Development/Library/buildout.python/parts/opt/lib/python3.4/inspect.py", line 1947, in _signature_internal
    skip_bound_arg=skip_bound_arg)
  File "/Users/mpietre/Development/Library/buildout.python/parts/opt/lib/python3.4/inspect.py", line 1884, in _signature_from_builtin
    raise ValueError("no signature found for builtin {!r}".format(func))
ValueError: no signature found for builtin <built-in function print>

I'm not sure where you got the idea from that new is a valid keyword for print() in any Python version however. No version of Python exists that supports that argument.

The only argument that is missing from print() in Python 2 and present in Python 3.3 and up, is the flush argument, see the Python 3 docs for print():

[...] if the flush keyword argument is true, the stream is forcibly flushed.

Changed in version 3.3: Added the flush keyword argument.

The only way to test for that (other than testing with sys.version_info >= (3, 3)) is to try and use it:

from io import StringIO

try:
    print('', end='', flush=False, file=StringIO())
    print_supports_flush = True
except TypeError:
    print_supports_flush = False
Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Great. Thanks for all that background on __future__ functions...I got the "new" argument from this post: http://stackoverflow.com/questions/493386/how-to-print-in-python-without-newline-or-space. Did I misunderstand that? – Roland Nov 06 '14 at 19:52
  • @Roland: I think you did; there is no mention of a `new` argument there, just that the `print()` function is new. – Martijn Pieters Nov 06 '14 at 20:22
  • hmm, I was looking at the 3rd example in CodeLogic's answer. It's talking about Python 3.x (which could be my problem). – Roland Nov 06 '14 at 21:37
  • Yet none of his examples use a `new` argument. His last example does use `flush` which is Python 3.3 and up only. – Martijn Pieters Nov 06 '14 at 21:40
  • what about `print('.', end="")`? It's just before the `flush` example. – Roland Nov 06 '14 at 22:38
  • @Roland: but that's not `new`, that's `end`. Note that I use backticks for *code*, not emphasis. And all versions of the `print()` function (Python 2.6+ and up) support the `end` argument. – Martijn Pieters Nov 06 '14 at 22:43
  • @Roland: your question used `new` as an argument, not as an adjective. – Martijn Pieters Nov 06 '14 at 22:44