แสดง Output จาก Python Data Structure ยังไงให้อ่านง่าย
How to Print Human-Readable Output from Python Data Structures
— — — — — — — — — — — — — — —
สารบัญเนื้อหาทั้งหมด (My Contents)
— — — — — — — — — — — — — — —
เคยมั้ยบางครั้งที่เราเขียน Python ขึ้นมาเพื่อช่วยในการทำงาน และต้องการความสะดวกรวดเร็วในการพัฒนา เราก็มักจะ print ผลลัพธ์ออกมาดื้อ ๆ จาก data structure เลยโดยไม่มีการจัด format แบบนี้
['10.0.0.1', '10.0.0.2', '10.0.0.3', '10.0.0.4', '10.0.0.5', '10.0.0.6', '10.0.0.7', '10.0.0.8', '10.0.0.9', '10.0.0.10', '10.0.0.11', '10.0.0.12', '10.0.0.13', '10.0.0.14', '10.0.0.15', '10.0.0.16', '10.0.0.17', '10.0.0.18', '10.0.0.19', '10.0.0.20']
หรือแบบนี้
[{'hostname': 'KCiBk', 'ip': '10.0.0.1', 'os': 'windows', 'version': '2012r2'}, {'hostname': 'tQcOv', 'ip': '10.0.0.2', 'os': 'redhat', 'version': '7'}, {'hostname': 'RwyOa', 'ip': '10.0.0.3', 'os': 'ubuntu', 'version': '18.04'}, {'hostname': 'IpQQa', 'ip': '10.0.0.4', 'os': 'windows', 'version': '2019'}, {'hostname': 'MCJEF', 'ip': '10.0.0.5', 'os': 'windows', 'version': '2019'}, {'hostname': 'OjAhw', 'ip': '10.0.0.6', 'os': 'redhat', 'version': '7.2'}, {'hostname': 'YkWrx', 'ip': '10.0.0.7', 'os': 'windows', 'version': '2019'}, {'hostname': 'KnFfQ', 'ip': '10.0.0.8', 'os': 'windows', 'version': '2016'}, {'hostname': 'iTIpJ', 'ip': '10.0.0.9', 'os': 'windows', 'version': '2019'}, {'hostname': 'KiEzv', 'ip': '10.0.0.10', 'os': 'redhat', 'version': '7.2'}, {'hostname': 'MgyOd', 'ip': '10.0.0.11', 'os': 'ubuntu', 'version': '18.04'}, {'hostname': 'uJEfD', 'ip': '10.0.0.12', 'os': 'redhat', 'version': '8'}, {'hostname': 'TRJjy', 'ip': '10.0.0.13', 'os': 'redhat', 'version': '7'}, {'hostname': 'zPeFd', 'ip': '10.0.0.14', 'os': 'redhat', 'version': '7'}, {'hostname': 'PHrYq', 'ip': '10.0.0.15', 'os': 'windows', 'version': '2016'}, {'hostname': 'CjrAr', 'ip': '10.0.0.16', 'os': 'ubuntu', 'version': '16.04'}, {'hostname': 'NaOrF', 'ip': '10.0.0.17', 'os': 'ubuntu', 'version': '20.04'}, {'hostname': 'PvhvF', 'ip': '10.0.0.18', 'os': 'windows', 'version': '2016'}, {'hostname': 'dIuqi', 'ip': '10.0.0.19', 'os': 'redhat', 'version': '7'}, {'hostname': 'fLHFB', 'ip': '10.0.0.20', 'os': 'ubuntu', 'version': '20.04'}]
วันนี้ผมจะมาสอนวิธีที่จะช่วยให้ output ของ Python ที่แสดงผลบน console window ของเราสวยขึ้น อ่านง่ายขึ้น มีความ human readable มากขึ้นว่างั้นเถอะ
— — — — — — — — — — — — — — — — — — — — — —
ฝากคอร์ส Python for Network Automation ผมด้วยครับ
— — — — — — — — — — — — — — — — — — — — — —
Code ตัวอย่าง
ใครอยากลองเอาไปรันเล่นเพื่อศึกษา ทุกอย่างอยู่ในนี้หมดแล้วครับ
git clone https://github.com/nopnithi/python_pretty_output_tutorial.git
Code ส่วนที่ใช้ Generate ข้อมูลจำลอง
เนื่องด้วยเราไม่มีข้อมูลจริง ก็เลยต้องใช้ code ช่วย generate เอา data ออกมาให้ โดยสมมุติว่าเป็นข้อมูลของ server จำนวน 20 เครื่อง (VMs)
from random import choice
import stringdevices = []
addresses = []for i in range(1, 21):
device = {
'hostname': (choice(string.ascii_letters) +
choice(string.ascii_letters) +
choice(string.ascii_letters) +
choice(string.ascii_letters) +
choice(string.ascii_letters)),
'ip': '10.0.0.' + str(i),
'os': choice(['ubuntu', 'redhat', 'windows'])
}
if device['os'] == 'ubuntu':
device['version'] = choice(['16.04', '18.04', '20.04'])
elif device['os'] == 'redhat':
device['version'] = choice(['6', '7', '7.1', '7.2', '8'])
elif device['os'] == 'windows':
device['version'] = choice(['2012r2', '2016', '2019']) addresses.append(device['ip'])
devices.append(device)
ซึ่งเดี๋ยวผมจะเอา raw data ที่ได้จาก code นี้(ตัวแปร addresses
และ devices
) ไปใช้ในแต่ละตัวอย่างต่อไปนะครับ
1) ตัวอย่างของปัญหา
สมมุติว่าผมเขียน Python ขึ้นมาช่วยในการเช็คว่า ณ ตอนนี้มี server ออนไลน์ทั้งหมดกี่ตัว พร้อมแสดง information ต่าง ๆ ออกมา
แต่ผมขี้เกียจเขียน code เยอะ ก็เลยใช้การ print เอา output ออกมาจาก data structure โดยตรงเลย โดยไม่ได้เขียนฟังก์ชั่นการแสดงผลอะไร
ปัญหาก็คือ output ที่ได้มันจะอ่านยากสำหรับ user ที่ใช้ script นี้ เราจะทำยังไงหละถึงจะง่ายทั้งฝั่ง developer และ user
2) เตรียม Library ให้เรียบร้อย
ติดตั้ง tabulate ก่อน
$ pip install tabulate
Collecting tabulate
Downloading tabulate-0.8.7-py3-none-any.whl (24 kB)
Installing collected packages: tabulate
Successfully installed tabulate-0.8.7
จากนั้น import pprint, tabulate และ itemgetter เข้ามา
from pprint import pprint
from tabulate import tabulate
from operator import itemgetter
3) แสดงผล List
ใช้ print (ธรรมดา)
print(addresses)
จะได้
['10.0.0.1', '10.0.0.2', '10.0.0.3', '10.0.0.4', '10.0.0.5', '10.0.0.6', '10.0.0.7', '10.0.0.8', '10.0.0.9', '10.0.0.10', '10.0.0.11', '10.0.0.12', '10.0.0.13', '10.0.0.14', '10.0.0.15', '10.0.0.16', '10.0.0.17', '10.0.0.18', '10.0.0.19', '10.0.0.20']
ใช้ pprint
pprint(addresses, width=-1)
จะได้
['10.0.0.1',
'10.0.0.2',
'10.0.0.3',
'10.0.0.4',
'10.0.0.5',
'10.0.0.6',
'10.0.0.7',
'10.0.0.8',
'10.0.0.9',
'10.0.0.10',
'10.0.0.11',
'10.0.0.12',
'10.0.0.13',
'10.0.0.14',
'10.0.0.15',
'10.0.0.16',
'10.0.0.17',
'10.0.0.18',
'10.0.0.19',
'10.0.0.20']
4) แสดงผล Dictionary
ใช้ print (ธรรมดา)
print(devices[0])
จะได้
{'hostname': 'KCiBk', 'ip': '10.0.0.1', 'os': 'windows', 'version': '2012r2'}
ใช้ pprint
pprint(devices[0], width=-1)
จะได้
{'hostname': 'KCiBk',
'ip': '10.0.0.1',
'os': 'windows',
'version': '2012r2'}
5) แสดงผล List ของ Dictionary
ใช้ print (ธรรมดา)
print(devices)
จะได้
[{'hostname': 'KCiBk', 'ip': '10.0.0.1', 'os': 'windows', 'version': '2012r2'}, {'hostname': 'tQcOv', 'ip': '10.0.0.2', 'os': 'redhat', 'version': '7'}, {'hostname': 'RwyOa', 'ip': '10.0.0.3', 'os': 'ubuntu', 'version': '18.04'}, {'hostname': 'IpQQa', 'ip': '10.0.0.4', 'os': 'windows', 'version': '2019'}, {'hostname': 'MCJEF', 'ip': '10.0.0.5', 'os': 'windows', 'version': '2019'}, {'hostname': 'OjAhw', 'ip': '10.0.0.6', 'os': 'redhat', 'version': '7.2'}, {'hostname': 'YkWrx', 'ip': '10.0.0.7', 'os': 'windows', 'version': '2019'}, {'hostname': 'KnFfQ', 'ip': '10.0.0.8', 'os': 'windows', 'version': '2016'}, {'hostname': 'iTIpJ', 'ip': '10.0.0.9', 'os': 'windows', 'version': '2019'}, {'hostname': 'KiEzv', 'ip': '10.0.0.10', 'os': 'redhat', 'version': '7.2'}, {'hostname': 'MgyOd', 'ip': '10.0.0.11', 'os': 'ubuntu', 'version': '18.04'}, {'hostname': 'uJEfD', 'ip': '10.0.0.12', 'os': 'redhat', 'version': '8'}, {'hostname': 'TRJjy', 'ip': '10.0.0.13', 'os': 'redhat', 'version': '7'}, {'hostname': 'zPeFd', 'ip': '10.0.0.14', 'os': 'redhat', 'version': '7'}, {'hostname': 'PHrYq', 'ip': '10.0.0.15', 'os': 'windows', 'version': '2016'}, {'hostname': 'CjrAr', 'ip': '10.0.0.16', 'os': 'ubuntu', 'version': '16.04'}, {'hostname': 'NaOrF', 'ip': '10.0.0.17', 'os': 'ubuntu', 'version': '20.04'}, {'hostname': 'PvhvF', 'ip': '10.0.0.18', 'os': 'windows', 'version': '2016'}, {'hostname': 'dIuqi', 'ip': '10.0.0.19', 'os': 'redhat', 'version': '7'}, {'hostname': 'fLHFB', 'ip': '10.0.0.20', 'os': 'ubuntu', 'version': '20.04'}]
ใช้ pprint
pprint(devices, width=-1)
จะได้
[{'hostname': 'KCiBk',
'ip': '10.0.0.1',
'os': 'windows',
'version': '2012r2'},
{'hostname': 'tQcOv',
'ip': '10.0.0.2',
'os': 'redhat',
'version': '7'},
{'hostname': 'RwyOa',
'ip': '10.0.0.3',
'os': 'ubuntu',
'version': '18.04'},
{'hostname': 'IpQQa',
'ip': '10.0.0.4',
'os': 'windows',
'version': '2019'},
{'hostname': 'MCJEF',
'ip': '10.0.0.5',
'os': 'windows',
'version': '2019'},
{'hostname': 'OjAhw',
'ip': '10.0.0.6',
'os': 'redhat',
'version': '7.2'},
{'hostname': 'YkWrx',
'ip': '10.0.0.7',
'os': 'windows',
'version': '2019'},
{'hostname': 'KnFfQ',
'ip': '10.0.0.8',
'os': 'windows',
'version': '2016'},
{'hostname': 'iTIpJ',
'ip': '10.0.0.9',
'os': 'windows',
'version': '2019'},
{'hostname': 'KiEzv',
'ip': '10.0.0.10',
'os': 'redhat',
'version': '7.2'},
{'hostname': 'MgyOd',
'ip': '10.0.0.11',
'os': 'ubuntu',
'version': '18.04'},
{'hostname': 'uJEfD',
'ip': '10.0.0.12',
'os': 'redhat',
'version': '8'},
{'hostname': 'TRJjy',
'ip': '10.0.0.13',
'os': 'redhat',
'version': '7'},
{'hostname': 'zPeFd',
'ip': '10.0.0.14',
'os': 'redhat',
'version': '7'},
{'hostname': 'PHrYq',
'ip': '10.0.0.15',
'os': 'windows',
'version': '2016'},
{'hostname': 'CjrAr',
'ip': '10.0.0.16',
'os': 'ubuntu',
'version': '16.04'},
{'hostname': 'NaOrF',
'ip': '10.0.0.17',
'os': 'ubuntu',
'version': '20.04'},
{'hostname': 'PvhvF',
'ip': '10.0.0.18',
'os': 'windows',
'version': '2016'},
{'hostname': 'dIuqi',
'ip': '10.0.0.19',
'os': 'redhat',
'version': '7'},
{'hostname': 'fLHFB',
'ip': '10.0.0.20',
'os': 'ubuntu',
'version': '20.04'}]
ใช้ for loop + dict.items() + F-strings
for device in devices:
for key, value in device.items():
print(f'{key:>10s}: {value}')
print('-' * 30)
ขออธิบายนิดเดียวละกันครับ ตรง :>10s
เป็นการจัด format ให้กับส่วน key
โดยเตรียมระยะหรือจำนวนตัวอักษรไว้ 10 ตัวและก็จัดชิดขวาไปแบบรูปด้านล่างนี้
จะได้
hostname: KCiBk
ip: 10.0.0.1
os: windows
version: 2012r2
------------------------------
hostname: tQcOv
ip: 10.0.0.2
os: redhat
version: 7
------------------------------
hostname: RwyOa
ip: 10.0.0.3
os: ubuntu
version: 18.04
------------------------------
hostname: IpQQa
ip: 10.0.0.4
os: windows
version: 2019
------------------------------
hostname: MCJEF
ip: 10.0.0.5
os: windows
version: 2019
------------------------------
hostname: OjAhw
ip: 10.0.0.6
os: redhat
version: 7.2
------------------------------
hostname: YkWrx
ip: 10.0.0.7
os: windows
version: 2019
------------------------------
hostname: KnFfQ
ip: 10.0.0.8
os: windows
version: 2016
------------------------------
hostname: iTIpJ
ip: 10.0.0.9
os: windows
version: 2019
------------------------------
hostname: KiEzv
ip: 10.0.0.10
os: redhat
version: 7.2
------------------------------
hostname: MgyOd
ip: 10.0.0.11
os: ubuntu
version: 18.04
------------------------------
hostname: uJEfD
ip: 10.0.0.12
os: redhat
version: 8
------------------------------
hostname: TRJjy
ip: 10.0.0.13
os: redhat
version: 7
------------------------------
hostname: zPeFd
ip: 10.0.0.14
os: redhat
version: 7
------------------------------
hostname: PHrYq
ip: 10.0.0.15
os: windows
version: 2016
------------------------------
hostname: CjrAr
ip: 10.0.0.16
os: ubuntu
version: 16.04
------------------------------
hostname: NaOrF
ip: 10.0.0.17
os: ubuntu
version: 20.04
------------------------------
hostname: PvhvF
ip: 10.0.0.18
os: windows
version: 2016
------------------------------
hostname: dIuqi
ip: 10.0.0.19
os: redhat
version: 7
------------------------------
hostname: fLHFB
ip: 10.0.0.20
os: ubuntu
version: 20.04
------------------------------
ใช้ tabulate และ itemgetter
tabular_output = tabulate(sorted(devices, key=itemgetter('os', 'version')), headers='keys')
print(tabular_output)
สำหรับ code ด้านบน เป็นการใช้ tabulate ช่วยสร้าง output ออกมาเป็นตาราง ซึ่งจุดสำคัญที่อยากอธิบายมี 2 ส่วน
ส่วนแรก sorted(devices, key=itemgetter('os', 'version'))
เป็นการบอกว่าข้อมูลใน devices
list นั้นผมต้องการจัดเรียงโดยเรียงจากข้อมูลที่ key os
ก่อน สังเกตว่า output จะไล่มาจาก redhat, ubuntu แล้วตามด้วย windows
จากนั้นเรียงลำดับอีกครั้งจาก version
สังเกต redhat ก็จะเรียงจากเวอร์ชั่น 7 → 7. 2 → 8 หรือ ubuntu ก็จาก 16.04 → 18.04 → 20.04 เป็นต้น
ส่วนที่สองคือ headers='keys'
ซึ่งเป็นการบอก tabulate ว่าให้ใช้ key ใน dictionary ในการสร้าง header ของตารางให้เราอัตโนมัติ
เพราะฉะนั้นจะได้
hostname ip os version
---------- --------- ------- ---------
tQcOv 10.0.0.2 redhat 7
TRJjy 10.0.0.13 redhat 7
zPeFd 10.0.0.14 redhat 7
dIuqi 10.0.0.19 redhat 7
OjAhw 10.0.0.6 redhat 7.2
KiEzv 10.0.0.10 redhat 7.2
uJEfD 10.0.0.12 redhat 8
CjrAr 10.0.0.16 ubuntu 16.04
RwyOa 10.0.0.3 ubuntu 18.04
MgyOd 10.0.0.11 ubuntu 18.04
NaOrF 10.0.0.17 ubuntu 20.04
fLHFB 10.0.0.20 ubuntu 20.04
KCiBk 10.0.0.1 windows 2012r2
KnFfQ 10.0.0.8 windows 2016
PHrYq 10.0.0.15 windows 2016
PvhvF 10.0.0.18 windows 2016
IpQQa 10.0.0.4 windows 2019
MCJEF 10.0.0.5 windows 2019
YkWrx 10.0.0.7 windows 2019
iTIpJ 10.0.0.9 windows 2019
ก็หวังว่าจะเป็นประโยชน์สำหรับทุกท่านที่เขียน Python และขี้เกียจแบบผมครับ
— — — — — — — — — — — — — — —
สารบัญเนื้อหาทั้งหมด (My Contents)
— — — — — — — — — — — — — — —