标签归档:printing

如何在Python的同一行上打印变量和字符串?

问题:如何在Python的同一行上打印变量和字符串?

我正在使用python算出如果一个孩子每7秒出生一次,那么5年内将有多少个孩子出生。问题出在我的最后一行。当我在文本的任何一侧打印文本时,如何使它工作?

这是我的代码:

currentPop = 312032486
oneYear = 365
hours = 24
minutes = 60
seconds = 60

# seconds in a single day
secondsInDay = hours * minutes * seconds

# seconds in a year
secondsInYear = secondsInDay * oneYear

fiveYears = secondsInYear * 5

#Seconds in 5 years
print fiveYears

# fiveYears in seconds, divided by 7 seconds
births = fiveYears // 7

print "If there was a birth every 7 seconds, there would be: " births "births"

I am using python to work out how many children would be born in 5 years if a child was born every 7 seconds. The problem is on my last line. How do I get a variable to work when I’m printing text either side of it?

Here is my code:

currentPop = 312032486
oneYear = 365
hours = 24
minutes = 60
seconds = 60

# seconds in a single day
secondsInDay = hours * minutes * seconds

# seconds in a year
secondsInYear = secondsInDay * oneYear

fiveYears = secondsInYear * 5

#Seconds in 5 years
print fiveYears

# fiveYears in seconds, divided by 7 seconds
births = fiveYears // 7

print "If there was a birth every 7 seconds, there would be: " births "births"

回答 0

使用,分隔字符串和变量,同时打印:

print "If there was a birth every 7 seconds, there would be: ",births,"births"

, 在print语句中将项目分隔一个空格:

>>> print "foo","bar","spam"
foo bar spam

或更好地使用字符串格式

print "If there was a birth every 7 seconds, there would be: {} births".format(births)

字符串格式化功能强大得多,它还允许您执行其他一些操作,例如:填充,填充,对齐,宽度,设置精度等

>>> print "{:d} {:03d} {:>20f}".format(1,2,1.1)
1 002             1.100000
  ^^^
  0's padded to 2

演示:

>>> births = 4
>>> print "If there was a birth every 7 seconds, there would be: ",births,"births"
If there was a birth every 7 seconds, there would be:  4 births

#formatting
>>> print "If there was a birth every 7 seconds, there would be: {} births".format(births)
If there was a birth every 7 seconds, there would be: 4 births

Use , to separate strings and variables while printing:

print("If there was a birth every 7 seconds, there would be: ", births, "births")

, in print function separates the items by a single space:

>>> print("foo", "bar", "spam")
foo bar spam

or better use string formatting:

print("If there was a birth every 7 seconds, there would be: {} births".format(births))

String formatting is much more powerful and allows you to do some other things as well, like padding, fill, alignment, width, set precision, etc.

>>> print("{:d} {:03d} {:>20f}".format(1, 2, 1.1))
1 002             1.100000
  ^^^
  0's padded to 2

Demo:

>>> births = 4
>>> print("If there was a birth every 7 seconds, there would be: ", births, "births")
If there was a birth every 7 seconds, there would be:  4 births

# formatting
>>> print("If there was a birth every 7 seconds, there would be: {} births".format(births))
If there was a birth every 7 seconds, there would be: 4 births

回答 1

还有两个

第一个

 >>>births = str(5)
 >>>print "there are " + births + " births."
 there are 5 births.

添加字符串时,它们会串联在一起。

第二个

同样format,字符串的(Python 2.6和更高版本)方法可能是标准方法:

>>> births = str(5)
>>>
>>> print "there are {} births.".format(births)
there are 5 births.

format方法也可以与列表一起使用

>>> format_list = ['five','three']
>>> print "there are {} births and {} deaths".format(*format_list) #unpack the list
there are five births and three deaths

或字典

>>> format_dictionary = {'births': 'five', 'deaths': 'three'}
>>> print "there are {births} births, and {deaths} deaths".format(**format_dictionary) #yup, unpack the dictionary
there are five births, and three deaths

Two more

The First one

>>> births = str(5)
>>> print("there are " + births + " births.")
there are 5 births.

When adding strings, they concatenate.

The Second One

Also the format (Python 2.6 and newer) method of strings is probably the standard way:

>>> births = str(5)
>>>
>>> print("there are {} births.".format(births))
there are 5 births.

This format method can be used with lists as well

>>> format_list = ['five', 'three']
>>> # * unpacks the list:
>>> print("there are {} births and {} deaths".format(*format_list))  
there are five births and three deaths

or dictionaries

>>> format_dictionary = {'births': 'five', 'deaths': 'three'}
>>> # ** unpacks the dictionary
>>> print("there are {births} births, and {deaths} deaths".format(**format_dictionary))
there are five births, and three deaths

回答 2

Python是一种非常通用的语言。您可以通过不同的方法打印变量。我列出了以下4种方法。您可以根据需要使用它们。

例:

a=1
b='ball'

方法1:

print('I have %d %s' %(a,b))

方法2:

print('I have',a,b)

方法3:

print('I have {} {}'.format(a,b))

方法4:

print('I have ' + str(a) +' ' +b)

方法5:

  print( f'I have {a} {b}')

输出为:

I have 1 ball

Python is a very versatile language. You may print variables by different methods. I have listed below five methods. You may use them according to your convenience.

Example:

a = 1
b = 'ball'

Method 1:

print('I have %d %s' % (a, b))

Method 2:

print('I have', a, b)

Method 3:

print('I have {} {}'.format(a, b))

Method 4:

print('I have ' + str(a) + ' ' + b)

Method 5:

print(f'I have {a} {b}')

The output would be:

I have 1 ball

回答 3

如果要使用python 3,它非常简单:

print("If there was a birth every 7 second, there would be %d births." % (births))

If you want to work with python 3, it’s very simple:

print("If there was a birth every 7 second, there would be %d births." % (births))

回答 4

从python 3.6开始,您可以使用文字字符串插值。

births = 5.25487
>>> print(f'If there was a birth every 7 seconds, there would be: {births:.2f} births')
If there was a birth every 7 seconds, there would be: 5.25 births

As of python 3.6 you can use Literal String Interpolation.

births = 5.25487
>>> print(f'If there was a birth every 7 seconds, there would be: {births:.2f} births')
If there was a birth every 7 seconds, there would be: 5.25 births

回答 5

您可以使用f-string.format()方法

使用f弦

print(f'If there was a birth every 7 seconds, there would be: {births} births')

使用.format()

print("If there was a birth every 7 seconds, there would be: {births} births".format(births=births))

You can either use the f-string or .format() methods

Using f-string

print(f'If there was a birth every 7 seconds, there would be: {births} births')

Using .format()

print("If there was a birth every 7 seconds, there would be: {births} births".format(births=births))

回答 6

您可以使用格式字符串:

print "There are %d births" % (births,)

或在这种简单情况下:

print "There are ", births, "births"

You can either use a formatstring:

print "There are %d births" % (births,)

or in this simple case:

print "There are ", births, "births"

回答 7

如果您使用的是python 3.6或最新版本,则f-string是最佳和简便的选择

print(f"{your_varaible_name}")

If you are using python 3.6 or latest, f-string is the best and easy one

print(f"{your_varaible_name}")

回答 8

您将首先创建一个变量:例如:D =1。然后执行此操作,但是将字符串替换为所需的任何内容:

D = 1
print("Here is a number!:",D)

You would first make a variable: for example: D = 1. Then Do This but replace the string with whatever you want:

D = 1
print("Here is a number!:",D)

回答 9

在当前的python版本上,您必须使用括号,如下所示:

print ("If there was a birth every 7 seconds", X)

On a current python version you have to use parenthesis, like so :

print ("If there was a birth every 7 seconds", X)

回答 10

使用字符串格式

print("If there was a birth every 7 seconds, there would be: {} births".format(births))
 # Will replace "{}" with births

如果您在进行玩具项目,请使用:

print('If there was a birth every 7 seconds, there would be:' births'births) 

要么

print('If there was a birth every 7 seconds, there would be: %d births' %(births))
# Will replace %d with births

use String formatting

print("If there was a birth every 7 seconds, there would be: {} births".format(births))
 # Will replace "{}" with births

if you doing a toy project use:

print('If there was a birth every 7 seconds, there would be:' births'births) 

or

print('If there was a birth every 7 seconds, there would be: %d births' %(births))
# Will replace %d with births

回答 11

您可以使用字符串格式来执行此操作:

print "If there was a birth every 7 seconds, there would be: %d births" % births

或者您可以提供print多个参数,它将自动用空格分隔它们:

print "If there was a birth every 7 seconds, there would be:", births, "births"

You can use string formatting to do this:

print "If there was a birth every 7 seconds, there would be: %d births" % births

or you can give print multiple arguments, and it will automatically separate them by a space:

print "If there was a birth every 7 seconds, there would be:", births, "births"

回答 12

我将您的脚本复制并粘贴到.py文件中。我使用Python 2.7.10原样运行它,并收到了相同的语法错误。我还在Python 3.5中尝试了该脚本,并收到以下输出:

File "print_strings_on_same_line.py", line 16
print fiveYears
              ^
SyntaxError: Missing parentheses in call to 'print'

然后,我修改了最后一行,其中打印了出生人数,如下所示:

currentPop = 312032486
oneYear = 365
hours = 24
minutes = 60
seconds = 60

# seconds in a single day
secondsInDay = hours * minutes * seconds

# seconds in a year
secondsInYear = secondsInDay * oneYear

fiveYears = secondsInYear * 5

#Seconds in 5 years
print fiveYears

# fiveYears in seconds, divided by 7 seconds
births = fiveYears // 7

print "If there was a birth every 7 seconds, there would be: " + str(births) + " births"

输出为(Python 2.7.10):

157680000
If there was a birth every 7 seconds, there would be: 22525714 births

我希望这有帮助。

I copied and pasted your script into a .py file. I ran it as-is with Python 2.7.10 and received the same syntax error. I also tried the script in Python 3.5 and received the following output:

File "print_strings_on_same_line.py", line 16
print fiveYears
              ^
SyntaxError: Missing parentheses in call to 'print'

Then, I modified the last line where it prints the number of births as follows:

currentPop = 312032486
oneYear = 365
hours = 24
minutes = 60
seconds = 60

# seconds in a single day
secondsInDay = hours * minutes * seconds

# seconds in a year
secondsInYear = secondsInDay * oneYear

fiveYears = secondsInYear * 5

#Seconds in 5 years
print fiveYears

# fiveYears in seconds, divided by 7 seconds
births = fiveYears // 7

print "If there was a birth every 7 seconds, there would be: " + str(births) + " births"

The output was (Python 2.7.10):

157680000
If there was a birth every 7 seconds, there would be: 22525714 births

I hope this helps.


回答 13

只需在之间使用,(逗号)。

请参阅以下代码以获得更好的理解:

# Weight converter pounds to kg

weight_lbs = input("Enter your weight in pounds: ")

weight_kg = 0.45 * int(weight_lbs)

print("You are ", weight_kg, " kg")

Just use , (comma) in between.

See this code for better understanding:

# Weight converter pounds to kg

weight_lbs = input("Enter your weight in pounds: ")

weight_kg = 0.45 * int(weight_lbs)

print("You are ", weight_kg, " kg")

回答 14

稍有不同:使用Python 3并在同一行中打印几个变量:

print("~~Create new DB:",argv[5],"; with user:",argv[3],"; and Password:",argv[4]," ~~")

Slightly different: Using Python 3 and print several variables in the same line:

print("~~Create new DB:",argv[5],"; with user:",argv[3],"; and Password:",argv[4]," ~~")

回答 15

PYTHON 3

最好使用格式选项

user_name=input("Enter your name : )

points = 10

print ("Hello, {} your point is {} : ".format(user_name,points)

或将输入声明为字符串并使用

user_name=str(input("Enter your name : ))

points = 10

print("Hello, "+user_name+" your point is " +str(points))

PYTHON 3

Better to use the format option

user_name=input("Enter your name : )

points = 10

print ("Hello, {} your point is {} : ".format(user_name,points)

or declare the input as string and use

user_name=str(input("Enter your name : ))

points = 10

print("Hello, "+user_name+" your point is " +str(points))

回答 16

如果在字符串和变量之间使用逗号,如下所示:

print "If there was a birth every 7 seconds, there would be: ", births, "births"

If you use a comma inbetween the strings and the variable, like this:

print "If there was a birth every 7 seconds, there would be: ", births, "births"

不带换行符的打印(print’a’,)打印空格,如何删除?

问题:不带换行符的打印(print’a’,)打印空格,如何删除?

我有此代码:

>>> for i in xrange(20):
...     print 'a',
... 
a a a a a a a a a a a a a a a a a a a a

我想输出'a',而' '不像这样:

aaaaaaaaaaaaaaaaaaaa

可能吗?

I have this code:

>>> for i in xrange(20):
...     print 'a',
... 
a a a a a a a a a a a a a a a a a a a a

I want to output 'a', without ' ' like this:

aaaaaaaaaaaaaaaaaaaa

Is it possible?


回答 0

有多种方法可以实现您的结果。如果你只是想为你的情况的解决方案,使用字符串倍增@Ant提到。仅当您的每个print语句都打印相同的字符串时,这才起作用。请注意,它适用于任何长度字符串的乘法(例如,'foo' * 20有效)。

>>> print 'a' * 20
aaaaaaaaaaaaaaaaaaaa

如果通常要这样做,请构建一个字符串,然后将其打印一次。这将为该字符串消耗一些内存,但是仅对进行一次调用print。请注意,+=现在使用的字符串串联使用的大小与您串联的字符串大小成线性关系,因此此操作很快。

>>> for i in xrange(20):
...     s += 'a'
... 
>>> print s
aaaaaaaaaaaaaaaaaaaa

或者,您可以使用sys.stdout更直接地进行操作。write(),这print是一个包装器。这将只写入您提供的原始字符串,而不进行任何格式化。请注意,即使在20 a秒结束时也不会打印换行符。

>>> import sys
>>> for i in xrange(20):
...     sys.stdout.write('a')
... 
aaaaaaaaaaaaaaaaaaaa>>> 

Python 3将print语句更改为print()函数,该函数允许您设置end参数。通过从中导入,可以在> = 2.6中使用它__future__。不过,我会避免在任何严重的2.x代码中使用此方法,因为对于从未使用过3.x的用户来说,这会有些混乱。但是,它应该使您体会3.x带来的一些好处。

>>> from __future__ import print_function
>>> for i in xrange(20):
...     print('a', end='')
... 
aaaaaaaaaaaaaaaaaaaa>>> 

There are a number of ways of achieving your result. If you’re just wanting a solution for your case, use string multiplication as @Ant mentions. This is only going to work if each of your print statements prints the same string. Note that it works for multiplication of any length string (e.g. 'foo' * 20 works).

>>> print 'a' * 20
aaaaaaaaaaaaaaaaaaaa

If you want to do this in general, build up a string and then print it once. This will consume a bit of memory for the string, but only make a single call to print. Note that string concatenation using += is now linear in the size of the string you’re concatenating so this will be fast.

>>> for i in xrange(20):
...     s += 'a'
... 
>>> print s
aaaaaaaaaaaaaaaaaaaa

Or you can do it more directly using sys.stdout.write(), which print is a wrapper around. This will write only the raw string you give it, without any formatting. Note that no newline is printed even at the end of the 20 as.

>>> import sys
>>> for i in xrange(20):
...     sys.stdout.write('a')
... 
aaaaaaaaaaaaaaaaaaaa>>> 

Python 3 changes the print statement into a print() function, which allows you to set an end parameter. You can use it in >=2.6 by importing from __future__. I’d avoid this in any serious 2.x code though, as it will be a little confusing for those who have never used 3.x. However, it should give you a taste of some of the goodness 3.x brings.

>>> from __future__ import print_function
>>> for i in xrange(20):
...     print('a', end='')
... 
aaaaaaaaaaaaaaaaaaaa>>> 

回答 1

PEP 3105:Python 2.6新增功能文档中的作为函数打印

>>> from __future__ import print_function
>>> print('a', end='')

显然,这仅适用于python 3.0或更高版本(或2.6+以from __future__ import print_function开头)。该print语句已删除,并print()在Python 3.0中默认成为函数。

From PEP 3105: print As a Function in the What’s New in Python 2.6 document:

>>> from __future__ import print_function
>>> print('a', end='')

Obviously that only works with python 3.0 or higher (or 2.6+ with a from __future__ import print_function at the beginning). The print statement was removed and became the print() function by default in Python 3.0.


回答 2

您可以通过在print语句之间将空字符串打印到stdout来抑制空格。

>>> import sys
>>> for i in range(20):
...   print 'a',
...   sys.stdout.write('')
... 
aaaaaaaaaaaaaaaaaaaa

但是,更干净的解决方案是首先构建您要打印的整个字符串,然后使用单个print语句将其输出。

You can suppress the space by printing an empty string to stdout between the print statements.

>>> import sys
>>> for i in range(20):
...   print 'a',
...   sys.stdout.write('')
... 
aaaaaaaaaaaaaaaaaaaa

However, a cleaner solution is to first build the entire string you’d like to print and then output it with a single print statement.


回答 3

您可以打印一个退格字符('\b'):

for i in xrange(20):
    print '\ba',

结果:

aaaaaaaaaaaaaaaaaaaa

You could print a backspace character ('\b'):

for i in xrange(20):
    print '\ba',

result:

aaaaaaaaaaaaaaaaaaaa

回答 4

Python 3.x:

for i in range(20):
    print('a', end='')

Python 2.6或2.7:

from __future__ import print_function
for i in xrange(20):
    print('a', end='')

Python 3.x:

for i in range(20):
    print('a', end='')

Python 2.6 or 2.7:

from __future__ import print_function
for i in xrange(20):
    print('a', end='')

回答 5

如果希望他们一次显示一个,则可以执行以下操作:

import time
import sys
for i in range(20):
    sys.stdout.write('a')
    sys.stdout.flush()
    time.sleep(0.5)

sys.stdout.flush() 必须在每次运行循环时强制写入字符。

If you want them to show up one at a time, you can do this:

import time
import sys
for i in range(20):
    sys.stdout.write('a')
    sys.stdout.flush()
    time.sleep(0.5)

sys.stdout.flush() is necessary to force the character to be written each time the loop is run.


回答 6

恰如其分:

打印为O(1),但先构建一个字符串,然后打印为O(n),其中n是字符串中字符的总数。因此,是的,尽管构建字符串是“更干净的”,但这并不是最有效的方法。

我的操作方式如下:

from sys import stdout
printf = stdout.write

现在,您有了一个“打印功能”,可以打印出您给它的任何字符串,而无需每次都返回换行符。

printf("Hello,")
printf("World!")

输出将是:世界,您好!

但是,如果要打印整数,浮点数或其他非字符串值,则必须使用str()函数将它们转换为字符串。

printf(str(2) + " " + str(4))

输出将是:2 4

Just as a side note:

Printing is O(1) but building a string and then printing is O(n), where n is the total number of characters in the string. So yes, while building the string is “cleaner”, it’s not the most efficient method of doing so.

The way I would do it is as follows:

from sys import stdout
printf = stdout.write

Now you have a “print function” that prints out any string you give it without returning the new line character each time.

printf("Hello,")
printf("World!")

The output will be: Hello, World!

However, if you want to print integers, floats, or other non-string values, you’ll have to convert them to a string with the str() function.

printf(str(2) + " " + str(4))

The output will be: 2 4


回答 7

无论是什么蚂蚁 ,或积累成一个字符串,然后打印一次:

s = '';
for i in xrange(20):
    s += 'a'
print s

Either what Ant says, or accumulate into a string, then print once:

s = '';
for i in xrange(20):
    s += 'a'
print s

回答 8

没有什么?你的意思是

>>> print 'a' * 20
aaaaaaaaaaaaaaaaaaaa

without what? do you mean

>>> print 'a' * 20
aaaaaaaaaaaaaaaaaaaa

?


回答 9

这真的很简单

对于python 3+版本,您只需要编写以下代码

for i in range(20):
      print('a',end='')

只需将循环转换为以下代码,您就不必担心其他事情

this is really simple

for python 3+ versions you only have to write the following codes

for i in range(20):
      print('a',end='')

just convert the loop to the following codes, you don’t have to worry about other things


回答 10

哇!!!

这是相当长一段时间

现在,在python 3.x中,这将非常容易

码:

for i in range(20):
      print('a',end='') # here end variable will clarify what you want in 
                        # end of the code

输出:

aaaaaaaaaaaaaaaaaaaa 

有关print()函数的更多信息

print(value1,value2,value3,sep='-',end='\n',file=sys.stdout,flush=False)

在这里

value1,value2,value3

您可以使用逗号打印多个值

sep = '-'

3个值将以’-‘字符分隔

您可以使用任何字符来代替甚至像sep =’@’或sep =’good’这样的字符串

end='\n'

默认情况下,打印功能将’\ n’字符放在输出末尾

但是您可以通过更改最终变量值来使用任何字符或字符串

例如end =’$’或end =’。或end =’Hello’

file=sys.stdout

这是默认值,系统标准输出

使用此参数,您可以创建输出文件流,例如

print("I am a Programmer", file=open("output.txt", "w"))

通过此代码,您将创建一个名为output.txt的文件,其中将存储您作为程序员的输出

flush = False

这是使用flush = True的默认值,您可以强制刷新流

WOW!!!

It’s pretty long time ago

Now, In python 3.x it will be pretty easy

code:

for i in range(20):
      print('a',end='') # here end variable will clarify what you want in 
                        # end of the code

output:

aaaaaaaaaaaaaaaaaaaa 

More about print() function

print(value1,value2,value3,sep='-',end='\n',file=sys.stdout,flush=False)

Here:

value1,value2,value3

you can print multiple values using commas

sep = '-'

3 values will be separated by ‘-‘ character

you can use any character instead of that even string like sep=’@’ or sep=’good’

end='\n'

by default print function put ‘\n’ charater at the end of output

but you can use any character or string by changing end variale value

like end=’$’ or end=’.’ or end=’Hello’

file=sys.stdout

this is a default value, system standard output

using this argument you can create a output file stream like

print("I am a Programmer", file=open("output.txt", "w"))

by this code you will create a file named output.txt where your output I am a Programmer will be stored

flush = False

It’s a default value using flush=True you can forcibly flush the stream


回答 11

就如此容易

def printSleeping():
     sleep = "I'm sleeping"
     v = ""
     for i in sleep:
         v += i
         system('cls')
         print v
         time.sleep(0.02)

as simple as that

def printSleeping():
     sleep = "I'm sleeping"
     v = ""
     for i in sleep:
         v += i
         system('cls')
         print v
         time.sleep(0.02)

Python方式打印列表项

问题:Python方式打印列表项

我想知道是否有比这更好的方法来打印Python列表中的所有对象:

myList = [Person("Foo"), Person("Bar")]
print("\n".join(map(str, myList)))
Foo
Bar

我读这种方式不是很好:

myList = [Person("Foo"), Person("Bar")]
for p in myList:
    print(p)

是否没有类似的东西:

print(p) for p in myList

如果没有,我的问题是…为什么?如果我们可以使用综合列表来完成此类工作,为什么不将其作为列表之外的简单语句呢?

I would like to know if there is a better way to print all objects in a Python list than this :

myList = [Person("Foo"), Person("Bar")]
print("\n".join(map(str, myList)))
Foo
Bar

I read this way is not really good :

myList = [Person("Foo"), Person("Bar")]
for p in myList:
    print(p)

Isn’t there something like :

print(p) for p in myList

If not, my question is… why ? If we can do this kind of stuff with comprehensive lists, why not as a simple statement outside a list ?


回答 0

假设您正在使用Python 3.x:

print(*myList, sep='\n')

您可以使用from __future__ import print_function,在Python 2.x上获得相同的行为,如mgilson在评论中所述。

使用Python 2.x上的print语句,您将需要某种形式的迭代,关于您的print(p) for p in myList不工作问题,您可以使用以下代码做同样的事情,并且仍然是一行:

for p in myList: print p

对于使用的解决方案'\n'.join(),我更喜欢列表推导和生成器,map()因此我可能会使用以下内容:

print '\n'.join(str(p) for p in myList) 

Assuming you are using Python 3.x:

print(*myList, sep='\n')

You can get the same behavior on Python 2.x using from __future__ import print_function, as noted by mgilson in comments.

With the print statement on Python 2.x you will need iteration of some kind, regarding your question about print(p) for p in myList not working, you can just use the following which does the same thing and is still one line:

for p in myList: print p

For a solution that uses '\n'.join(), I prefer list comprehensions and generators over map() so I would probably use the following:

print '\n'.join(str(p) for p in myList) 

回答 1

我经常用这个 :

#!/usr/bin/python

l = [1,2,3,7] 
print "".join([str(x) for x in l])

I use this all the time :

#!/usr/bin/python

l = [1,2,3,7] 
print "".join([str(x) for x in l])

回答 2

[print(a) for a in list] 尽管会打印出所有项目,但最后会给出一堆None类型

[print(a) for a in list] will give a bunch of None types at the end though it prints out all the items


回答 3

对于Python 2. *:

如果为您的Person类重载了函数__str __(),则可以省略带有map(str,…)的部分。另一种方法是创建一个函数,就像您写的那样:

def write_list(lst):
    for item in lst:
        print str(item) 

...

write_list(MyList)

Python 3. * 中有print()函数的参数sep。看一下文档。

For Python 2.*:

If you overload the function __str__() for your Person class, you can omit the part with map(str, …). Another way for this is creating a function, just like you wrote:

def write_list(lst):
    for item in lst:
        print str(item) 

...

write_list(MyList)

There is in Python 3.* the argument sep for the print() function. Take a look at documentation.


回答 4

扩展@lucasg的答案(受其收到的评论启发):

要获得格式化的列表输出,可以按照以下步骤进行操作:

l = [1,2,5]
print ", ".join('%02d'%x for x in l)

01, 02, 05

现在,", "提供分隔符(仅在项目之间,而不是末尾),并且'02d'结合使用%x格式字符串为每个项目提供格式化的字符串x-在这种情况下,格式为具有两位数字的整数,并用零填充。

Expanding @lucasg’s answer (inspired by the comment it received):

To get a formatted list output, you can do something along these lines:

l = [1,2,5]
print ", ".join('%02d'%x for x in l)

01, 02, 05

Now the ", " provides the separator (only between items, not at the end) and the formatting string '02d'combined with %x gives a formatted string for each item x – in this case, formatted as an integer with two digits, left-filled with zeros.


回答 5

要显示每个内容,我使用:

mylist = ['foo', 'bar']
indexval = 0
for i in range(len(mylist)):     
    print(mylist[indexval])
    indexval += 1

在函数中使用的示例:

def showAll(listname, startat):
   indexval = startat
   try:
      for i in range(len(mylist)):
         print(mylist[indexval])
         indexval = indexval + 1
   except IndexError:
      print('That index value you gave is out of range.')

希望我能帮上忙。

To display each content, I use:

mylist = ['foo', 'bar']
indexval = 0
for i in range(len(mylist)):     
    print(mylist[indexval])
    indexval += 1

Example of using in a function:

def showAll(listname, startat):
   indexval = startat
   try:
      for i in range(len(mylist)):
         print(mylist[indexval])
         indexval = indexval + 1
   except IndexError:
      print('That index value you gave is out of range.')

Hope I helped.


回答 6

我认为如果您只想查看列表中的内容,这是最方便的:

myList = ['foo', 'bar']
print('myList is %s' % str(myList))

简单,易读,可与格式字符串一起使用。

I think this is the most convenient if you just want to see the content in the list:

myList = ['foo', 'bar']
print('myList is %s' % str(myList))

Simple, easy to read and can be used together with format string.


回答 7

OP的问题是:是否存在类似以下内容的内容,如果不存在,为什么?

print(p) for p in myList # doesn't work, OP's intuition

答案是,它确实存在,它是:

[p for p in myList] #works perfectly

基本上,[]用于列表理解并print避免避免打印None。看看为什么print打印None看到这个

OP’s question is: does something like following exists, if not then why

print(p) for p in myList # doesn't work, OP's intuition

answer is, it does exist which is:

[p for p in myList] #works perfectly

Basically, use [] for list comprehension and get rid of print to avoiding printing None. To see why print prints None see this


回答 8

我最近制作了一个密码生成器,尽管我对python还是很陌生,但我还是想把它作为一种显示列表中所有项目的方式(进行一些小的修改即可满足您的需要…

    x = 0
    up = 0
    passwordText = ""
    password = []
    userInput = int(input("Enter how many characters you want your password to be: "))
    print("\n\n\n") # spacing

    while x <= (userInput - 1): #loops as many times as the user inputs above
            password.extend([choice(groups.characters)]) #adds random character from groups file that has all lower/uppercase letters and all numbers
            x = x+1 #adds 1 to x w/o using x ++1 as I get many errors w/ that
            passwordText = passwordText + password[up]
            up = up+1 # same as x increase


    print(passwordText)

就像我说的,IM对Python非常新,我相信这对于专家来说是笨拙的方式,但是我在这里只是另一个例子

I recently made a password generator and although I’m VERY NEW to python, I whipped this up as a way to display all items in a list (with small edits to fit your needs…

    x = 0
    up = 0
    passwordText = ""
    password = []
    userInput = int(input("Enter how many characters you want your password to be: "))
    print("\n\n\n") # spacing

    while x <= (userInput - 1): #loops as many times as the user inputs above
            password.extend([choice(groups.characters)]) #adds random character from groups file that has all lower/uppercase letters and all numbers
            x = x+1 #adds 1 to x w/o using x ++1 as I get many errors w/ that
            passwordText = passwordText + password[up]
            up = up+1 # same as x increase


    print(passwordText)

Like I said, IM VERY NEW to Python and I’m sure this is way to clunky for a expert, but I’m just here for another example


回答 9

假设您可以很好地打印列表[1,2,3],那么Python3中的一种简单方法是:

mylist=[1,2,3,'lorem','ipsum','dolor','sit','amet']

print(f"There are {len(mylist):d} items in this lorem list: {str(mylist):s}")

运行此命令将产生以下输出:

此lorem列表中有8个项目:[1、2、3,’lorem’,’ipsum’,’dolor’,’sit’,’amet’]

Assuming you are fine with your list being printed [1,2,3], then an easy way in Python3 is:

mylist=[1,2,3,'lorem','ipsum','dolor','sit','amet']

print(f"There are {len(mylist):d} items in this lorem list: {str(mylist):s}")

Running this produces the following output:

There are 8 items in this lorem list: [1, 2, 3, ‘lorem’, ‘ipsum’, ‘dolor’, ‘sit’, ‘amet’]


漂亮打印熊猫数据框

问题:漂亮打印熊猫数据框

如何将pandas数据框打印为基于文本的漂亮表格,如下所示?

+------------+---------+-------------+
| column_one | col_two |   column_3  |
+------------+---------+-------------+
|          0 |  0.0001 | ABCD        |
|          1 |  1e-005 | ABCD        |
|          2 |  1e-006 | long string |
|          3 |  1e-007 | ABCD        |
+------------+---------+-------------+

How can I print a pandas dataframe as a nice text-based table, like the following?

+------------+---------+-------------+
| column_one | col_two |   column_3  |
+------------+---------+-------------+
|          0 |  0.0001 | ABCD        |
|          1 |  1e-005 | ABCD        |
|          2 |  1e-006 | long string |
|          3 |  1e-007 | ABCD        |
+------------+---------+-------------+

回答 0

我刚刚找到了一个满足这种需求的好工具,它称为tabulate

它打印表格数据并与一起使用DataFrame

from tabulate import tabulate
import pandas as pd

df = pd.DataFrame({'col_two' : [0.0001, 1e-005 , 1e-006, 1e-007],
                   'column_3' : ['ABCD', 'ABCD', 'long string', 'ABCD']})
print(tabulate(df, headers='keys', tablefmt='psql'))

+----+-----------+-------------+
|    |   col_two | column_3    |
|----+-----------+-------------|
|  0 |    0.0001 | ABCD        |
|  1 |    1e-05  | ABCD        |
|  2 |    1e-06  | long string |
|  3 |    1e-07  | ABCD        |
+----+-----------+-------------+

注意:

要取消所有类型数据的行索引,请通过showindex="never"showindex=False

I’ve just found a great tool for that need, it is called tabulate.

It prints tabular data and works with DataFrame.

from tabulate import tabulate
import pandas as pd

df = pd.DataFrame({'col_two' : [0.0001, 1e-005 , 1e-006, 1e-007],
                   'column_3' : ['ABCD', 'ABCD', 'long string', 'ABCD']})
print(tabulate(df, headers='keys', tablefmt='psql'))

+----+-----------+-------------+
|    |   col_two | column_3    |
|----+-----------+-------------|
|  0 |    0.0001 | ABCD        |
|  1 |    1e-05  | ABCD        |
|  2 |    1e-06  | long string |
|  3 |    1e-07  | ABCD        |
+----+-----------+-------------+

Note:

To suppress row indices for all types of data, pass showindex="never" or showindex=False.


回答 1

一种简单的方法是将HTML输出为html,pandas可以直接使用

df.to_html('temp.html')

A simple approach is to output as html, which pandas does out of the box:

df.to_html('temp.html')

回答 2

熊猫> = 1.0

如果您想要一个内置函数将数据转储到某些github markdown中,则现在有了一个。看一下to_markdown

df = pd.DataFrame({"A": [1, 2, 3], "B": [1, 2, 3]}, index=['a', 'a', 'b'])  
print(df.to_markdown()) 

|    |   A |   B |
|:---|----:|----:|
| a  |   1 |   1 |
| a  |   2 |   2 |
| b  |   3 |   3 |

这是在github上的样子:

请注意,您仍然需要tabulate安装该软件包。

pandas >= 1.0

If you want an inbuilt function to dump your data into some github markdown, you now have one. Take a look at to_markdown:

df = pd.DataFrame({"A": [1, 2, 3], "B": [1, 2, 3]}, index=['a', 'a', 'b'])  
print(df.to_markdown()) 

|    |   A |   B |
|:---|----:|----:|
| a  |   1 |   1 |
| a  |   2 |   2 |
| b  |   3 |   3 |

Here’s what that looks like on github:

Note that you will still need to have the tabulate package installed.


回答 3

如果您在Jupyter笔记本中,则可以运行以下代码,以格式正确的表格交互显示数据框。

这个答案建立在上面的to_html(’temp.html’)答案的基础上,但不是直接在笔记本中显示格式正确的表,而是创建文件:

from IPython.display import display, HTML

display(HTML(df.to_html()))

由于以下示例中的代码而获得了此代码的感谢:在iPython Notebook中将DataFrame显示为表

If you are in Jupyter notebook, you could run the following code to interactively display the dataframe in a well formatted table.

This answer builds on the to_html(‘temp.html’) answer above, but instead of creating a file displays the well formatted table directly in the notebook:

from IPython.display import display, HTML

display(HTML(df.to_html()))

Credit for this code due to example at: Show DataFrame as table in iPython Notebook


回答 4

您可以使用prettytable将表呈现为文本。诀窍是将data_frame转换为内存中的csv文件,并让prettytable读取该文件。这是代码:

from StringIO import StringIO
import prettytable    

output = StringIO()
data_frame.to_csv(output)
output.seek(0)
pt = prettytable.from_csv(output)
print pt

You can use prettytable to render the table as text. The trick is to convert the data_frame to an in-memory csv file and have prettytable read it. Here’s the code:

from StringIO import StringIO
import prettytable    

output = StringIO()
data_frame.to_csv(output)
output.seek(0)
pt = prettytable.from_csv(output)
print pt

回答 5

我用了一段时间的答案,发现在大多数情况下都很好。不幸的是,由于熊猫的to_csvprettytable 的from_csv之间不一致,因此我不得不以其他方式使用prettytable。

一种失败的情况是包含逗号的数据框:

pd.DataFrame({'A': [1, 2], 'B': ['a,', 'b']})

Prettytable引发以下形式的错误:

Error: Could not determine delimiter

下面的函数处理这种情况:

def format_for_print(df):    
    table = PrettyTable([''] + list(df.columns))
    for row in df.itertuples():
        table.add_row(row)
    return str(table)

如果您不关心索引,请使用:

def format_for_print2(df):    
    table = PrettyTable(list(df.columns))
    for row in df.itertuples():
        table.add_row(row[1:])
    return str(table)

I used Ofer’s answer for a while and found it great in most cases. Unfortunately, due to inconsistencies between pandas’s to_csv and prettytable‘s from_csv, I had to use prettytable in a different way.

One failure case is a dataframe containing commas:

pd.DataFrame({'A': [1, 2], 'B': ['a,', 'b']})

Prettytable raises an error of the form:

Error: Could not determine delimiter

The following function handles this case:

def format_for_print(df):    
    table = PrettyTable([''] + list(df.columns))
    for row in df.itertuples():
        table.add_row(row)
    return str(table)

If you don’t care about the index, use:

def format_for_print2(df):    
    table = PrettyTable(list(df.columns))
    for row in df.itertuples():
        table.add_row(row[1:])
    return str(table)

回答 6

遵循Mark的回答,如果由于某些原因(例如,您想在控制台上进行快速测试)而不使用Jupyter,则可以使用该DataFrame.to_string方法,该方法至少适用于-Pandas 0.12(2014)起。

import pandas as pd

matrix = [(1, 23, 45), (789, 1, 23), (45, 678, 90)]
df = pd.DataFrame(matrix, columns=list('abc'))
print(df.to_string())

#  outputs:
#       a    b   c
#  0    1   23  45
#  1  789    1  23
#  2   45  678  90

Following up on Mark’s answer, if you’re not using Jupyter for some reason, e.g. you want to do some quick testing on the console, you can use the DataFrame.to_string method, which works from — at least — Pandas 0.12 (2014) onwards.

import pandas as pd

matrix = [(1, 23, 45), (789, 1, 23), (45, 678, 90)]
df = pd.DataFrame(matrix, columns=list('abc'))
print(df.to_string())

#  outputs:
#       a    b   c
#  0    1   23  45
#  1  789    1  23
#  2   45  678  90

回答 7

也许您正在寻找这样的东西:

def tableize(df):
    if not isinstance(df, pd.DataFrame):
        return
    df_columns = df.columns.tolist() 
    max_len_in_lst = lambda lst: len(sorted(lst, reverse=True, key=len)[0])
    align_center = lambda st, sz: "{0}{1}{0}".format(" "*(1+(sz-len(st))//2), st)[:sz] if len(st) < sz else st
    align_right = lambda st, sz: "{0}{1} ".format(" "*(sz-len(st)-1), st) if len(st) < sz else st
    max_col_len = max_len_in_lst(df_columns)
    max_val_len_for_col = dict([(col, max_len_in_lst(df.iloc[:,idx].astype('str'))) for idx, col in enumerate(df_columns)])
    col_sizes = dict([(col, 2 + max(max_val_len_for_col.get(col, 0), max_col_len)) for col in df_columns])
    build_hline = lambda row: '+'.join(['-' * col_sizes[col] for col in row]).join(['+', '+'])
    build_data = lambda row, align: "|".join([align(str(val), col_sizes[df_columns[idx]]) for idx, val in enumerate(row)]).join(['|', '|'])
    hline = build_hline(df_columns)
    out = [hline, build_data(df_columns, align_center), hline]
    for _, row in df.iterrows():
        out.append(build_data(row.tolist(), align_right))
    out.append(hline)
    return "\n".join(out)


df = pd.DataFrame([[1, 2, 3], [11111, 22, 333]], columns=['a', 'b', 'c'])
print tableize(df)
输出:
+ ------- + ---- + ----- +
| 一个| b | c |
+ ------- + ---- + ----- +
| 1 | 2 | 3 |
| 11111 | 22 | 333 |
+ ------- + ---- + ----- +

Maybe you’re looking for something like this:

def tableize(df):
    if not isinstance(df, pd.DataFrame):
        return
    df_columns = df.columns.tolist() 
    max_len_in_lst = lambda lst: len(sorted(lst, reverse=True, key=len)[0])
    align_center = lambda st, sz: "{0}{1}{0}".format(" "*(1+(sz-len(st))//2), st)[:sz] if len(st) < sz else st
    align_right = lambda st, sz: "{0}{1} ".format(" "*(sz-len(st)-1), st) if len(st) < sz else st
    max_col_len = max_len_in_lst(df_columns)
    max_val_len_for_col = dict([(col, max_len_in_lst(df.iloc[:,idx].astype('str'))) for idx, col in enumerate(df_columns)])
    col_sizes = dict([(col, 2 + max(max_val_len_for_col.get(col, 0), max_col_len)) for col in df_columns])
    build_hline = lambda row: '+'.join(['-' * col_sizes[col] for col in row]).join(['+', '+'])
    build_data = lambda row, align: "|".join([align(str(val), col_sizes[df_columns[idx]]) for idx, val in enumerate(row)]).join(['|', '|'])
    hline = build_hline(df_columns)
    out = [hline, build_data(df_columns, align_center), hline]
    for _, row in df.iterrows():
        out.append(build_data(row.tolist(), align_right))
    out.append(hline)
    return "\n".join(out)


df = pd.DataFrame([[1, 2, 3], [11111, 22, 333]], columns=['a', 'b', 'c'])
print tableize(df)
Output:
+-------+----+-----+
|    a  |  b |   c |
+-------+----+-----+
|     1 |  2 |   3 |
| 11111 | 22 | 333 |
+-------+----+-----+

回答 8

我希望将数据框打印出来,但也希望在同一页面上添加一些结果和注释。我已经完成了上述工作,但无法获得想要的东西。我最终使用file.write(df1.to_csv())和file.write(“ ,,, blah ,,,,, blah”)语句在页面上获取我的其他内容。当我打开csv文件时,它直接进入了一个电子表格,该电子表格以正确的速度和格式打印了所有内容。

I wanted a paper printout of a dataframe but I wanted to add some results and comments as well on the same page. I have worked through the above and I could not get what I wanted. I ended up using file.write(df1.to_csv()) and file.write(“,,,blah,,,,,,blah”) statements to get my extras on the page. When I opened the csv file it went straight to a spreadsheet which printed everything in the right pace and format.


在python中,为什么要使用日志记录而不是print?

问题:在python中,为什么要使用日志记录而不是print?

对于复杂项目中的简单调试,是否有理由使用python记录器而不是print?那其他用例呢?是否每个都有一个公认的最佳用例(尤其是在您仅查找标准输出时)?

我一直都听说这是“最佳实践”,但我一直无法弄清原因。

For simple debugging in a complex project is there a reason to use the python logger instead of print? What about other use-cases? Is there an accepted best use-case for each (especially when you’re only looking for stdout)?

I’ve always heard that this is a “best practice” but I haven’t been able to figure out why.


回答 0

日志记录程序包具有许多有用的功能:

  • 易于查看从何处以及何时(即使是哪一行)进行记录调用。
  • 您可以同时登录文件,套接字,几乎所有内容。
  • 您可以根据严重性区分日志记录。

印刷没有这些。

另外,如果您的项目打算由其他python工具导入,则对于您的包来说,将内容打印到stdout是不好的做法,因为用户很可能不知道打印消息的来源。使用日志记录,包的用户可以选择是否要传播您工具中的日志记录消息。

The logging package has a lot of useful features:

  • Easy to see where and when (even what line no.) a logging call is being made from.
  • You can log to files, sockets, pretty much anything, all at the same time.
  • You can differentiate your logging based on severity.

Print doesn’t have any of these.

Also, if your project is meant to be imported by other python tools, it’s bad practice for your package to print things to stdout, since the user likely won’t know where the print messages are coming from. With logging, users of your package can choose whether or not they want to propogate logging messages from your tool or not.


回答 1

正确记录的最大优点之一是您可以对消息进行分类,然后根据需要将其打开或关闭。例如,为项目的某个部分打开调试级别的消息,而为其他部分调低调试级别的消息,这样可能会很有用,以免被信息过载所取代,并轻松地专注于您需要执行的任务记录。

另外,日志是可配置的。您可以轻松地对其进行过滤,将其发送到文件,对其进行格式化,添加时间戳以及在全球范围内可能需要的任何其他事项。打印报表不容易管理。

One of the biggest advantages of proper logging is that you can categorize messages and turn them on or off depending on what you need. For example, it might be useful to turn on debugging level messages for a certain part of the project, but tone it down for other parts, so as not to be taken over by information overload and to easily concentrate on the task for which you need logging.

Also, logs are configurable. You can easily filter them, send them to files, format them, add timestamps, and any other things you might need on a global basis. Print statements are not easily managed.


回答 2

打印语句将在线调试器的负面影响与诊断工具结合在一起,是两全其美的方式。您必须修改程序,但无法从中获得更多有用的代码

在线调试器使您可以检查正在运行的程序的状态。但是真正的调试器的好处是您不必修改源代码。调试会话之前或之后;您只需将程序加载到调试器中,告诉调试器您要查找的位置,便一切就绪。

对应用程序进行检测可能需要先进行一些工作,以某种方式修改源代码,但是生成的诊断输出可能具有大量详细信息,并且可以在非常特定的程度上打开或关闭。python日志记录模块不仅可以显示记录的消息,还可以显示调用该消息的文件和函数,是否有回溯,是否发出了消息的实际时间等等。比那更多的; 诊断仪器永远不需要拆除;当程序完成并投入生产时,它与添加之日一样有效和有用。但是它可以将其输出卡在一个日志文件中,在该文件中它不会惹恼任何人,或者可以将日志级别调低以将所有最紧急的消息拒之门外。

真正比在测试时使用ipython更加容易,并且可以预测调试器的需求或用途,并且熟悉其用于控制​​内置pdb调试器的命令。

当您发现自己认为打印语句可能比使用pdb容易(通常如此)时,您会发现使用记录器比使用并随后删除打印语句更容易使程序处于工作状态。 。

我将编辑器配置为突出显示打印语句为语法错误,并将记录语句突出为注释,因为这就是我如何看待它们。

Print statements are sort of the worst of both worlds, combining the negative aspects of an online debugger with diagnostic instrumentation. You have to modify the program but you don’t get more, useful code from it.

An online debugger allows you to inspect the state of a running program; But the nice thing about a real debugger is that you don’t have to modify the source; neither before nor after the debugging session; You just load the program into the debugger, tell the debugger where you want to look, and you’re all set.

Instrumenting the application might take some work up front, modifying the source code in some way, but the resulting diagnostic output can have enormous amounts of detail, and can be turned on or off to a very specific degree. The python logging module can show not just the message logged, but also the file and function that called it, a traceback if there was one, the actual time that the message was emitted, and so on. More than that; diagnostic instrumentation need never be removed; It’s just as valid and useful when the program is finished and in production as it was the day it was added; but it can have it’s output stuck in a log file where it’s not likely to annoy anyone, or the log level can be turned down to keep all but the most urgent messages out.

anticipating the need or use for a debugger is really no harder than using ipython while you’re testing, and becoming familiar with the commands it uses to control the built in pdb debugger.

When you find yourself thinking that a print statement might be easier than using pdb (as it often is), You’ll find that using a logger pulls your program in a much easier to work on state than if you use and later remove print statements.

I have my editor configured to highlight print statements as syntax errors, and logging statements as comments, since that’s about how I regard them.


回答 3

如果使用日志记录,则负责部署的人员可以配置记录器以将其与自定义信息一起发送到自定义位置。如果仅打印,则仅此而已。

If you use logging then the person responsible for deployment can configure the logger to send it to a custom location, with custom information. If you only print, then that’s all they get.


回答 4

日志记录实质上会创建一个具有其他元数据(时间戳,日志级别,行号,进程等)的可打印输出的可搜索纯文本数据库。

这是纯金,我可以在python脚本运行在日志文件上运行egrep 。我可以调整egrep模式搜索以准确选择我感兴趣的内容,而忽略其余内容。认知负担的减少和以后通过反复试验选择我的egrep模式的自由是我的主要好处。

tail -f mylogfile.log | egrep "key_word1|key_word2"

现在,抛出其他打印无法完成的很棒的事情(发送至套接字,设置调试级别,logrotate,添加元数据等),您有充分的理由偏爱于记录普通打印语句。

我倾向于使用打印语句,因为它既懒惰又容易,添加日志记录需要一些样板代码,嘿,我们有yasnippets(emacs)和ultisnips(vim)以及其他模板工具,所以为什么要放弃对普通打印语句的记录!

Logging essentially creates a searchable plain text database of print outputs with other meta data (timestamp, loglevel, line number, process etc.).

This is pure gold, I can run egrep over the log file after the python script has run. I can tune my egrep pattern search to pick exactly what I am interested in and ignore the rest. This reduction of cognitive load and freedom to pick my egrep pattern later on by trial and error is the key benefit for me.

tail -f mylogfile.log | egrep "key_word1|key_word2"

Now throw in other cool things that print can’t do (sending to socket, setting debug levels, logrotate, adding meta data etc.), you have every reason to prefer logging over plain print statements.

I tend to use print statements because it’s lazy and easy, adding logging needs some boiler plate code, hey we have yasnippets (emacs) and ultisnips (vim) and other templating tools, so why give up logging for plain print statements!?


为什么在Python 2.7中自愿使用印刷括号?

问题:为什么在Python 2.7中自愿使用印刷括号?

在Python 2.7中,以下两者将执行相同的操作

print("Hello, World!") # Prints "Hello, World!"

print "Hello, World!" # Prints "Hello, World!"

但是以下内容不会

print("Hello,", "World!") # Prints the tuple: ("Hello,", "World!")

print "Hello,", "World!" # Prints the words "Hello, World!"

在Python 3.x中,括号print是强制性的,本质上使其成为一个函数,但是在2.7中,两者都可以使用不同的结果。我print在Python 2.7中还应该了解什么?

In Python 2.7 both the following will do the same

print("Hello, World!") # Prints "Hello, World!"

print "Hello, World!" # Prints "Hello, World!"

However the following will not

print("Hello,", "World!") # Prints the tuple: ("Hello,", "World!")

print "Hello,", "World!" # Prints the words "Hello, World!"

In Python 3.x parenthesis on print is mandatory, essentially making it a function, but in 2.7 both will work with differing results. What else should I know about print in Python 2.7?


回答 0

在Python 2.x print中,实际上是一个特殊的语句,而不是一个函数*。

这也是为什么不能像这样使用的原因: lambda x: print x

请注意,(expr)它不会创建元组(结果为expr),但,会创建。在方寸之间这种可能的结果print (x),并print (x, y)在Python 2.7

(1)   # 1 -- no tuple Mister!
(1,)  # (1,)
(1,2) # (1, 2)
1,2   # 1 2 -- no tuple and no parenthesis :) [See below for print caveat.]

但是,由于print是Python 2.x中的特殊语法语句/语法构造,因此,如果没有括号,它将,以特殊方式处理,并且不会创建元组。对print语句的这种特殊处理使它无论是否有尾随都可以采取不同的行动,

快乐的编码。


* printPython 2中的此行为可以更改为Python 3:

from __future__ import print_function

In Python 2.x print is actually a special statement and not a function*.

This is also why it can’t be used like: lambda x: print x

Note that (expr) does not create a Tuple (it results in expr), but , does. This likely results in the confusion between print (x) and print (x, y) in Python 2.7

(1)   # 1 -- no tuple Mister!
(1,)  # (1,)
(1,2) # (1, 2)
1,2   # 1 2 -- no tuple and no parenthesis :) [See below for print caveat.]

However, since print is a special syntax statement/grammar construct in Python 2.x then, without the parenthesis, it treats the ,‘s in a special manner – and does not create a Tuple. This special treatment of the print statement enables it to act differently if there is a trailing , or not.

Happy coding.


*This print behavior in Python 2 can be changed to that of Python 3:

from __future__ import print_function

回答 1

这一切都非常简单,与向前或向后兼容性无关。

print在版本3之前的所有Python版本中,该语句的一般形式为:

print expr1, expr2, ... exprn

(依次对每个表达式求值,将其转换为字符串并在它们之间显示一个空格。)

但是请记住,在表达式周围加上括号仍然是相同的表达式。

因此,您也可以这样写:

print (expr1), (expr2), ... (expr3)

这与调用函数无关。

It’s all very simple and has nothing to do with forward or backward compatibility.

The general form for the print statement in all Python versions before version 3 is:

print expr1, expr2, ... exprn

(Each expression in turn is evaluated, converted to a string and displayed with a space between them.)

But remember that putting parentheses around an expression is still the same expression.

So you can also write this as:

print (expr1), (expr2), ... (expr3)

This has nothing to do with calling a function.


回答 2

在谈到UTF-8时,我们有一个有趣的副作用。

>> greek = dict( dog="σκύλος", cat="γάτα" )
>> print greek['dog'], greek['cat']
σκύλος γάτα
>> print (greek['dog'], greek['cat'])
('\xcf\x83\xce\xba\xcf\x8d\xce\xbb\xce\xbf\xcf\x82', '\xce\xb3\xce\xac\xcf\x84\xce\xb1')

最后打印的是带有十六进制字节值的元组。

Here we have interesting side effect when it comes to UTF-8.

>> greek = dict( dog="σκύλος", cat="γάτα" )
>> print greek['dog'], greek['cat']
σκύλος γάτα
>> print (greek['dog'], greek['cat'])
('\xcf\x83\xce\xba\xcf\x8d\xce\xbb\xce\xbf\xcf\x82', '\xce\xb3\xce\xac\xcf\x84\xce\xb1')

The last print is tuple with hexadecimal byte values.


回答 3

基本上在Python 3之前的Python中,print是一个特殊的语句,如果作为参数获取,则打印所有字符串。因此,print "foo","bar"仅表示“先打印’foo’,再打印’bar’”。这样做的问题是,很容易将print当作一个函数来使用,而Python语法对此却模棱两可,因为它(a,b)是一个包含ab只是foo(a,b)对两个参数的函数的调用的元组。

因此,他们对3进行了不兼容的更改,以减少程序的歧义性和规则性。

(实际上,我认为2.7的行为与2.6的行为相同,但我不确定。)

Basically in Python before Python 3, print was a special statement that printed all the strings if got as arguments. So print "foo","bar" simply meant “print ‘foo’ followed by ‘bar'”. The problem with that was it was tempting to act as if print were a function, and the Python grammar is ambiguous on that, since (a,b) is a tuple containing a and b but foo(a,b) is a call to a function of two arguments.

So they made the incompatible change for 3 to make programs less ambiguous and more regular.

(Actually, I think 2.7 behaves as 2.6 did on this, but I’m not certain.)


为什么打印到标准输出这么慢?可以加快速度吗?

问题:为什么打印到标准输出这么慢?可以加快速度吗?

我一直对使用print语句简单地输出到终端需要多长时间感到惊讶/沮丧。在经历了最近令人痛苦的缓慢日志记录之后,我决定进行调查,并惊讶地发现几乎所有的时间都在等待终端处理结果。

可以以某种方式加快对stdout的写入速度吗?

我编写了一个脚本(print_timer.py此问题底部的’ ‘)来比较将100k行写入stdout,文件以及将stdout重定向到时的时序/dev/null。计时结果如下:

$ python print_timer.py
this is a test
this is a test
<snipped 99997 lines>
this is a test
-----
timing summary (100k lines each)
-----
print                         :11.950 s
write to file (+ fsync)       : 0.122 s
print with stdout = /dev/null : 0.050 s

哇。为了确保python在幕后不做任何事情,例如认识到我将stdout重新分配给/ dev / null之类的东西,我在脚本之外进行了重定向…

$ python print_timer.py > /dev/null
-----
timing summary (100k lines each)
-----
print                         : 0.053 s
write to file (+fsync)        : 0.108 s
print with stdout = /dev/null : 0.045 s

因此,这不是python技巧,而仅仅是终端。我一直都知道将输出转储到/ dev / null会加快速度,但是从来没有想到它是如此重要!

令我惊讶的是tty这么慢。写入物理磁盘比写入“屏幕”(大概是全RAM操作)要快得多,并且实际上与使用/ dev / null转储到垃圾中一样快?

此链接讨论了终端如何阻止I / O,以便它可以“解析[输入],更新其帧缓冲区,与X服务器通信以滚动窗口等等” ……但是我不知道完全了解它。可能要花这么长时间?

我期望没有出路(缺少更快的tty实现?),但是无论如何我都会问。


更新:阅读了一些评论后,我想知道屏幕尺寸实际上对打印时间有多大影响,这确实有一定意义。上面最慢的数字是我的Gnome终端被炸毁为1920×1200。如果我减小很小,我得到…

-----
timing summary (100k lines each)
-----
print                         : 2.920 s
write to file (+fsync)        : 0.121 s
print with stdout = /dev/null : 0.048 s

那当然更好(〜4倍),但不会改变我的问题。这只会增加我的问题,因为我不明白为什么终端屏幕渲染会减慢应用程序向stdout的写入速度。为什么我的程序需要等待屏幕渲染继续?

是否所有创建的终端/ tty应用程序都不相等?我还没有实验。在我看来,终端确实应该能够缓冲所有传入的数据,不可见地进行解析/渲染,并且仅以合理的帧速率渲染在当前屏幕配置中可见的最新块。因此,如果我可以在约0.1秒内将+ fsync写入磁盘,则终端应该能够以该顺序完成相同的操作(在执行此操作时可能需要进行一些屏幕更新)。

我仍然希望可以从应用程序端更改tty设置,以使程序员更好地实现此行为。如果严格来说这是终端应用程序问题,那么这可能甚至不属于StackOverflow吗?

我想念什么?


这是用于生成计时的python程序:

import time, sys, tty
import os

lineCount = 100000
line = "this is a test"
summary = ""

cmd = "print"
startTime_s = time.time()
for x in range(lineCount):
    print line
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

#Add a newline to match line outputs above...
line += "\n"

cmd = "write to file (+fsync)"
fp = file("out.txt", "w")
startTime_s = time.time()
for x in range(lineCount):
    fp.write(line)
os.fsync(fp.fileno())
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

cmd = "print with stdout = /dev/null"
sys.stdout = file(os.devnull, "w")
startTime_s = time.time()
for x in range(lineCount):
    fp.write(line)
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

print >> sys.stderr, "-----"
print >> sys.stderr, "timing summary (100k lines each)"
print >> sys.stderr, "-----"
print >> sys.stderr, summary

I’ve always been amazed/frustrated with how long it takes to simply output to the terminal with a print statement. After some recent painfully slow logging I decided to look into it and was quite surprised to find that almost all the time spent is waiting for the terminal to process the results.

Can writing to stdout be sped up somehow?

I wrote a script (‘print_timer.py‘ at the bottom of this question) to compare timing when writing 100k lines to stdout, to file, and with stdout redirected to /dev/null. Here is the timing result:

$ python print_timer.py
this is a test
this is a test
<snipped 99997 lines>
this is a test
-----
timing summary (100k lines each)
-----
print                         :11.950 s
write to file (+ fsync)       : 0.122 s
print with stdout = /dev/null : 0.050 s

Wow. To make sure python isn’t doing something behind the scenes like recognizing that I reassigned stdout to /dev/null or something, I did the redirection outside the script…

$ python print_timer.py > /dev/null
-----
timing summary (100k lines each)
-----
print                         : 0.053 s
write to file (+fsync)        : 0.108 s
print with stdout = /dev/null : 0.045 s

So it isn’t a python trick, it is just the terminal. I always knew dumping output to /dev/null sped things up, but never figured it was that significant!

It amazes me how slow the tty is. How can it be that writing to physical disk is WAY faster than writing to the “screen” (presumably an all-RAM op), and is effectively as fast as simply dumping to the garbage with /dev/null?

This link talks about how the terminal will block I/O so it can “parse [the input], update its frame buffer, communicate with the X server in order to scroll the window and so on”… but I don’t fully get it. What can be taking so long?

I expect there is no way out (short of a faster tty implementation?) but figure I’d ask anyway.


UPDATE: after reading some comments I wondered how much impact my screen size actually has on the print time, and it does have some significance. The really slow numbers above are with my Gnome terminal blown up to 1920×1200. If I reduce it very small I get…

-----
timing summary (100k lines each)
-----
print                         : 2.920 s
write to file (+fsync)        : 0.121 s
print with stdout = /dev/null : 0.048 s

That is certainly better (~4x), but doesn’t change my question. It only adds to my question as I don’t understand why the terminal screen rendering should slow down an application writing to stdout. Why does my program need to wait for screen rendering to continue?

Are all terminal/tty apps not created equal? I have yet to experiment. It really seems to me like a terminal should be able to buffer all incoming data, parse/render it invisibly, and only render the most recent chunk that is visible in the current screen configuration at a sensible frame rate. So if I can write+fsync to disk in ~0.1 seconds, a terminal should be able to complete the same operation in something of that order (with maybe a few screen updates while it did it).

I’m still kind of hoping there is a tty setting that can be changed from the application side to make this behaviour better for programmer. If this is strictly a terminal application issue, then this maybe doesn’t even belong on StackOverflow?

What am I missing?


Here is the python program used to generate the timing:

import time, sys, tty
import os

lineCount = 100000
line = "this is a test"
summary = ""

cmd = "print"
startTime_s = time.time()
for x in range(lineCount):
    print line
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

#Add a newline to match line outputs above...
line += "\n"

cmd = "write to file (+fsync)"
fp = file("out.txt", "w")
startTime_s = time.time()
for x in range(lineCount):
    fp.write(line)
os.fsync(fp.fileno())
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

cmd = "print with stdout = /dev/null"
sys.stdout = file(os.devnull, "w")
startTime_s = time.time()
for x in range(lineCount):
    fp.write(line)
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

print >> sys.stderr, "-----"
print >> sys.stderr, "timing summary (100k lines each)"
print >> sys.stderr, "-----"
print >> sys.stderr, summary

回答 0

写入物理磁盘比写入“屏幕”(大概是全RAM操作)要快得多,并且实际上与使用/ dev / null转储到垃圾中一样快?

恭喜,您刚刚发现了I / O缓冲的重要性。:-)

磁盘似乎速度更快,因为它具有很高的缓冲能力:write()在将任何内容实际写入物理磁盘之前,所有Python的调用都将返回。(操作系统稍后执行此操作,将成千上万的单个写入合并为一个大而有效的块。)

另一方面,终端几乎不执行缓冲或不进行缓冲:每个人print/ write(line)等待完整的写入(即显示到输出设备)完成。

为了使比较合理,必须使文件测试使用与终端相同的输出缓冲,可以通过将示例修改为以下操作来做到这一点:

fp = file("out.txt", "w", 1)   # line-buffered, like stdout
[...]
for x in range(lineCount):
    fp.write(line)
    os.fsync(fp.fileno())      # wait for the write to actually complete

我在我的机器上运行了文件写入测试,并通过缓冲在100,000行中也进行了0.05s的测试。

但是,通过上述修改以无缓冲方式写入数据,只需要40秒就可以将1,000行写入磁盘。我放弃了等待100,000行的写操作,但是从以前的内容推论得出,这将花费一个多小时

这使航站楼的11秒成为现实,不是吗?

因此,要回答您最初的问题,考虑到所有因素,实际上写信到终端的速度非常快,并且没有太多的空间可以使它更快(但是各个终端的工作量有所不同;请参阅Russ对此的评论)回答)。

(您可以像使用磁盘I / O一样添加更多的写缓冲,但是直到刷新缓冲区之后,您才能看到向终端写入的内容。这是一个折衷方案:交互性与大容量效率。)

How can it be that writing to physical disk is WAY faster than writing to the “screen” (presumably an all-RAM op), and is effectively as fast as simply dumping to the garbage with /dev/null?

Congratulations, you have just discovered the importance of I/O buffering. :-)

The disk appears to be faster, because it is highly buffered: all Python’s write() calls are returning before anything is actually written to physical disk. (The OS does this later, combining many thousands of individual writes into a big, efficient chunks.)

The terminal, on the other hand, does little or no buffering: each individual print / write(line) waits for the full write (i.e. display to output device) to complete.

To make the comparison fair, you must make the file test use the same output buffering as the terminal, which you can do by modifying your example to:

fp = file("out.txt", "w", 1)   # line-buffered, like stdout
[...]
for x in range(lineCount):
    fp.write(line)
    os.fsync(fp.fileno())      # wait for the write to actually complete

I ran your file writing test on my machine, and with buffering, it also 0.05s here for 100,000 lines.

However, with the above modifications to write unbuffered, it takes 40 seconds to write only 1,000 lines to disk. I gave up waiting for 100,000 lines to write, but extrapolating from the previous, it would take over an hour.

That puts the terminal’s 11 seconds into perspective, doesn’t it?

So to answer your original question, writing to a terminal is actually blazingly fast, all things considered, and there’s not a lot of room to make it much faster (but individual terminals do vary in how much work they do; see Russ’s comment to this answer).

(You could add more write buffering, like with disk I/O, but then you wouldn’t see what was written to your terminal until after the buffer gets flushed. It’s a trade-off: interactivity versus bulk efficiency.)


回答 1

感谢所有的评论!我最终在您的帮助下自行回答。不过,回答您自己的问题感觉很脏。

问题1:为什么打印到标准输出速度慢?

答:打印到标准输出并不是天生就慢。您正在使用的终端很慢。它与应用程序端的I / O缓冲(例如python文件缓冲)几乎为零。见下文。

问题2:可以加快速度吗?

答:是的,可以,但是似乎不是从程序方面(将“打印”到stdout的那一侧)进行。为了加快速度,请使用更快的其他终端仿真器。

说明…

我尝试了一个自描述为“轻量级”的终端程序,wterm并获得了明显更好的结果。下面是在wterm同一系统上以1920×1200 运行时,我的测试脚本的输出(位于问题的底部),该系统使用gnome-terminal的基本打印选项花费了12s:

-----
时序摘要(每条10万行)
-----
打印:0.261 s
写入文件(+ fsync):0.110 s
用stdout = / dev / null打印:0.050 s

0.26s比12s好得多!我不知道是否wterm更聪明地按照我的建议进行渲染(以合理的帧频渲染“可见”尾巴),或者是否“做得比”少gnome-terminal。为了我的问题,我得到了答案。 gnome-terminal是慢的。

所以-如果您运行的脚本长时间运行,感觉很慢,并且会向stdout喷出大量文本,请尝试其他终端,看看它是否更好!

请注意,我几乎是wterm从ubuntu / debian存储库中随机提取的。 该链接可能是同一终端,但是我不确定。我没有测试任何其他终端模拟器。


更新:因为必须要抓痒,所以我用相同的脚本和全屏(1920×1200)测试了一堆其他终端模拟器。我的手动收集的统计信息在这里:

wterm 0.3秒
间隔0.3秒
接收0.3秒
mrxvt 0.4s
konsole 0.6秒
药师0.7s
接线柱7s
xterm 9s
gnome终端12s
xfce4端子12s
巴拉终端18s
xvt 48s

记录的时间是手动收集的,但是它们是相当一致的。我记录了最好的(ish)值。YMMV,显然。

另外,它是对其中可用的各种终端仿真器的一次有趣的浏览!我很惊讶我的第一个“替代”测试竟然是同类中最好的。

Thanks for all the comments! I’ve ended up answering it myself with your help. It feels dirty answering your own question, though.

Question 1: Why is printing to stdout slow?

Answer: Printing to stdout is not inherently slow. It is the terminal you work with that is slow. And it has pretty much zero to do with I/O buffering on the application side (eg: python file buffering). See below.

Question 2: Can it be sped up?

Answer: Yes it can, but seemingly not from the program side (the side doing the ‘printing’ to stdout). To speed it up, use a faster different terminal emulator.

Explanation…

I tried a self-described ‘lightweight’ terminal program called wterm and got significantly better results. Below is the output of my test script (at the bottom of the question) when running in wterm at 1920×1200 in on the same system where the basic print option took 12s using gnome-terminal:

-----
timing summary (100k lines each)
-----
print                         : 0.261 s
write to file (+fsync)        : 0.110 s
print with stdout = /dev/null : 0.050 s

0.26s is MUCH better than 12s! I don’t know whether wterm is more intelligent about how it renders to screen along the lines of how I was suggesting (render the ‘visible’ tail at a reasonable frame rate), or whether it just “does less” than gnome-terminal. For the purposes of my question I’ve got the answer, though. gnome-terminal is slow.

So – If you have a long running script that you feel is slow and it spews massive amounts of text to stdout… try a different terminal and see if it is any better!

Note that I pretty much randomly pulled wterm from the ubuntu/debian repositories. This link might be the same terminal, but I’m not sure. I did not test any other terminal emulators.


Update: Because I had to scratch the itch, I tested a whole pile of other terminal emulators with the same script and full screen (1920×1200). My manually collected stats are here:

wterm           0.3s
aterm           0.3s
rxvt            0.3s
mrxvt           0.4s
konsole         0.6s
yakuake         0.7s
lxterminal        7s
xterm             9s
gnome-terminal   12s
xfce4-terminal   12s
vala-terminal    18s
xvt              48s

The recorded times are manually collected, but they were pretty consistent. I recorded the best(ish) value. YMMV, obviously.

As a bonus, it was an interesting tour of some of the various terminal emulators available out there! I’m amazed my first ‘alternate’ test turned out to be the best of the bunch.


回答 2

重定向可能什么也不做,因为程序可以确定其输出FD是否指向tty。

指向终端时,stdout可能是行缓冲的(与C的stdout流行为相同)。

作为一项有趣的实验,请尝试将输出传递到cat


我已经尝试了自己有趣的实验,这是结果。

$ python test.py 2>foo
...
$ cat foo
-----
timing summary (100k lines each)
-----
print                         : 6.040 s
write to file                 : 0.122 s
print with stdout = /dev/null : 0.121 s

$ python test.py 2>foo |cat
...
$ cat foo
-----
timing summary (100k lines each)
-----
print                         : 1.024 s
write to file                 : 0.131 s
print with stdout = /dev/null : 0.122 s

Your redirection probably does nothing as programs can determine whether their output FD points to a tty.

It’s likely that stdout is line buffered when pointing to a terminal (the same as C’s stdout stream behaviour).

As an amusing experiment, try piping the output to cat.


I’ve tried my own amusing experiment, and here are the results.

$ python test.py 2>foo
...
$ cat foo
-----
timing summary (100k lines each)
-----
print                         : 6.040 s
write to file                 : 0.122 s
print with stdout = /dev/null : 0.121 s

$ python test.py 2>foo |cat
...
$ cat foo
-----
timing summary (100k lines each)
-----
print                         : 1.024 s
write to file                 : 0.131 s
print with stdout = /dev/null : 0.122 s

回答 3

我无法谈论技术细节,因为我不知道这些细节,但这并不令我感到惊讶:该终端并非为打印此类数据而设计的。的确,您甚至提供了指向您每次打印某些内容时必须要做的GUI负载的链接!请注意,如果pythonw改为使用调用脚本,则不会花费15秒。这完全是一个GUI问题。重定向stdout到文件以避免这种情况:

import contextlib, io
@contextlib.contextmanager
def redirect_stdout(stream):
    import sys
    sys.stdout = stream
    yield
    sys.stdout = sys.__stdout__

output = io.StringIO
with redirect_stdout(output):
    ...

I can’t talk about the technical details because I don’t know them, but this doesn’t surprise me: the terminal was not designed for printing lots of data like this. Indeed, you even provide a link to a load of GUI stuff that it has to do every time you want to print something! Notice that if you call the script with pythonw instead, it does not take 15 seconds; this is entirely a GUI issue. Redirect stdout to a file to avoid this:

import contextlib, io
@contextlib.contextmanager
def redirect_stdout(stream):
    import sys
    sys.stdout = stream
    yield
    sys.stdout = sys.__stdout__

output = io.StringIO
with redirect_stdout(output):
    ...

回答 4

打印到终端将很慢。不幸的是,如果没有编写新的终端实现,我真的看不到您如何显着加快这一步。

Printing to the terminal is going to be slow. Unfortunately short of writing a new terminal implementation I can’t really see how you’d speed this up significantly.


回答 5

除了输出可能默认为行缓冲模式外,输出到终端还导致您的数据以最大的吞吐量流入终端和串行线,或者是伪终端和单独的处理显示的进程事件循环,从某种字体渲染字符,移动显示位以实现滚动显示。后一种情况可能分布在多个进程(例如telnet服务器/客户端,终端应用程序,X11显示服务器)上,因此也存在上下文切换和延迟问题。

In addition to the output probably defaulting to a line-buffered mode, output to a terminal is also causing your data to flow into a terminal and serial line with a maximum throughput, or a pseudo-terminal and a separate process that is handling a display event loop, rendering characters from some font, moving display bits to implement a scrolling display. The latter scenario is probably spread over multiple processes (e.g. telnet server/client, terminal app, X11 display server) so there are context switching and latency issues too.


如何在Python中逐行打印字典?

问题:如何在Python中逐行打印字典?

这是字典

cars = {'A':{'speed':70,
        'color':2},
        'B':{'speed':60,
        'color':3}}

使用这个 for loop

for keys,values in cars.items():
    print(keys)
    print(values)

它打印以下内容:

B
{'color': 3, 'speed': 60}
A
{'color': 2, 'speed': 70}

但是我希望程序像这样打印它:

B
color : 3
speed : 60
A
color : 2
speed : 70

我刚刚开始学习字典,所以不确定如何执行此操作。

This is the dictionary

cars = {'A':{'speed':70,
        'color':2},
        'B':{'speed':60,
        'color':3}}

Using this for loop

for keys,values in cars.items():
    print(keys)
    print(values)

It prints the following:

B
{'color': 3, 'speed': 60}
A
{'color': 2, 'speed': 70}

But I want the program to print it like this:

B
color : 3
speed : 60
A
color : 2
speed : 70

I just started learning dictionaries so I’m not sure how to do this.


回答 0

for x in cars:
    print (x)
    for y in cars[x]:
        print (y,':',cars[x][y])

输出:

A
color : 2
speed : 70
B
color : 3
speed : 60
for x in cars:
    print (x)
    for y in cars[x]:
        print (y,':',cars[x][y])

output:

A
color : 2
speed : 70
B
color : 3
speed : 60

回答 1

您可以json为此使用模块。dumps此模块中的函数将JSON对象转换为格式正确的字符串,然后可以打印该字符串。

import json

cars = {'A':{'speed':70, 'color':2},
        'B':{'speed':60, 'color':3}}

print(json.dumps(cars, indent = 4))

输出看起来像

{
    “一个”: {
        “颜色”:2
        “速度”:70
    },
    “ B”:{
        “颜色”:3,
        “速度”:60
    }
}

文件还规定了一堆这种方法有用的选项。

You could use the json module for this. The dumps function in this module converts a JSON object into a properly formatted string which you can then print.

import json

cars = {'A':{'speed':70, 'color':2},
        'B':{'speed':60, 'color':3}}

print(json.dumps(cars, indent = 4))

The output looks like

{
    "A": {
        "color": 2,
        "speed": 70
    },
    "B": {
        "color": 3,
        "speed": 60
    }
}

The documentation also specifies a bunch of useful options for this method.


回答 2

处理任意深度嵌套的字典和列表的更通用的解决方案是:

def dumpclean(obj):
    if isinstance(obj, dict):
        for k, v in obj.items():
            if hasattr(v, '__iter__'):
                print k
                dumpclean(v)
            else:
                print '%s : %s' % (k, v)
    elif isinstance(obj, list):
        for v in obj:
            if hasattr(v, '__iter__'):
                dumpclean(v)
            else:
                print v
    else:
        print obj

产生输出:

A
color : 2
speed : 70
B
color : 3
speed : 60

我遇到了类似的需求,并开发了更强大的功能作为自己的练习。我将其包含在此处,以防它可能对另一个有价值。在运行鼻子测试中,我还发现能够在调用中指定输出流很有用,这样可以代替使用sys.stderr。

import sys

def dump(obj, nested_level=0, output=sys.stdout):
    spacing = '   '
    if isinstance(obj, dict):
        print >> output, '%s{' % ((nested_level) * spacing)
        for k, v in obj.items():
            if hasattr(v, '__iter__'):
                print >> output, '%s%s:' % ((nested_level + 1) * spacing, k)
                dump(v, nested_level + 1, output)
            else:
                print >> output, '%s%s: %s' % ((nested_level + 1) * spacing, k, v)
        print >> output, '%s}' % (nested_level * spacing)
    elif isinstance(obj, list):
        print >> output, '%s[' % ((nested_level) * spacing)
        for v in obj:
            if hasattr(v, '__iter__'):
                dump(v, nested_level + 1, output)
            else:
                print >> output, '%s%s' % ((nested_level + 1) * spacing, v)
        print >> output, '%s]' % ((nested_level) * spacing)
    else:
        print >> output, '%s%s' % (nested_level * spacing, obj)

使用此功能,OP的输出如下所示:

{
   A:
   {
      color: 2
      speed: 70
   }
   B:
   {
      color: 3
      speed: 60
   }
}

我个人认为这更有用和更具描述性。

给出以下简单的例子:

{"test": [{1:3}], "test2":[(1,2),(3,4)],"test3": {(1,2):['abc', 'def', 'ghi'],(4,5):'def'}}

OP要求的解决方案将产生以下结果:

test
1 : 3
test3
(1, 2)
abc
def
ghi
(4, 5) : def
test2
(1, 2)
(3, 4)

而“增强型”版本会产生以下结果:

{
   test:
   [
      {
         1: 3
      }
   ]
   test3:
   {
      (1, 2):
      [
         abc
         def
         ghi
      ]
      (4, 5): def
   }
   test2:
   [
      (1, 2)
      (3, 4)
   ]
}

我希望这可以为下一个寻求这种功能的人提供一些价值。

A more generalized solution that handles arbitrarily-deeply nested dicts and lists would be:

def dumpclean(obj):
    if isinstance(obj, dict):
        for k, v in obj.items():
            if hasattr(v, '__iter__'):
                print k
                dumpclean(v)
            else:
                print '%s : %s' % (k, v)
    elif isinstance(obj, list):
        for v in obj:
            if hasattr(v, '__iter__'):
                dumpclean(v)
            else:
                print v
    else:
        print obj

This produces the output:

A
color : 2
speed : 70
B
color : 3
speed : 60

I ran into a similar need and developed a more robust function as an exercise for myself. I’m including it here in case it can be of value to another. In running nosetest, I also found it helpful to be able to specify the output stream in the call so that sys.stderr could be used instead.

import sys

def dump(obj, nested_level=0, output=sys.stdout):
    spacing = '   '
    if isinstance(obj, dict):
        print >> output, '%s{' % ((nested_level) * spacing)
        for k, v in obj.items():
            if hasattr(v, '__iter__'):
                print >> output, '%s%s:' % ((nested_level + 1) * spacing, k)
                dump(v, nested_level + 1, output)
            else:
                print >> output, '%s%s: %s' % ((nested_level + 1) * spacing, k, v)
        print >> output, '%s}' % (nested_level * spacing)
    elif isinstance(obj, list):
        print >> output, '%s[' % ((nested_level) * spacing)
        for v in obj:
            if hasattr(v, '__iter__'):
                dump(v, nested_level + 1, output)
            else:
                print >> output, '%s%s' % ((nested_level + 1) * spacing, v)
        print >> output, '%s]' % ((nested_level) * spacing)
    else:
        print >> output, '%s%s' % (nested_level * spacing, obj)

Using this function, the OP’s output looks like this:

{
   A:
   {
      color: 2
      speed: 70
   }
   B:
   {
      color: 3
      speed: 60
   }
}

which I personally found to be more useful and descriptive.

Given the slightly less-trivial example of:

{"test": [{1:3}], "test2":[(1,2),(3,4)],"test3": {(1,2):['abc', 'def', 'ghi'],(4,5):'def'}}

The OP’s requested solution yields this:

test
1 : 3
test3
(1, 2)
abc
def
ghi
(4, 5) : def
test2
(1, 2)
(3, 4)

whereas the ‘enhanced’ version yields this:

{
   test:
   [
      {
         1: 3
      }
   ]
   test3:
   {
      (1, 2):
      [
         abc
         def
         ghi
      ]
      (4, 5): def
   }
   test2:
   [
      (1, 2)
      (3, 4)
   ]
}

I hope this provides some value to the next person looking for this type of functionality.


回答 3

您具有嵌套结构,因此您也需要格式化嵌套字典:

for key, car in cars.items():
    print(key)
    for attribute, value in car.items():
        print('{} : {}'.format(attribute, value))

打印:

A
color : 2
speed : 70
B
color : 3
speed : 60

You have a nested structure, so you need to format the nested dictionary too:

for key, car in cars.items():
    print(key)
    for attribute, value in car.items():
        print('{} : {}'.format(attribute, value))

This prints:

A
color : 2
speed : 70
B
color : 3
speed : 60

回答 4

pprint.pprint() 是完成这项工作的好工具:

>>> import pprint
>>> cars = {'A':{'speed':70,
...         'color':2},
...         'B':{'speed':60,
...         'color':3}}
>>> pprint.pprint(cars, width=1)
{'A': {'color': 2,
       'speed': 70},
 'B': {'color': 3,
       'speed': 60}}

pprint.pprint() is a good tool for this job:

>>> import pprint
>>> cars = {'A':{'speed':70,
...         'color':2},
...         'B':{'speed':60,
...         'color':3}}
>>> pprint.pprint(cars, width=1)
{'A': {'color': 2,
       'speed': 70},
 'B': {'color': 3,
       'speed': 60}}

回答 5

for car,info in cars.items():
    print(car)
    for key,value in info.items():
        print(key, ":", value)
for car,info in cars.items():
    print(car)
    for key,value in info.items():
        print(key, ":", value)

回答 6

如果您知道树只有两个级别,这将起作用:

for k1 in cars:
    print(k1)
    d = cars[k1]
    for k2 in d
        print(k2, ':', d[k2])

This will work if you know the tree only has two levels:

for k1 in cars:
    print(k1)
    d = cars[k1]
    for k2 in d
        print(k2, ':', d[k2])

回答 7

检查以下一线:

print('\n'.join("%s\n%s" % (key1,('\n'.join("%s : %r" % (key2,val2) for (key2,val2) in val1.items()))) for (key1,val1) in cars.items()))

输出:

A
speed : 70
color : 2
B
speed : 60
color : 3

Check the following one-liner:

print('\n'.join("%s\n%s" % (key1,('\n'.join("%s : %r" % (key2,val2) for (key2,val2) in val1.items()))) for (key1,val1) in cars.items()))

Output:

A
speed : 70
color : 2
B
speed : 60
color : 3

回答 8

我更喜欢以下格式yaml

import yaml
yaml.dump(cars)

输出:

A:
  color: 2
  speed: 70
B:
  color: 3
  speed: 60

I prefer the clean formatting of yaml:

import yaml
yaml.dump(cars)

output:

A:
  color: 2
  speed: 70
B:
  color: 3
  speed: 60

回答 9

###newbie exact answer desired (Python v3):
###=================================
"""
cars = {'A':{'speed':70,
        'color':2},
        'B':{'speed':60,
        'color':3}}
"""

for keys, values in  reversed(sorted(cars.items())):
    print(keys)
    for keys,values in sorted(values.items()):
        print(keys," : ", values)

"""
Output:
B
color  :  3
speed  :  60
A
color  :  2
speed  :  70

##[Finished in 0.073s]
"""
###newbie exact answer desired (Python v3):
###=================================
"""
cars = {'A':{'speed':70,
        'color':2},
        'B':{'speed':60,
        'color':3}}
"""

for keys, values in  reversed(sorted(cars.items())):
    print(keys)
    for keys,values in sorted(values.items()):
        print(keys," : ", values)

"""
Output:
B
color  :  3
speed  :  60
A
color  :  2
speed  :  70

##[Finished in 0.073s]
"""

回答 10

# Declare and Initialize Map
map = {}

map ["New"] = 1
map ["to"] = 1
map ["Python"] = 5
map ["or"] = 2

# Print Statement
for i in map:
  print ("", i, ":", map[i])

#  New : 1
#  to : 1
#  Python : 5
#  or : 2
# Declare and Initialize Map
map = {}

map ["New"] = 1
map ["to"] = 1
map ["Python"] = 5
map ["or"] = 2

# Print Statement
for i in map:
  print ("", i, ":", map[i])

#  New : 1
#  to : 1
#  Python : 5
#  or : 2

回答 11

这是我对问题的解决方案。我认为它的方法类似,但是比其他一些答案要简单一些。它还允许任意数量的子词典,并且似乎适用于任何数据类型(我什至在具有值功能的字典上对其进行了测试):

def pprint(web, level):
    for k,v in web.items():
        if isinstance(v, dict):
            print('\t'*level, f'{k}: ')
            level += 1
            pprint(v, level)
            level -= 1
        else:
            print('\t'*level, k, ": ", v)

Here is my solution to the problem. I think it’s similar in approach, but a little simpler than some of the other answers. It also allows for an arbitrary number of sub-dictionaries and seems to work for any datatype (I even tested it on a dictionary which had functions as values):

def pprint(web, level):
    for k,v in web.items():
        if isinstance(v, dict):
            print('\t'*level, f'{k}: ')
            level += 1
            pprint(v, level)
            level -= 1
        else:
            print('\t'*level, k, ": ", v)

回答 12

修改MrWonderful代码

import sys

def print_dictionary(obj, ident):
    if type(obj) == dict:
        for k, v in obj.items():
            sys.stdout.write(ident)
            if hasattr(v, '__iter__'):
                print k
                print_dictionary(v, ident + '  ')
            else:
                print '%s : %s' % (k, v)
    elif type(obj) == list:
        for v in obj:
            sys.stdout.write(ident)
            if hasattr(v, '__iter__'):
                print_dictionary(v, ident + '  ')
            else:
                print v
    else:
        print obj

Modifying MrWonderful code

import sys

def print_dictionary(obj, ident):
    if type(obj) == dict:
        for k, v in obj.items():
            sys.stdout.write(ident)
            if hasattr(v, '__iter__'):
                print k
                print_dictionary(v, ident + '  ')
            else:
                print '%s : %s' % (k, v)
    elif type(obj) == list:
        for v in obj:
            sys.stdout.write(ident)
            if hasattr(v, '__iter__'):
                print_dictionary(v, ident + '  ')
            else:
                print v
    else:
        print obj

为什么在lambda中无法打印?

问题:为什么在lambda中无法打印?

为什么不起作用?

lambda: print "x"

这不是一个单一的陈述,还是其他?该文档对于lambda允许的内容似乎有点稀疏…

Why doesn’t this work?

lambda: print "x"

Is this not a single statement, or is it something else? The documentation seems a little sparse on what is allowed in a lambda…


回答 0

一个lambda人的身体必须是一个单一的表情。在Python 2.x中,print是一条语句。但是,在Python 3中,print函数(而函数应用程序是表达式,因此它将在lambda中工作)。如果您使用的是最新的Python 2.x,则可以(并且应该,为了向前兼容:)使用向后打印功能:

In [1324]: from __future__ import print_function

In [1325]: f = lambda x: print(x)

In [1326]: f("HI")
HI

A lambda‘s body has to be a single expression. In Python 2.x, print is a statement. However, in Python 3, print is a function (and a function application is an expression, so it will work in a lambda). You can (and should, for forward compatibility :) use the back-ported print function if you are using the latest Python 2.x:

In [1324]: from __future__ import print_function

In [1325]: f = lambda x: print(x)

In [1326]: f("HI")
HI

回答 1

在我将其用于简单存根的​​情况下,请使用以下方法:

fn = lambda x: sys.stdout.write(str(x) + "\n")

完美地运作。

In cases where I am using this for simple stubbing out I use this:

fn = lambda x: sys.stdout.write(str(x) + "\n")

which works perfectly.


回答 2

你写的等同于

def anon():
    return print "x"

这也会导致SyntaxError,python不允许您分配要在2.xx中打印的值;在python3中,你可以说

lambda: print('hi')

这样做是可行的,因为他们将print更改为函数而不是语句。

what you’ve written is equivalent to

def anon():
    return print "x"

which also results in a SyntaxError, python doesn’t let you assign a value to print in 2.xx; in python3 you could say

lambda: print('hi')

and it would work because they’ve changed print to be a function instead of a statement.


回答 3

Lambda的主体必须是一个返回值的表达式。 print作为语句,不会返回任何东西,甚至也不返回None。同样,您不能将的结果分配给print变量:

>>> x = print "hello"
  File "<stdin>", line 1
    x = print "hello"
            ^
SyntaxError: invalid syntax

您也不能将变量赋值放在lambda中,因为赋值是语句:

>>> lambda y: (x = y)
  File "<stdin>", line 1
    lambda y: (x = y)
                 ^
SyntaxError: invalid syntax

The body of a lambda has to be an expression that returns a value. print, being a statement, doesn’t return anything, not even None. Similarly, you can’t assign the result of print to a variable:

>>> x = print "hello"
  File "<stdin>", line 1
    x = print "hello"
            ^
SyntaxError: invalid syntax

You also can’t put a variable assignment in a lambda, since assignments are statements:

>>> lambda y: (x = y)
  File "<stdin>", line 1
    lambda y: (x = y)
                 ^
SyntaxError: invalid syntax

回答 4

你可以做这样的事情。

创建一个函数以将打印语句转换为函数:

def printf(text):
   print text

并打印:

lambda: printf("Testing")

You can do something like this.

Create a function to transform print statement into a function:

def printf(text):
   print text

And print it:

lambda: printf("Testing")

回答 5

使用Python 3.x,打印可以在lambda中工作,而无需更改lambda的语义。

以特殊的方式使用,这对于调试非常方便。我发布此“最新答案”,因为这是我经常使用的实用技巧。

假设您的“非工具化” lambda为:

lambda: 4

然后,您的“工具化” lambda为:

lambda: (print (3), 4) [1]

With Python 3.x, print CAN work in a lambda, without changing the semantics of the lambda.

Used in a special way this is very handy for debugging. I post this ‘late answer’, because it’s a practical trick that I often use.

Suppose your ‘uninstrumented’ lambda is:

lambda: 4

Then your ‘instrumented’ lambda is:

lambda: (print (3), 4) [1]

回答 6

Lambda的主体必须是单个表达式print是一个声明,很遗憾,它已经退出了。

The body of a lambda has to be a single expression. print is a statement, so it’s out, unfortunately.


回答 7

在这里,您会看到问题的答案。 print它说不是在Python中表达。

Here, you see an answer for your question. print is not expression in Python, it says.


是否可以“破解” Python的打印功能?

问题:是否可以“破解” Python的打印功能?

注意:此问题仅供参考。我很想知道这样做有多深入到Python内部。

不久之前,在某个问题的内部开始了一个讨论,该问题是关于传递给print语句的字符串是否可以在调用to之后/期间进行修改print。例如,考虑以下功能:

def print_something():
    print('This cat was scared.')

现在,当print运行时,到终端的输出应显示:

This dog was scared.

请注意,单词“ cat”已被单词“ dog”代替。某处某种方式能够修改那些内部缓冲区以更改打印的内容。假设这样做是在未经原始代码作者明确许可的情况下进行的(因此,被黑客/劫持)。

这个评论从智者@abarnert,尤其让我思考:

有两种方法可以做到这一点,但是它们都很丑陋,绝不应该这样做。最丑陋的方法是code用一个带有不同co_consts 列表的对象替换 函数内部的对象。接下来可能是进入C API以访问str的内部缓冲区。[…]

因此,看起来这实际上是可能的。

这是我解决此问题的幼稚方法:

>>> import inspect
>>> exec(inspect.getsource(print_something).replace('cat', 'dog'))
>>> print_something()
This dog was scared.

当然,这exec很糟糕,但这并不能真正回答问题,因为 print调用when / after之后,它实际上并未进行任何修改。

正如@abarnert解释的那样,它将如何进行?

Note: This question is for informational purposes only. I am interested to see how deep into Python’s internals it is possible to go with this.

Not very long ago, a discussion began inside a certain question regarding whether the strings passed to print statements could be modified after/during the call to print has been made. For example, consider the function:

def print_something():
    print('This cat was scared.')

Now, when print is run, then the output to the terminal should display:

This dog was scared.

Notice the word “cat” has been replaced by the word “dog”. Something somewhere somehow was able to modify those internal buffers to change what was printed. Assume this is done without the original code author’s explicit permission (hence, hacking/hijacking).

This comment from the wise @abarnert, in particular, got me thinking:

There are a couple of ways to do that, but they’re all very ugly, and should never be done. The least ugly way is to probably replace the code object inside the function with one with a different co_consts list. Next is probably reaching into the C API to access the str’s internal buffer. […]

So, it looks like this is actually possible.

Here’s my naive way of approaching this problem:

>>> import inspect
>>> exec(inspect.getsource(print_something).replace('cat', 'dog'))
>>> print_something()
This dog was scared.

Of course, exec is bad, but that doesn’t really answer the question, because it does not actually modify anything during when/after print is called.

How would it be done as @abarnert has explained it?


回答 0

首先,实际上没有那么多hacky方式。我们要做的就是更改print打印内容,对吗?

_print = print
def print(*args, **kw):
    args = (arg.replace('cat', 'dog') if isinstance(arg, str) else arg
            for arg in args)
    _print(*args, **kw)

或者,类似地,您可以选择Monkey补丁sys.stdout而不是print


同样,这个exec … getsource …想法也没有错。好吧,这当然有很多问题,但是比这里的要少…


但是,如果您确实想修改函数对象的代码常量,则可以这样做。

如果您真的想真正使用代码对象,则应该使用bytecode(完成时)或byteplay(直到那时,或者对于较旧的Python版本)之类的库,而不是手动执行。即使对于这种琐碎的事情,CodeType初始化器还是很痛苦的。如果您确实需要做一些固定的工作lnotab,那么只有疯子才会手动进行。

另外,不用说,并非所有的Python实现都使用CPython风格的代码对象。这段代码可以在CPython 3.7中使用,并且可能所有版本都可以回溯到至少2.2,但需要进行一些细微的更改(不是代码黑客的东西,而是生成器表达式之类的东西),但是不适用于任何版本的IronPython。

import types

def print_function():
    print ("This cat was scared.")

def main():
    # A function object is a wrapper around a code object, with
    # a bit of extra stuff like default values and closure cells.
    # See inspect module docs for more details.
    co = print_function.__code__
    # A code object is a wrapper around a string of bytecode, with a
    # whole bunch of extra stuff, including a list of constants used
    # by that bytecode. Again see inspect module docs. Anyway, inside
    # the bytecode for string (which you can read by typing
    # dis.dis(string) in your REPL), there's going to be an
    # instruction like LOAD_CONST 1 to load the string literal onto
    # the stack to pass to the print function, and that works by just
    # reading co.co_consts[1]. So, that's what we want to change.
    consts = tuple(c.replace("cat", "dog") if isinstance(c, str) else c
                   for c in co.co_consts)
    # Unfortunately, code objects are immutable, so we have to create
    # a new one, copying over everything except for co_consts, which
    # we'll replace. And the initializer has a zillion parameters.
    # Try help(types.CodeType) at the REPL to see the whole list.
    co = types.CodeType(
        co.co_argcount, co.co_kwonlyargcount, co.co_nlocals,
        co.co_stacksize, co.co_flags, co.co_code,
        consts, co.co_names, co.co_varnames, co.co_filename,
        co.co_name, co.co_firstlineno, co.co_lnotab,
        co.co_freevars, co.co_cellvars)
    print_function.__code__ = co
    print_function()

main()

入侵代码对象可能会出什么问题?大多数情况下,segfaults RuntimeError会耗尽整个堆栈,更正常RuntimeError的segfault 会被处理,或者垃圾值可能只会引发a TypeErrorAttributeError当您尝试使用它们时。例如,尝试创建一个代码对象,该对象只带有一个RETURN_VALUE在堆栈上没有任何内容的字节码b'S\0'(3.6以上的字节码,b'S'之前),或者一个空元组(表示字节码中是否co_consts有a LOAD_CONST 0,或者varnames减1,因此最高的字节LOAD_FAST实际上加载了一个freevar) / cellvar单元格。为了获得一些真正的乐趣,如果您lnotab弄错了太多,那么只有在调试器中运行代码时,您的代码才会出现段错误。

使用bytecodebyteplay不会保护您免受所有这些问题的影响,但是它们确实具有一些基本的健全性检查,并且好的助手可以让您执行诸如插入代码块之类的事情,并使其担心更新所有偏移量和标签,以便您能够弄错了,等等。(此外,它们使您不必键入该可笑的6行构造函数,也不必调试由此产生的愚蠢的错字。)


现在进入第二。

我提到代码对象是不可变的。当然,const是一个元组,因此我们不能直接更改它。const元组中的东西是一个字符串,我们也不能直接更改它。这就是为什么我必须构建一个新的字符串来构建一个新的元组来构建一个新的代码对象的原因。

但是,如果您可以直接更改字符串怎么办?

好吧,在足够深入的内容下,所有内容都只是指向某些C数据的指针,对吗?如果您使用的是CPython,则有一个C API可以访问对象,并且可以使用ctypes它从Python本身内部访问该API,这是一个很糟糕的想法,他们将它们放在pythonapistdlib的ctypes模块中。:)您需要了解的最重要的技巧id(x)是实际指向x内存的指针(作为int)。

不幸的是,用于字符串的C API不能让我们安全地获取已经冻结的字符串的内部存储。因此,请放心,我们只需要阅读头文件并自己找到该存储即可。

如果您使用的是CPython 3.4-3.7(旧版本有所不同,谁知道未来),那么将使用紧凑ASCII格式存储由纯ASCII组成的模块中的字符串文字。提早结束,并且ASCII字节的缓冲区立即在内存中。如果您在字符串或某些非文字字符串中输入非ASCII字符,这将中断(可能在段错误中),但是您可以阅读其他4种方式来访问不同类型字符串的缓冲区。

为了使事情变得简单一些,我在superhackyinternalsGitHub上使用了该项目。(这是有意不可pip安装的,因为您真的不应该使用它,除非尝试在本地构建解释器等。)

import ctypes
import internals # https://github.com/abarnert/superhackyinternals/blob/master/internals.py

def print_function():
    print ("This cat was scared.")

def main():
    for c in print_function.__code__.co_consts:
        if isinstance(c, str):
            idx = c.find('cat')
            if idx != -1:
                # Too much to explain here; just guess and learn to
                # love the segfaults...
                p = internals.PyUnicodeObject.from_address(id(c))
                assert p.compact and p.ascii
                addr = id(c) + internals.PyUnicodeObject.utf8_length.offset
                buf = (ctypes.c_int8 * 3).from_address(addr + idx)
                buf[:3] = b'dog'

    print_function()

main()

如果您想玩这些东西,int则比起隐藏起来要简单得多str。而且,通过更改2to 的值来猜测可以破坏什么,容易得多1,对吗?实际上,忘记想象,让我们开始吧(superhackyinternals再次使用类型):

>>> n = 2
>>> pn = PyLongObject.from_address(id(n))
>>> pn.ob_digit[0]
2
>>> pn.ob_digit[0] = 1
>>> 2
1
>>> n * 3
3
>>> i = 10
>>> while i < 40:
...     i *= 2
...     print(i)
10
10
10

…假设代码框具有无限长的滚动条。

我在IPython中尝试过同样的事情,并且第一次尝试2在提示符下进行评估,它陷入了某种不间断的无限循环。大概2是在REPL循环中将数字用于某物,而股票解释器不是吗?

First, there’s actually a much less hacky way. All we want to do is change what print prints, right?

_print = print
def print(*args, **kw):
    args = (arg.replace('cat', 'dog') if isinstance(arg, str) else arg
            for arg in args)
    _print(*args, **kw)

Or, similarly, you can monkeypatch sys.stdout instead of print.


Also, nothing wrong with the exec … getsource … idea. Well, of course there’s plenty wrong with it, but less than what follows here…


But if you do want to modify the function object’s code constants, we can do that.

If you really want to play around with code objects for real, you should use a library like bytecode (when it’s finished) or byteplay (until then, or for older Python versions) instead of doing it manually. Even for something this trivial, the CodeType initializer is a pain; if you actually need to do stuff like fixing up lnotab, only a lunatic would do that manually.

Also, it goes without saying that not all Python implementations use CPython-style code objects. This code will work in CPython 3.7, and probably all versions back to at least 2.2 with a few minor changes (and not the code-hacking stuff, but things like generator expressions), but it won’t work with any version of IronPython.

import types

def print_function():
    print ("This cat was scared.")

def main():
    # A function object is a wrapper around a code object, with
    # a bit of extra stuff like default values and closure cells.
    # See inspect module docs for more details.
    co = print_function.__code__
    # A code object is a wrapper around a string of bytecode, with a
    # whole bunch of extra stuff, including a list of constants used
    # by that bytecode. Again see inspect module docs. Anyway, inside
    # the bytecode for string (which you can read by typing
    # dis.dis(string) in your REPL), there's going to be an
    # instruction like LOAD_CONST 1 to load the string literal onto
    # the stack to pass to the print function, and that works by just
    # reading co.co_consts[1]. So, that's what we want to change.
    consts = tuple(c.replace("cat", "dog") if isinstance(c, str) else c
                   for c in co.co_consts)
    # Unfortunately, code objects are immutable, so we have to create
    # a new one, copying over everything except for co_consts, which
    # we'll replace. And the initializer has a zillion parameters.
    # Try help(types.CodeType) at the REPL to see the whole list.
    co = types.CodeType(
        co.co_argcount, co.co_kwonlyargcount, co.co_nlocals,
        co.co_stacksize, co.co_flags, co.co_code,
        consts, co.co_names, co.co_varnames, co.co_filename,
        co.co_name, co.co_firstlineno, co.co_lnotab,
        co.co_freevars, co.co_cellvars)
    print_function.__code__ = co
    print_function()

main()

What could go wrong with hacking up code objects? Mostly just segfaults, RuntimeErrors that eat up the whole stack, more normal RuntimeErrors that can be handled, or garbage values that will probably just raise a TypeError or AttributeError when you try to use them. For examples, try creating a code object with just a RETURN_VALUE with nothing on the stack (bytecode b'S\0' for 3.6+, b'S' before), or with an empty tuple for co_consts when there’s a LOAD_CONST 0 in the bytecode, or with varnames decremented by 1 so the highest LOAD_FAST actually loads a freevar/cellvar cell. For some real fun, if you get the lnotab wrong enough, your code will only segfault when run in the debugger.

Using bytecode or byteplay won’t protect you from all of those problems, but they do have some basic sanity checks, and nice helpers that let you do things like insert a chunk of code and let it worry about updating all offsets and labels so you can’t get it wrong, and so on. (Plus, they keep you from having to type in that ridiculous 6-line constructor, and having to debug the silly typos that come from doing so.)


Now on to #2.

I mentioned that code objects are immutable. And of course the consts are a tuple, so we can’t change that directly. And the thing in the const tuple is a string, which we also can’t change directly. That’s why I had to build a new string to build a new tuple to build a new code object.

But what if you could change a string directly?

Well, deep enough under the covers, everything is just a pointer to some C data, right? If you’re using CPython, there’s a C API to access the objects, and you can use ctypes to access that API from within Python itself, which is such a terrible idea that they put a pythonapi right there in the stdlib’s ctypes module. :) The most important trick you need to know is that id(x) is the actual pointer to x in memory (as an int).

Unfortunately, the C API for strings won’t let us safely get at the internal storage of an already-frozen string. So screw safely, let’s just read the header files and find that storage ourselves.

If you’re using CPython 3.4 – 3.7 (it’s different for older versions, and who knows for the future), a string literal from a module that’s made of pure ASCII is going to be stored using the compact ASCII format, which means the struct ends early and the buffer of ASCII bytes follows immediately in memory. This will break (as in probably segfault) if you put a non-ASCII character in the string, or certain kinds of non-literal strings, but you can read up on the other 4 ways to access the buffer for different kinds of strings.

To make things slightly easier, I’m using the superhackyinternals project off my GitHub. (It’s intentionally not pip-installable because you really shouldn’t be using this except to experiment with your local build of the interpreter and the like.)

import ctypes
import internals # https://github.com/abarnert/superhackyinternals/blob/master/internals.py

def print_function():
    print ("This cat was scared.")

def main():
    for c in print_function.__code__.co_consts:
        if isinstance(c, str):
            idx = c.find('cat')
            if idx != -1:
                # Too much to explain here; just guess and learn to
                # love the segfaults...
                p = internals.PyUnicodeObject.from_address(id(c))
                assert p.compact and p.ascii
                addr = id(c) + internals.PyUnicodeObject.utf8_length.offset
                buf = (ctypes.c_int8 * 3).from_address(addr + idx)
                buf[:3] = b'dog'

    print_function()

main()

If you want to play with this stuff, int is a whole lot simpler under the covers than str. And it’s a lot easier to guess what you can break by changing the value of 2 to 1, right? Actually, forget imagining, let’s just do it (using the types from superhackyinternals again):

>>> n = 2
>>> pn = PyLongObject.from_address(id(n))
>>> pn.ob_digit[0]
2
>>> pn.ob_digit[0] = 1
>>> 2
1
>>> n * 3
3
>>> i = 10
>>> while i < 40:
...     i *= 2
...     print(i)
10
10
10

… pretend that code box has an infinite-length scrollbar.

I tried the same thing in IPython, and the first time I tried to evaluate 2 at the prompt, it went into some kind of uninterruptable infinite loop. Presumably it’s using the number 2 for something in its REPL loop, while the stock interpreter isn’t?


回答 1

Monkey补丁 print

print是一个内置函数,因此它将使用模块(或Python 2)中print定义的函数。因此,无论何时要修改或更改内置函数的行为,都可以在该模块中简单地重新分配名称。builtins__builtin__

此过程称为monkey-patching

# Store the real print function in another variable otherwise
# it will be inaccessible after being modified.
_print = print  

# Actual implementation of the new print
def custom_print(*args, **options):
    _print('custom print called')
    _print(*args, **options)

# Change the print function globally
import builtins
builtins.print = custom_print

之后,即使是在外部模块中,每个print调用也都将通过。custom_printprint

但是,您实际上并不想打印其他文本,而是要更改打印的文本。一种解决方法是将其替换为要打印的字符串:

_print = print  

def custom_print(*args, **options):
    # Get the desired seperator or the default whitspace
    sep = options.pop('sep', ' ')
    # Create the final string
    printed_string = sep.join(args)
    # Modify the final string
    printed_string = printed_string.replace('cat', 'dog')
    # Call the default print function
    _print(printed_string, **options)

import builtins
builtins.print = custom_print

实际上,如果您运行:

>>> def print_something():
...     print('This cat was scared.')
>>> print_something()
This dog was scared.

或者,如果您将其写入文件:

test_file.py

def print_something():
    print('This cat was scared.')

print_something()

并导入:

>>> import test_file
This dog was scared.
>>> test_file.print_something()
This dog was scared.

因此,它确实按预期工作。

但是,如果您只想临时打印Monkey补丁,可以将其包装在上下文管理器中:

import builtins

class ChangePrint(object):
    def __init__(self):
        self.old_print = print

    def __enter__(self):
        def custom_print(*args, **options):
            # Get the desired seperator or the default whitspace
            sep = options.pop('sep', ' ')
            # Create the final string
            printed_string = sep.join(args)
            # Modify the final string
            printed_string = printed_string.replace('cat', 'dog')
            # Call the default print function
            self.old_print(printed_string, **options)

        builtins.print = custom_print

    def __exit__(self, *args, **kwargs):
        builtins.print = self.old_print

因此,当您运行时,它取决于上下文,显示的内容是:

>>> with ChangePrint() as x:
...     test_file.print_something()
... 
This dog was scared.
>>> test_file.print_something()
This cat was scared.

这样便可以print通过Monkey补丁“破解” 。

修改目标,而不是 print

如果您看一下签名,print则会注意到默认情况下有一个file参数sys.stdout。请注意,这是一个动态默认参数(每次调用时都会真正查找),而不像Python中的普通默认参数。因此,如果您进行更改,则实际上将打印到其他目标会更加方便,因为Python还提供了一个功能(从Python 3.4开始,但是为早期的Python版本创建等效功能很容易)。sys.stdoutprintsys.stdout printredirect_stdout

缺点是它不适用于print不打印到的语句,sys.stdout并且创建自己的语句stdout并不是很简单。

import io
import sys

class CustomStdout(object):
    def __init__(self, *args, **kwargs):
        self.current_stdout = sys.stdout

    def write(self, string):
        self.current_stdout.write(string.replace('cat', 'dog'))

但是,这也可以:

>>> import contextlib
>>> with contextlib.redirect_stdout(CustomStdout()):
...     test_file.print_something()
... 
This dog was scared.
>>> test_file.print_something()
This cat was scared.

摘要

@abarnet已经提到了其中一些观点,但是我想更详细地探讨这些选项。特别是如何跨模块(使用builtins/ __builtin__)修改它,以及如何仅临时更改(使用contextmanagers)。

Monkey-patch print

print is a builtin function so it will use the print function defined in the builtins module (or __builtin__ in Python 2). So whenever you want to modify or change the behavior of a builtin function you can simply reassign the name in that module.

This process is called monkey-patching.

# Store the real print function in another variable otherwise
# it will be inaccessible after being modified.
_print = print  

# Actual implementation of the new print
def custom_print(*args, **options):
    _print('custom print called')
    _print(*args, **options)

# Change the print function globally
import builtins
builtins.print = custom_print

After that every print call will go through custom_print, even if the print is in an external module.

However you don’t really want to print additional text, you want to change the text that is printed. One way to go about that is to replace it in the string that would be printed:

_print = print  

def custom_print(*args, **options):
    # Get the desired seperator or the default whitspace
    sep = options.pop('sep', ' ')
    # Create the final string
    printed_string = sep.join(args)
    # Modify the final string
    printed_string = printed_string.replace('cat', 'dog')
    # Call the default print function
    _print(printed_string, **options)

import builtins
builtins.print = custom_print

And indeed if you run:

>>> def print_something():
...     print('This cat was scared.')
>>> print_something()
This dog was scared.

Or if you write that to a file:

test_file.py

def print_something():
    print('This cat was scared.')

print_something()

and import it:

>>> import test_file
This dog was scared.
>>> test_file.print_something()
This dog was scared.

So it really works as intended.

However, in case you only temporarily want to monkey-patch print you could wrap this in a context-manager:

import builtins

class ChangePrint(object):
    def __init__(self):
        self.old_print = print

    def __enter__(self):
        def custom_print(*args, **options):
            # Get the desired seperator or the default whitspace
            sep = options.pop('sep', ' ')
            # Create the final string
            printed_string = sep.join(args)
            # Modify the final string
            printed_string = printed_string.replace('cat', 'dog')
            # Call the default print function
            self.old_print(printed_string, **options)

        builtins.print = custom_print

    def __exit__(self, *args, **kwargs):
        builtins.print = self.old_print

So when you run that it depends on the context what is printed:

>>> with ChangePrint() as x:
...     test_file.print_something()
... 
This dog was scared.
>>> test_file.print_something()
This cat was scared.

So that’s how you could “hack” print by monkey-patching.

Modify the target instead of the print

If you look at the signature of print you’ll notice a file argument which is sys.stdout by default. Note that this is a dynamic default argument (it really looks up sys.stdout every time you call print) and not like normal default arguments in Python. So if you change sys.stdout print will actually print to the different target even more convenient that Python also provides a redirect_stdout function (from Python 3.4 on, but it’s easy to create an equivalent function for earlier Python versions).

The downside is that it won’t work for print statements that don’t print to sys.stdout and that creating your own stdout isn’t really straightforward.

import io
import sys

class CustomStdout(object):
    def __init__(self, *args, **kwargs):
        self.current_stdout = sys.stdout

    def write(self, string):
        self.current_stdout.write(string.replace('cat', 'dog'))

However this also works:

>>> import contextlib
>>> with contextlib.redirect_stdout(CustomStdout()):
...     test_file.print_something()
... 
This dog was scared.
>>> test_file.print_something()
This cat was scared.

Summary

Some of these points have already be mentioned by @abarnet but I wanted to explore these options in more detail. Especially how to modify it across modules (using builtins/__builtin__) and how to make that change only temporary (using contextmanagers).


回答 2

print函数捕获所有输出然后对其进行处理的一种简单方法是将输出流更改为其他内容,例如文件。

我将使用PHP命名约定(ob_startob_get_contents,…)

from functools import partial
output_buffer = None
print_orig = print
def ob_start(fname="print.txt"):
    global print
    global output_buffer
    print = partial(print_orig, file=output_buffer)
    output_buffer = open(fname, 'w')
def ob_end():
    global output_buffer
    close(output_buffer)
    print = print_orig
def ob_get_contents(fname="print.txt"):
    return open(fname, 'r').read()

用法:

print ("Hi John")
ob_start()
print ("Hi John")
ob_end()
print (ob_get_contents().replace("Hi", "Bye"))

将打印

嗨约翰再见约翰

A simple way to capture all output from a print function and then process it, is to change the output stream to something else, e.g. a file.

I’ll use a PHP naming conventions (ob_start, ob_get_contents,…)

from functools import partial
output_buffer = None
print_orig = print
def ob_start(fname="print.txt"):
    global print
    global output_buffer
    print = partial(print_orig, file=output_buffer)
    output_buffer = open(fname, 'w')
def ob_end():
    global output_buffer
    close(output_buffer)
    print = print_orig
def ob_get_contents(fname="print.txt"):
    return open(fname, 'r').read()

Usage:

print ("Hi John")
ob_start()
print ("Hi John")
ob_end()
print (ob_get_contents().replace("Hi", "Bye"))

Would print

Hi John Bye John


回答 3

让我们将其与帧自省结合起来!

import sys

_print = print

def print(*args, **kw):
    frame = sys._getframe(1)
    _print(frame.f_code.co_name)
    _print(*args, **kw)

def greetly(name, greeting = "Hi")
    print(f"{greeting}, {name}!")

class Greeter:
    def __init__(self, greeting = "Hi"):
        self.greeting = greeting
    def greet(self, name):
        print(f"{self.greeting}, {name}!")

您会发现此技巧在调用函数或方法的每个问候语前都有序。这对于日志记录或调试可能非常有用;特别是因为它可以让您“劫持”第三方代码中的打印语句。

Let’s combine this with frame introspection!

import sys

_print = print

def print(*args, **kw):
    frame = sys._getframe(1)
    _print(frame.f_code.co_name)
    _print(*args, **kw)

def greetly(name, greeting = "Hi")
    print(f"{greeting}, {name}!")

class Greeter:
    def __init__(self, greeting = "Hi"):
        self.greeting = greeting
    def greet(self, name):
        print(f"{self.greeting}, {name}!")

You’ll find this trick prefaces every greeting with the calling function or method. This might be very useful for logging or debugging; especially as it lets you “hijack” print statements in third party code.