SageMath 基本语法

archive time: 2024-08-31

SageMath 就是 Python 的超集

函数的定义与使用

在 SageMath 中定义函数与 Python 中是一样的,使用 def 关键词,例如:

def self_fib_fun(n):
    def inner_fib(n, a, b):
        if n == 0:
            return a
        elif n == 1:
            return b
        else:
            return inner_fib(n - 1, b, a + b)
    return inner_fib(n, 0, 1)

在使用方面,和内置的函数一样,都是使用小括号和可能需要的参数来调用

self_fib_fun(10)
# => 55

在定义函数时,函数的参数可以有默认值, 那么有默认值的参数在函数调用时就可以不传递参数,而是使用默认值,例如:

def another_fib_fun(n, a = 0, b = 1):
    if n == 0:
        return a
    elif n == 1:
        return b
    else:
        return another_fib_fun(n - 1, b, a + b)

不传递参数的情况:

# a = 0, b = 1
another_fib_fun(10)
# => 55

也可以显式传递参数:

# b = 1
another_fib_fun(10, a = 1)
# => 89

虽然不推荐,但是也可以根据位置传递参数:

# a = 1, b = 1
another_fib_fun(10, 1)
# => 89

# a = 1, b = 2
another_fib_fun(10, 1, 2)
# => 144

类似的,对于所有的参数,都可以使用名称来传递参数值,这样就可以按照自己想要的顺序传递参数,例如:

another_fib_fun(a = 1, n = 10, b = 2)
# => 144

作用域

在 SageMath 和 Python 中,作用域是通过缩进来区分的, 所以每个缩进的大小都应该要一致,一般是 个空格

如果缩进不一致,则会出现 IndentationError

缩进错误

图中可能不明显,错误之处在于 return v 一行的缩进是 个空格, 而其他地方使用的都是 个空格,缩进不匹配,导致解释器不知道具体的层级

流程控制

一般来说,控制流有三种,分别是 顺序执行分支执行循环执行

默认情况下,SageMath 和 Python 都是自上而下执行的,也就是所谓的顺序执行, 但是我们有办法让执行顺序改变,也就是所谓的流程控制

例如在之前的 self_fib_fun 中看到的 if ... elif ... else ... 就是分支执行

这种分支执行顺序是通过某种条件来判断状态,进而选择一条分支来执行,其他的分支就被放弃

a = 10

# 分支执行
if a == 1:
    print("a is ONE")
elif a == 2:
    print("a is TWO")
elif a == 3:
    print("a is THREE")
else:
    print(f"a is {a}")
# => a is 10

而循环执行则是通过 while ...for ... in ... 的形式来完成的

for i in range(5):
    print(i, end=" ")
else:
    print()

a = 10
while a > 0:
    print(a, end=" ")
    a = a - 1
else:
    print()

# =>
# 0 1 2 3 4
# 10 9 8 7 6 5 4 3 2 1

在循环执行中还可以通过 break 或者 continue 来中断或者跳过某次循环, 而循环执行中的 else 是在循环正常结束的时候执行的内容:

for i in range(10):
    print(f"ok for {i}")
    if i == 2:
        break
else:
    print("finished")
# =>
# ok for 0
# ok for 1
# ok for 2

上述代码中,由于循环是通过 break 结束的,所以并不会输出 finished

可迭代对象

for ... in ... 循环中,in 后面的对象被称为 可迭代对象(Iterable)1

在 SageMath 和 Python 中,最常见也是最实用的可迭代对象就是 列表(List)

通常情况下,可以通过 list() 函数来将可迭代对象变成一个列表,例如:

list(range(1, 15, 2))
# => [1, 3, 5, 7, 9, 11, 13]

并且列表中的元素的类型不固定,可以是任意类型的对象,并且列表的索引是从 开始的

x = var("x")
# 定义并初始化一个列表
v = [1, "hello", 2/3, sin(x^3)]
# 通过索引获取列表中的值
bool((v[3]).subs(x = 3) == sin(27))
# => True

可以通过 bool() 函数判断两个表达式是否相等

对于列表,常用的函数有 len()append(),以及 del 操作符

除了列表,字典,或者说关联列表,也是常用的一种可迭代对象

d = {
    "hi": "hello",
    pi: e
}

d["hi"] == "hello"
# => True

字典的每个元素都可以看成是一个键值对, 其中 是用于索引的元素, 是每个键对应的元素, 元素的类型对是不固定的,但是作为 的元素一定要是 不变的

bool(d[pi] == e)
# => True

自定义可迭代对象

除了自带的一些可迭代对象和类型,SageMath 和 Python 还给了我们自定义类型的能力:

class Odds(list):
    def __init__(self, n):
        self.n = n
        list.__init__(self, range(1, n+1, 2))
    def __repr__(self):
        return f"odds positive numbers up to {self.n}."

odd7 = Odds(7)
odd7
# => odds positive numbers up to 7.

这里,我们定义了一个类型 Odds,其中 Odds 是基于 list 类型的, 这在 Python 中称为继承关系,listOdds 的父类, Oddslist 的子类

类似的,我们也可以使用 list() 函数将 Odds 转变为一个列表

list(odd7)
# => [1, 3, 5, 7]

对于 odd7,我们也可以进行索引和迭代:

odd7[2]
# => 5

后记

SageMath 和 Python 语法几乎一模一样,仅有一些细节上有区别, 这既是好事,降低了使用者的学习门槛,也方便已经熟悉 Python 语法的人使用 SageMath, 也是坏事,因为 Python 的与 JavaScript 类似的动态类型,让 Python 变得不再可靠, 如果出现错误,除了需要花时间排查逻辑上的问题,还需要花时间去检查语法问题


1

可迭代对象.Python Docs [DB/OL].(2024-08-29)[2024-08-31]. https://docs.python.org/zh-cn/3/glossary.html#term-iterable