39

I tried to use the C-function printf() in the Python command line on Linux. To make that work I imported ctypes. If I create an object of CDLL to use the printf()-function in a loop, I get a really weird output:

>>> import ctypes >>> libc = ctypes.CDLL("libc.so.6") >>> for i in range(10): ... libc.printf("%d", i) ... 01 11 21 31 41 51 61 71 81 91 >>> 

However when I call this loop inside a function, it works as expected:

>>> import ctypes >>> libc = ctypes.CDLL("libc.so.6") >>> def pr(): ... for i in range(10): ... libc.printf("%d", i) ... libc.printf("\n") ... >>> pr() 0123456789 >>> 

What causes this behavior? I'm using Python 2.7.6 on Linux.

1
  • 2
    Actually an easier way to suppress output is to just add a semicolon to the end: libc.printf("%d", i); Commented Dec 15, 2016 at 8:07

2 Answers 2

87

Those extra '1's at the end of each number are the return value from printf, which returns the number of chars that it prints. The return value of a function called in the interactive interpreter is automatically printed (unless it's None).

In fact, the interactive interpreter prints any non-None expression that isn't assigned. And of course it adds a newline to those expressions, which explains why the output in your first code block is on separate lines.

Your pr function doesn't have a return statement, so it returns None, and thus no extra stuff gets printed.

Sign up to request clarification or add additional context in comments.

6 Comments

And it doesn't get printed in the function, because the function code isn't interactive anymore?
@Aemyl Basically. You're calling pr in the interactive context, so its return value gets printed by the interpreter, but any functions that pr calls work normally, otherwise the terminal would get filled with unwanted rubbish. :)
@Aemyl No, that's standard on all versions of the standard (CPython) interpreter and on all OSes. There are other Python interpreters / IDEs, but by default they also print the value of non-None expressions when running in interactive mode (AFAIK), although they may also print additional information.
Same thing without the printf call: for i in range(10): 1
Note: ipython (a very common alternative interactive interpreter that wraps the CPython interpreter, as one of a bazillion features) is smarter, and doesn't output the result of unassigned expressions in a block. It only outputs for individual expressions that aren't assigned.
|
5

While PM 2Ring has answered the question quite well, I think it's worth pointing out that printf's behaviour, or something very close, is available as a python built-in, so it's really quite strange that you'd be using the C library version, unless you're using it to learn how to use ctypes, in which case carry on.

But on the other hand, it's strange to want to use ctypes when you haven't used enough python to know how the REPL works... at the risk of sounding arrogant, as someone with 10 years of python experience, I've never actually had to use ctypes yet.

There are two built-in options for string formatting in python:

print("%d" % (i,)) 

which is the old style, and very similar to printf, and

print("{:d}".format(i)) 

which is new to python 3, and is somewhat more powerful. There are questions addressing the differences on this site. Both of the above lines will output identically to libc.printf("%d\n", i). It's also possible to print without the newline.

The CPython implementation of "%" string formatting actually uses sprintf under the hood.

2 Comments

I agree that there's virtually no point in using C's printf in Python, apart from as a learning exercise in using ctypes. I guess the fact that it returns the number of characters printed could be handy, but it'd be saner to just use normal Python string formatting & get the len of the result before printing. FWIW, the format function & method have bee back-ported to Python 2.6 & 2.7. And Python 3 introduces yet another way to format strings: Literal String Interpolation aka f-strings.
FWIW, I haven't used ctypes much, either, but here is a program I wrote that uses it to access the OpenSSL crypto library in order to implement a resumable SHA256 hash function.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.