类似于ls的输出列表
这个问题和这个是一样的,不过是针对Python的。如果我有一个列表
['a','b','cdefg','jk','lmnopqr','st','uv','wxyz',1,2,3,4]
我想把它打印出来,像bash中的ls命令那样,类似于
[ 'a', 'b', 'cdefg',
'jk', 'st', 'lm',
'no', 'pqrstuv', 'wxyz',
1, 2, 3,
4, ]
我的目标是让屏幕上能一次性显示更多的信息,方便查看。我只找到pprint这个库,但对于简单的列表,它要么默认打印,要么每行一个。有没有类似的东西已经存在呢?
3 个回答
0
我创建了一个模块 columnify.py,目的是为了实现相同的功能。
假设我们有以下这个列表作为输入:
items: list[str] = [
"Canidae", "Felidae", "Cat", "Cattle", "Dog",
"Donkey", "Goat", "Guinea pig", "Horse", "Pig",
"Rabbit", "Fancy rat varieties", "laboratory rat strains",
]
可以生成以下结果:
默认情况
Canidae Cat Dog Goat Horse Rabbit laboratory rat strains
Felidae Cattle Donkey Guinea pig Pig Fancy rat varieties
横向优先
Canidae Felidae Cat Cattle Dog Donkey Goat
Guinea pig Horse Pig Rabbit Fancy rat varieties laboratory rat strains
居中显示()
Canidae Cat Dog Goat Horse Rabbit laboratory rat strains
Felidae Cattle Donkey Guinea pig Pig Fancy rat varieties
右对齐()
Canidae Cat Dog Goat Horse Rabbit laboratory rat strains
Felidae Cattle Donkey Guinea pig Pig Fancy rat varieties
自定义分隔符 ( | )
Canidae | Cattle | Goat | Pig | laboratory rat strains
Felidae | Dog | Guinea pig | Rabbit
Cat | Donkey | Horse | Fancy rat varieties
缩进(4个空格):
Canidae Cattle Goat Pig laboratory rat strains
Felidae Dog Guinea pig Rabbit
Cat Donkey Horse Fancy rat varieties
4
def columnify(iterable):
# First convert everything to its repr
strings = [repr(x) for x in iterable]
# Now pad all the strings to match the widest
widest = max(len(x) for x in strings)
padded = [x.ljust(widest) for x in strings]
return padded
现在你可以使用 pprint.pprint(compact=True)
,或者 textwrap
,或者其他工具来调整格式,达到你想要的效果。
不过,如果你想手动调整,也不是很难。比如说:
def colprint(iterable, width=72):
columns = columnify(iterable)
colwidth = len(columns[0])+2
perline = (width-4) // colwidth
print('[ ', end='')
for i, column in enumerate(columns):
print(column, end=', ')
if i % perline == perline-1:
print('\n ', end='')
print(' ]')
所以:
>>> arr = ['a', 'b', 'cdefg', 'jk', 'lmnopqr', 'st', 'uv', 'wxyz', 1, 2, 3, 4]
>>> colprint(arr, 60)
[ 'a' , 'b' , 'cdefg' , 'jk' , 'lmnopqr',
'st' , 'uv' , 'wxyz' , 1 , 2 ,
3 , 4 , ]
这样做还是不能完全和 ls
的效果一样;比如说,ls
有一些智能算法,会确保那些“太长”的文件名不会算入最大宽度,而是会跨越多个列。如果你真的想要做到和 ls
一模一样,可能需要查看源代码,并把 C 语言的代码转换成 Python……
另外,可以看看 pprint
。每当一个模块的文档开头有指向源代码的链接时,这意味着这个模块不仅是为了自己好用,还可以作为有用的示例代码。所以,如果你想了解它是如何决定何时换行的(根据 compact
标志和宽度),你应该能从那里找到答案。
4
感谢大家的想法,也感谢你们澄清了目前确实没有现成的解决方案。我写了我想要的代码,下面是代码。
pprint_list( [ string.lowercase[i % 26]*random.randint(1,20) for i in range(8) ] )
在一个宽度为80个字符的终端中打印出来是这样的:
[ 'aaaa', 'bbbbbbbbbbbbbbb', 'ccccccccccccccccccc', 'd',
'eeeeeeeeeee', 'ffffffffffffffff', 'gggggggggggggggg', 'h' ]
从代码来看,显然在计算列的大小时会有一些额外的开销,条目越多、终端越宽,计算就越复杂。不过,把条目的数量从8增加到50000时,延迟并没有太明显,所以我觉得这个效果还不错。
这段代码依赖于一个叫做get_terminal_size的函数,详细信息可以在这里找到。
#!/usr/bin/env python
def pprint_list(input_list):
(term_width, term_height) = get_terminal_size()
if len( str(input_list) ) <= term_width:
print input_list
return
repr_list = [repr(x) for x in input_list]
min_chars_between = 3 # a comma and two spaces
usable_term_width = term_width - 3 # For '[ ' and ']' at beginning and end
min_element_width = min( len(x) for x in repr_list ) + min_chars_between
max_element_width = max( len(x) for x in repr_list ) + min_chars_between
if max_element_width >= usable_term_width:
ncol = 1
col_widths = [1]
else:
# Start with max possible number of columns and reduce until it fits
ncol = min( len(repr_list), usable_term_width / min_element_width )
while True:
col_widths = [ max( len(x) + min_chars_between \
for j, x in enumerate( repr_list ) if j % ncol == i ) \
for i in range(ncol) ]
if sum( col_widths ) <= usable_term_width: break
else: ncol -= 1
sys.stdout.write('[ ')
for i, x in enumerate(repr_list):
if i != len(repr_list)-1: x += ','
sys.stdout.write( x.ljust( col_widths[ i % ncol ] ) )
if i == len(repr_list) - 1:
sys.stdout.write(']\n')
elif (i+1) % ncol == 0:
sys.stdout.write('\n ')