首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

Python 字串格式化:映射解包與 **locals() 進階技巧

     編輯:更多程式設計知識

Python str.format() 支援映射解包語法 **mapping,配合 locals()、vars() 或自訂字典,能實現極度簡潔的變數插值,避免重複變數名稱。本文詳細說明映射解包語法、locals() 應用、作用域陷阱、安全性考量與最佳實務。

核心語法:映射解包


name = "jack"
age = 24

# 傳統格式化:重複變數名
s1 = "name is {name} and age is {age}".format(name=name, age=age)

# 映射解包:自動對應同名鍵
s2 = "name is {name} and age is {age}".format(**locals())
# 等價於 .format(**{'name': 'jack', 'age': 24})

print(s1)  # name is jack and age is 24
print(s2)  # name is jack and age is 24

locals() 行為與作用域


def demo_locals():
    x = 10
    y = 20
    print(locals())  # {'x': 10, 'y': 20, ...}

demo_locals()

# 全域 locals() 等同 globals()
print(locals() is globals())  # True(模組層級)

進階應用模式

1. 函式參數自動格式化


def log_call(func_name, **params):
    """自動記錄函式呼叫參數"""
    template = "{func_name}({params})"
    param_str = ", ".join(f"{k}={v!r}" for k, v in params.items())
    print(template.format(func_name=func_name, params=param_str))

# 使用:將參數打包為字典
args = {'user_id': 123, 'action': 'login', 'ip': '192.168.1.1'}
log_call("auth", **args)
# auth(user_id=123, action='login', ip='192.168.1.1')

2. 設定檔模板渲染


# 設定模板(可外部載入)
CONFIG_TEMPLATE = """
[database]
host = {db_host}
port = {db_port}
user = {db_user}
password = {db_pass}
"""

# 環境變數或設定來源
config = {
    'db_host': 'localhost',
    'db_port': 5432,
    'db_user': 'admin',
    'db_pass': 'secret123'
}

rendered = CONFIG_TEMPLATE.format(**config)
print(rendered)

3. 類別實例屬性格式化


class User:
    def __init__(self, name, email, role):
        self.name = name
        self.email = email
        self.role = role

user = User("Alice", "alice@example.com", "admin")

# vars(obj) 等同 obj.__dict__
template = "User: {name}, Email: {email}, Role: {role}"
print(template.format(**vars(user)))
# User: Alice, Email: alice@example.com, Role: admin

4. 結合解包與顯式參數(優先權)


base = {'app': 'MyApp', 'version': '1.0'}
# 顯式參數覆蓋映射值
s = "{app} v{version} - {env}".format(**base, env="production")
print(s)  # MyApp v1.0 - production

# 衝突時顯式參數優先
s = "{app} v{version}".format(**{'app': 'Old', 'version': '0.9'}, app="New", version="2.0")
print(s)  # New v2.0

作用域陷阱與避坑指南

  1. 函式內 locals() 包含所有區域變數:
    
    def format_user(name, age):
        # locals() = {'name': name, 'age': age, ...}
        # 若模板只需 name,age 也會被傳入(無害但多餘)
        return "User: {name}".format(**locals())
    
    # 建議:顯式建構字典
    def format_user_v2(name, age):
        return "User: {name}".format(name=name)
    # 或
    def format_user_v3(name, age):
        return "User: {name}".format(**{'name': name})
  2. 迴圈變數洩漏:
    
    for i in range(3):
        x = i * 10
    # 迴圈結束後,i, x 仍在 locals() 中
    print(locals())  # 包含 'i': 2, 'x': 20
  3. 效能考量:locals() 建立字典副本,頻繁呼叫有開銷。熱路徑請用顯式字典。

安全性考量:格式化字串注入


# 危險:使用者控制格式化字串
user_input = "{__import__('os').system('rm -rf /')}"
# template.format(**locals()) 可能執行惡意代碼(視 Python 版本)

# 安全實務:
# 1. 格式化字串不可來自使用者輸入
# 2. 使用 string.Template(較安全,功能受限)
from string import Template
t = Template("Hello $name")
print(t.substitute(name="Alice"))  # 僅支援 $var 或 ${var}

# 3. 驗證格式化字串鍵名
ALLOWED_KEYS = {'name', 'age', 'email'}
def safe_format(template, data):
    used_keys = set(re.findall(r'\{(\w+)\}', template))
    if not used_keys.issubset(ALLOWED_KEYS):
        raise ValueError("模板包含不允許的鍵")
    return template.format(**data)

format_map():直接使用映射(Python 3.2+)


# format_map 不複製字典,直接使用(支援 __missing__)
class SafeDict(dict):
    def __missing__(self, key):
        return "{" + key + "}"  # 缺鍵保留原樣

data = {'name': 'Alice'}
print("Hello {name}, age {age}".format_map(SafeDict(data)))
# Hello Alice, age {age}(不拋出 KeyError)

現代替代方案:f-string(Python 3.6+)


name = "jack"
age = 24
# 直接使用變數,無需解包
print(f"name is {name} and age is {age}")

# 複雜表達式
print(f"Next year: {age + 1}")
print(f"Name upper: {name.upper()}")

# 格式化規格
import math
print(f"Pi: {math.pi:.3f}")

總結

**locals() 映射解包是快速原型、除錯輸出、模板渲染的便利技巧,**但生產代碼建議顯式建構字典**,避免作用域洩漏、效能開銷、安全性風險。掌握 vars(obj)、format_map()、SafeDict 進階模式,能靈活處理物件序列化、設定渲染、日誌格式化等場景。現代 Python 3.6+ 首選 f-string,語法最簡潔、效能最佳、功能最強。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved