MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Python中%s的格式化输出定制

2021-09-302.7k 阅读

一、Python 格式化输出基础

在 Python 编程中,格式化输出是一项非常重要的操作,它允许我们以一种结构化和易读的方式呈现数据。Python 提供了多种格式化输出的方法,其中使用 %s 进行格式化是一种较为传统且常用的方式。

%s 是一个占位符,代表字符串类型。当我们使用 % 操作符与包含 %s 的字符串模板结合时,% 操作符右侧的值会被插入到字符串模板中 %s 所在的位置。例如:

name = "Alice"
print("Hello, %s!" % name)

上述代码中,字符串模板 "Hello, %s!" 中的 %s 被变量 name 的值 "Alice" 所替换,最终输出 Hello, Alice!

二、基本格式化定制

  1. 对齐方式
    • 左对齐:在 %s 中,可以通过在 %s 之间添加 - 来实现左对齐。例如:
text = "Python"
print("|%-10s|" % text)

在这个例子中,%-10s 表示将 text 左对齐,并占用 10 个字符的宽度。输出结果为 |Python |,右侧填充了空格以达到 10 个字符的宽度。

  • 右对齐:默认情况下,不添加 - 时,字符串是右对齐的。例如:
text = "Python"
print("|%10s|" % text)

这里 %10s 表示将 text 右对齐,占用 10 个字符宽度,输出结果为 | Python|,左侧填充了空格。

  • 居中对齐:要实现居中对齐,可以在 %s 之间添加 ^。例如:
text = "Python"
print("|%^10s|" % text)

%^10s 表示将 text 居中对齐,占用 10 个字符宽度,输出结果为 | Python |,两侧均匀填充空格。

  1. 填充字符 除了使用空格进行填充外,我们还可以指定其他字符进行填充。例如,要使用 * 进行填充:
text = "Python"
print("|%*10s|" % ('*', text))

这里通过在 %s 之间添加 *,并且在 % 操作符右侧先给出填充字符 *,再给出变量 text。输出结果为 |***Python***|,使用 * 填充到 10 个字符宽度。

三、格式化多个 %s

当字符串模板中有多个 %s 占位符时,% 操作符右侧需要提供对应数量的值,并且按照顺序依次替换。例如:

name1 = "Alice"
name2 = "Bob"
print("%s and %s are friends." % (name1, name2))

上述代码中,第一个 %sname1 的值 "Alice" 替换,第二个 %sname2 的值 "Bob" 替换,最终输出 Alice and Bob are friends.

四、与其他数据类型结合格式化

虽然 %s 主要用于字符串类型,但 Python 会自动将其他数据类型转换为字符串进行格式化。例如:

number = 123
print("The number is %s" % number)

这里 number 是整数类型,但通过 %s 格式化时,它会被自动转换为字符串 "123" 进行输出,结果为 The number is 123

不过,有时候我们可能需要更精确地控制非字符串类型数据的格式化。比如对于浮点数,我们可以结合 %s 实现特定格式的输出。假设我们有一个浮点数,想要保留两位小数并以字符串形式输出:

float_num = 3.14159
formatted_str = "%.2f" % float_num
print("The formatted string is %s" % formatted_str)

这里先使用 %.2f 将浮点数 float_num 格式化为保留两位小数的字符串 3.14,然后再通过 %s 进行整体的格式化输出,最终结果为 The formatted string is 3.14

五、格式化字典中的字符串

当处理字典数据结构时,也可以使用 %s 进行格式化输出。我们可以在字符串模板中使用类似于 %(key)s 的形式来引用字典中的值。例如:

person = {
    "name": "Charlie",
    "age": 30
}
print("%(name)s is %(age)s years old." % person)

在这个例子中,%(name)s 会被字典 person 中键为 "name" 的值 "Charlie" 替换,%(age)s 会被键为 "age" 的值 30(自动转换为字符串)替换,输出结果为 Charlie is 30 years old.

六、动态格式化字符串模板

在实际编程中,字符串模板可能需要根据不同的情况动态生成。例如,我们可能根据用户输入来决定格式化的具体内容。

user_choice = input("Enter 'left', 'right' or 'center' for alignment: ")
text = "Python"
if user_choice == "left":
    format_str = "|%-10s|"
elif user_choice == "right":
    format_str = "|%10s|"
elif user_choice == "center":
    format_str = "|%^10s|"
else:
    print("Invalid choice.")
    exit()
print(format_str % text)

上述代码根据用户输入的对齐方式动态生成字符串模板,然后使用 %s 进行格式化输出。这种动态生成格式化字符串的方式在处理多样化的输出需求时非常有用。

七、在函数中使用 %s 格式化输出

在函数内部,%s 格式化输出同样适用。我们可以将需要格式化的内容作为函数参数传递进来,然后在函数中进行格式化操作。

def greet(name):
    return "Hello, %s!" % name
result = greet("David")
print(result)

在这个 greet 函数中,接受一个参数 name,并使用 %s 将其格式化为问候语,最后返回格式化后的字符串并输出 Hello, David!

八、格式化输出中的转义字符处理

在使用 %s 进行格式化输出时,可能会遇到需要处理转义字符的情况。例如,如果我们想要输出包含双引号的字符串:

text = 'She said, "Hello!"'
print('The text is: %s' % text)

这里 text 字符串本身包含双引号,在格式化输出时,Python 会正确处理这种情况,输出 The text is: She said, "Hello!"

但是,如果字符串中包含 % 字符,就需要进行转义。例如:

text = "The percentage is 50%"
print("The content is: %s" % text.replace('%', '%%'))

由于 % 在格式化中有特殊含义,所以需要将字符串中的 % 替换为 %% 才能正确输出 The content is: The percentage is 50%

九、%s 格式化与其他格式化方式的对比

  1. format() 方法对比
    • 语法灵活性format() 方法的语法相对更灵活。例如,使用 format() 方法可以通过索引或关键字参数来指定替换位置:
name1 = "Alice"
name2 = "Bob"
print("{} and {} are friends.".format(name1, name2))
print("{1} and {0} are friends.".format(name1, name2))
print("{name1} and {name2} are friends.".format(name1 = "Alice", name2 = "Bob"))

%s 格式化只能按照顺序依次替换。

  • 格式化功能丰富度format() 方法在格式化数字、日期等方面有更强大的功能。例如,格式化浮点数时,可以更简洁地指定千位分隔符等:
num = 1234567.89
print("{:,.2f}".format(num))

输出 1,234,567.89。而使用 %s 实现类似功能则需要更多的额外操作。 2. 与 f - 字符串对比

  • 性能:在 Python 3.6 及以上版本,f - 字符串在性能上通常优于 %s 格式化。f - 字符串在编译时就进行求值,而 %s 格式化在运行时进行操作。例如:
import timeit
name = "Eve"
def using_percent():
    return "Hello, %s!" % name
def using_fstring():
    return f"Hello, {name}!"
print(timeit.timeit(using_percent, number = 100000))
print(timeit.timeit(using_fstring, number = 100000))

通常情况下,using_fstring 的执行时间会更短。

  • 可读性:f - 字符串的可读性更强,它直接在字符串中嵌入表达式,例如 f"Today is {datetime.now().strftime('%Y - %m - %d')}",相比 %s 格式化,代码意图更清晰。

然而,%s 格式化作为 Python 较早期就存在的方式,在一些旧代码库中仍然广泛存在,并且在简单的字符串替换场景下,其语法简洁明了,仍然具有一定的使用价值。

十、在文件操作中的 %s 格式化输出

在文件操作中,我们也可以使用 %s 格式化将数据写入文件。例如:

name = "Frank"
with open('output.txt', 'w') as file:
    file.write("The name is %s\n" % name)

上述代码将格式化后的字符串 The name is Frank 写入到 output.txt 文件中,并添加了换行符 \n。读取文件时,我们也可以结合 %s 格式化进行内容的处理和展示。

with open('output.txt', 'r') as file:
    line = file.readline()
    print("Read from file: %s" % line.strip())

这里读取文件的一行内容,并使用 %s 格式化输出,同时使用 strip() 方法去除行末的换行符。

十一、%s 格式化在日志记录中的应用

日志记录是软件开发中非常重要的一部分,用于记录程序运行过程中的关键信息、错误信息等。%s 格式化在日志记录中经常被使用。例如,使用 Python 内置的 logging 模块:

import logging
logging.basicConfig(level = logging.INFO)
name = "Grace"
logging.info("User %s logged in." % name)

上述代码使用 logging.info 记录用户登录信息,通过 %s 格式化将用户名插入到日志消息中。这样在查看日志时,可以清晰地看到具体是哪个用户执行了登录操作。

在实际应用中,日志记录可能会更加复杂,需要记录时间、模块名等更多信息。例如:

import logging
import datetime
logging.basicConfig(level = logging.INFO, format='%(asctime)s - %(module)s - %(levelname)s - %(message)s')
name = "Henry"
logging.info("User %s logged in." % name)

这里通过 basicConfigformat 参数设置了日志的格式,其中 %(asctime)s 表示时间,%(module)s 表示模块名,%(levelname)s 表示日志级别,%(message)s 表示具体的日志消息,而消息中又使用 %s 格式化了用户名。

十二、%s 格式化在网络编程中的应用

在网络编程中,例如在客户端 - 服务器模型中,%s 格式化可用于构建和处理网络消息。假设我们有一个简单的 TCP 服务器和客户端: 服务器端代码

import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('127.0.0.1', 12345))
server_socket.listen(1)
print("Server is listening...")
while True:
    client_socket, addr = server_socket.accept()
    data = client_socket.recv(1024).decode('utf - 8')
    response = "Server received: %s" % data
    client_socket.send(response.encode('utf - 8'))
    client_socket.close()

客户端代码

import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('127.0.0.1', 12345))
message = "Hello, Server!"
client_socket.send(message.encode('utf - 8'))
response = client_socket.recv(1024).decode('utf - 8')
print(response)
client_socket.close()

在这个例子中,服务器端接收到客户端发送的数据后,使用 %s 格式化构建响应消息并返回给客户端。客户端接收到响应后进行输出,展示了 %s 格式化在网络消息处理中的应用。

十三、%s 格式化在数据库操作中的应用

在与数据库交互时,%s 格式化可用于构建 SQL 查询语句。例如,使用 sqlite3 模块:

import sqlite3
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
name = "Ivy"
age = 25
cursor.execute("INSERT INTO users (name, age) VALUES ('%s', %d)" % (name, age))
conn.commit()
conn.close()

上述代码通过 %s 格式化将用户名插入到 SQL 插入语句中。需要注意的是,这种直接在 SQL 语句中使用格式化字符串的方式存在 SQL 注入风险。为了安全起见,更好的方式是使用参数化查询:

import sqlite3
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
name = "Ivy"
age = 25
cursor.execute("INSERT INTO users (name, age) VALUES (?,?)", (name, age))
conn.commit()
conn.close()

虽然参数化查询更安全,但了解 %s 格式化在构建 SQL 语句中的使用方式,对于理解早期代码或简单场景下的操作仍有帮助。

十四、在模板引擎中的 %s 格式化概念延伸

一些模板引擎,例如 Jinja2,虽然其自身有一套强大的模板语法,但 %s 格式化背后的替换占位符思想在模板引擎中也有体现。例如在 Jinja2 模板中:

from jinja2 import Template
template = Template("Hello, {{ name }}!")
name = "Jack"
print(template.render(name = name))

这里 {{ name }} 类似于 %s 占位符的概念,只不过 Jinja2 有更丰富的语法和功能,如循环、条件判断等。理解 %s 格式化有助于理解模板引擎中占位符替换的基本原理,以及在不同场景下如何灵活运用格式化和模板技术来生成动态内容。

十五、%s 格式化在代码调试中的作用

在代码调试过程中,%s 格式化可以帮助我们输出关键变量的值,以便快速定位问题。例如:

def divide(a, b):
    try:
        result = a / b
        print("The result of %s divided by %s is %s" % (a, b, result))
        return result
    except ZeroDivisionError:
        print("Cannot divide by zero.")
divide(10, 2)
divide(5, 0)

divide 函数中,通过 %s 格式化输出除法运算的操作数和结果,当出现异常时,也能清晰地看到输入的参数值,有助于调试和分析问题。

十六、%s 格式化在国际化与本地化中的应用

在开发国际化(i18n)和本地化(l10n)应用时,%s 格式化可以用于处理不同语言环境下的字符串替换。例如,假设我们有一个英文消息模板和一个法文消息模板:

english_template = "Welcome, %s!"
french_template = "Bienvenue, %s!"
user_name = "Leo"
# 根据用户的语言设置选择模板
language = "en"
if language == "en":
    message = english_template % user_name
else:
    message = french_template % user_name
print(message)

这里根据用户的语言设置选择不同语言的消息模板,并使用 %s 格式化将用户名插入到消息中。在实际的国际化应用中,通常会使用更复杂的机制来管理不同语言的资源文件,但 %s 格式化是实现字符串替换的基础操作之一。

通过以上多个方面对 %s 格式化输出定制的介绍,我们可以看到它在 Python 编程的各个领域都有广泛的应用。虽然随着 Python 的发展,出现了一些更强大和方便的格式化方式,但 %s 格式化因其简单易用,在许多场景下仍然是一个不错的选择。在实际编程中,我们应根据具体需求灵活选择合适的格式化方式,以达到高效、清晰地输出数据的目的。