当前位置:首页>python>Python格式化字符与SAS 宏变量对比分析

Python格式化字符与SAS 宏变量对比分析

  • 2026-10-11 07:23:32
Python格式化字符与SAS 宏变量对比分析

前言

Python与SAS是数据分析工作中常用的两款工具。二者都支持动态变量嵌入与文本格式化,以此简化代码编写。Python格式化字符和SAS Macro宏变量正是实现该功能的核心手段,但二者的语法和运行逻辑各不相同。本文将简单对比两者的用法与差异,方便大家在实操中灵活选用。欢迎同行友好交流、探讨指正。

首次发布:2026-06-13


1. 核心概念定义

什么是格式化字符串?

定义:任何包含占位符的字符串模板,涵盖 %、str.format()、f-string 三种风格。比如,"Hello, %s", "Hello, {0}", f"Hello, {name}"都是格式化字符串。本文重点介绍的是 f-string。

下面的代码是一个具体的例子:

name = "Yuang"
s = f"""Hello, everyone!
My name is {name}!"""

print(s)

输出的内容是:
Hello, everyone!
My name is Yuang!

其中,Python 使用三重引号后,可以在字符串内保留换行.

怎么样?这个用法是不是有点像 SAS 宏变量。在字符串中通过占位符引用变量,最终生成包含变量实际值的文本。sas 是 %let 定义+ ampersand (&) 解析,而python 是直接在 "格式化字符串字面量" 中用花括号将定义的变量括起来。

格式化字符串字面量 (Formatted String Literal) 是指 f"..." 或 F"..." 形式的字符串字面量。而这里面花括号包裹的内容被称为替换字段。

字面量 就是代码里「直接写出来的值」,比如 5、3.1415926 是数字的字面量,True/False 是布尔字面量。其实,替换字段也支持表达式,如 f"{x**2 + math.sqrt(y):.2f}"。

上述的表达式是什么意思呢?即x 的平方 + y 的平方根,最后再保留2位小数。

2. 变量的作用域

请先看一段 Python 代码:

x = 100

deffunc(x):
    template = f"x is {x}"
    print(template)    

func(5) 

我们首先给变量 x 赋值为100,然后函数参数也设置为 x, 我们会发现运行 func(5) 打印的值仍然是 5。因为 python 的变量查找遵循 LEGB 查找顺序, 优先级是这样的:

  • Local:函数内部定义的变量、参数、for 循环变量等。
  • Enclosing:外层函数的局部变量(对嵌套的内层函数而言)。
  • Global:模块(即 .py 文件)顶层定义的变量,或者在函数内用 global 声明的变量。
  • Built-in:Python 内置的名字,如 print、len、Exception 等。

看看这一段程序就很直观了:

len = "我是全局的 len"# G,覆盖了内置的 len

defouter():
    len = "outer 的 len"# E(相对于 inner)
definner():
        len = "inner 的 len"# L
        print(len)              # 先找 L,找到 "inner 的 len"
    inner()
    print(len)                  # 这里的 L 是 outer 的,打印 "outer 的 len"

outer()
print(len)                      # G,打印 "我是全局的 len"

而 SAS 宏变量的作用域是先查找当前宏的局部符号表,调用当前宏的上一层宏的局部符号表(调用者),逐级向外,最后是全局符号表。

SAS 解析宏变量的值取决于运行时是谁调用了它,作用域是动态的,他不像 Python 一样,作用域由代码的书写位置决定。我举一个例子:

%macro outer;
  %let x = 10;
  %inner
%mend outer;

%macro inner;
  %put &x;   /* 此处查找 x */
%mend inner;

%macro another;
  %let x = 999;
  %outer      /* 在 another 内部调用 outer,outer 再调用 inner */
%mend another;

%another

上面这段 SAS 代码展示了3个宏的嵌套, 这里调用 %inner 的是 %outer, 所以 %put &x;在日志中的显示为 10。那么,如果我直接用宏 %another 调用 %inner 呢?

%macro another;
  %let x = 999;
  %inner
%mend another;
%another

那么输出的就是999了,因为 macro variable 取决于“谁在调用”而不是“在哪里定义”。

3. 通过条件生成代码

我们知道,SAS 宏 %IF 在宏处理器展开阶段工作,根据宏变量的值决定哪段代码被送往编译器。

如下面的代码块:在 sas 宏中, macro processor 会检测到 %if, 然后根据宏变量 type 判断需要执行的代码。这里执行的语句是 proc means 而不是 proc print.

%lettype = summary;

%macro report;
  %if &type = summary %then %do;
        proc means data=sashelp.shoes; run;     
    %end;
    %else %do;
        proc print data=sashelp.shoes; run;     
    %end;
%mend;

%report

那么,如果 Python 其实也可以实现这一功能。通常而言,python 的函数(对标 sas 宏)直接在 if 中用变量判断就可以了,比如这样:

from datetime import datetime

defgenerate_report(scores, report_type):
"""
    scores: dict,如 {'语文':88, '数学':92, '英语':79}
    report_type: str,取值 'summary' 或 'full'
    """

if report_type == "summary":
defcalc_summary(data):
return sum(data) / len(data)
        result = calc_summary(scores.values())
        print(f"汇总结果:{result:.2f}")
else:
defprint_full(data):
for k, v in data.items():
                print(f"{k}: {v}")
        print_full(scores)
        print(f"完整数据输出于 {datetime.now():%Y-%m-%d}")

# 调用
scores = {'语文':88, '数学':92, '英语':79}
generate_report(scores, "summary")
generate_report(scores, "full")

当判断条件需要基于多个外部输入、动态拼接成特定模式,或者需要把非字符串类型强制统一为字符串再做比较时,f-string 在 if 条件里就非常有用。比如这样:

# 从外部获取用户和操作类型(例如 API 参数、表单、文件配置)
user = input("用户名: ")
action = input("操作: ")

# 需要组合成一个模式来判断权限
iff"{user}_{action}" == "Alice_delete":
    print("允许删除")
else:
    print("权限不足")

有一个点值得讨论, sas 中可以用 %if %then %do; %end; %else %do; %end; 控制变量或部分语句的生成。比如这样:

%macro analysis(type);
    proc means data=sales;
        var price;
        %if &type = detailed %then %do;
            /* 只在详细模式下增加 class 和 weight */
            class region;
            weight quantity;
        %end;
    run;
%mend;

上述代码中,%if 仅仅控制了部分语句。但 Python 的 if/else 只能控制“整块代码”执行,不能生成半行代码,需要另辟蹊径,通过其他方式执行。


✍️ 文 / Yuang
   临研数据人: 用数字讲述药物故事

最新文章

随机文章