Python

发布于 2020-10-05  1.41k 次阅读


本文仅讲解 Python 基础语法。

Python

Python 是一种解释型、面向对象、动态数据类型的高级程序设计语言。

Python 由 Guido van Rossum 于 1989 年底发明,第一个公开发行版发行于 1991 年。

语言优点

人生苦短,我用 Python。

  1. 易于学习:Python 有相对较少的关键字,结构简单,和一个明确定义的语法,学习起来更加简单。
  2. 易于阅读:Python 代码定义的更清晰。
  3. 易于维护:Python 的成功在于它的源代码是相当容易维护的。
  4. 一个广泛的标准库:Python 的最大的优势之一是丰富的库,跨平台的,在 UNIX,Windows 和 Macintosh 兼容很好。
  5. 互动模式:互动模式的支持,您可以从终端输入执行代码并获得结果的语言,互动的测试和调试代码片断。
  6. 可移植:基于其开放源代码的特性,Python 已经被移植(也就是使其工作)到许多平台。
  7. 可扩展:如果你需要一段运行很快的关键代码,或者是想要编写一些不愿开放的算法,你可以使用 C 或 C++ 完成那部分程序,然后从你的 Python 程序中调用。
  8. 数据库:Python 提供所有主要的商业数据库的接口。
  9. GUI 编程:Python 支持 GUI 可以创建和移植到许多系统调用。
  10. 可嵌入: 你可以将 Python 嵌入到 C/C++ 程序,让你的程序的用户获得"脚本化"的能力。

语言缺点

  1. 运行效率较低。如果你对速度有要求的话,还是需要用 C++ 改写关键部分吧。
  2. 国内市场较小。
  3. 中文资料匮乏。尽管有一些优秀的教材已经被翻译了,但大多都是入门级教材,高级内容还是只能看英语版。
  4. 构架选择太多。

环境安装(Windows)

访问官方下载地址,下载并安装。

你可以开始菜单打开 Python3 IDLE,新建一个 .py 文件,在其中写下你的脚本,按 F5 运行。

你也可以使用编辑器先写好 xxx.py,然后在命令行中输入 python xxx.py 运行该脚本。


基础语法

由于作者本人主要使用 C++,本文部分讲解可能更照顾 C++ 使用者,但并不妨碍其他语言使用者正常理解。

本文主要讲解 Python 3,部分代码可能无法在 Python 2 下运行。

原始数据类型和运算符

数字

Python 仅支持三种不同的数字类型:intfloatcomplex,但是它们足以支持你将用到的所有计算。

10      # int (有符号整形)
15.20   # float (浮点型)
3.14j   # complex (复数)

常规运算

加法、减法、乘法和模除并没有什么特别的。

1 + 1       # => 2
3 - 2       # => 1
4 * 5       # => 20
7 % 3       # => 1

3 * 2.0     # => 6.0 浮点数的运算结果也是浮点数

(1 + 3) * 2 # => 8

除法会自动转换成浮点数。

40 / 8      # => 5.0
2 / 3       # => 0.6666666666666667

整数除法的结果向下取整。

float 也可以参与整数除法运算。

5 // 3          # => 1
5.0 // 3.0      # => 1.0
-5 // 3         # => -2
-5.0 // 3.0     # => -2.0

还有 C++ 没有的乘方。

2**3    # => 8

逻辑运算

布尔值为 TrueFalse,注意开头大写。

not 取非。

not True    # => False
not False   # => True

逻辑运算使用 andor

True and False  # => False
False or True   # => True

整数也可以当做布尔值。

0 and 2     #=> 0
-5 or 0     #=> -5
0 == False  #=> True
2 == True   #=> False
1 == True   #=> True

== 判断相等,用 != 判断不等,这与 C++ 没有区别。

1 == 1  # => True
2 == 1  # => False
1 != 1  # => False
2 != 1  # => True

比较大小,这也没有什么特别的。

1 < 10  # => True
1 > 10  # => False
2 <= 2  # => True
2 >= 2  # => True

但是在 Python 中,大小比较是可以连起来的。

1 < 2 < 3   # => True
2 < 3 < 2   # => False

字符串

字符串用 '" 都可以。

"这是个字符串"
'这也是个字符串'

字符串可以直接相加。

"Hello " + "world!" # => "Hello world!"

字符串可以被当做字符列表(与 C++ 的字符数组相似)。

"This is a string"[1]  # => 'h'

使用 .format 格式化字符串。

用后面括号内的内容去替换前面字符串中 {} 的位置。

"{} can be {}".format("strings", "interpolated")

可以重复参数以节省时间。

即用后面括号内的第一项去替换前面 {0} 的位置,第二项去替换前面 {1} 的位置……

"{0} be nimble, {0} be quick, {0} jump over the {1}".format("Jack", "candle stick")
# => "Jack be nimble, Jack be quick, Jack jump over the candle stick"

如果你觉得参数并不好记,也可以用关键字。

"{name} wants to eat {food}".format(name="Bob", food="lasagna")
# => "Bob wants to eat lasagna"

特殊

None 是一个对象。

None    # => None

当尝试与 None 进行比较时不应使用 ==,要用 isis 用来比较两个变量是否指向同一个对象。

"etc" is None   # => False
None is None    # => True

注意 None0,空字符串,空列表,空字典都算是 False;除此以外的所有值都为 True

bool(0)     # => False
bool("")    # => False
bool([])    # => False
bool({})    # => False

变量和集合

变量

在给变量赋值前不用提前声明。

注意 Python 同样对大小写敏感。

(本文中所有变量名均采用骆驼式命名法命名。这种命名方法在许多新的函数库以及 Microsoft Windows 等环境中使用的相当多,本人较为推荐。)

someVar = 5
someVar       # => 5

访问未赋值的变量会抛出异常。

someUnknownVar  # 抛出异常 NameError

列表

在 Python 中使用列表(list)存储序列。

li = []
otherLi = [4, 5, 6]

append 在列表最后插入元素。

li.append(1)    # li = [1]
li.append(2)    # li = [1, 2]
li.append(4)    # li = [1, 2, 4]
li.append(3)    # li = [1, 2, 4, 3]
li.append(5)    # li = [1, 2, 4, 3, 5]

pop 删除列表尾部的元素。

li.pop()       # [1, 2, 4, 3]

列表存储与 C++ 的数组完全相同,特别的,下标 -1 表示最后一个元素。

li[0]   # => 1
li[-1]  # => 3
li[4]   # 抛出 IndexError

列表有切割语法。

切割语法形如 list[l:r:step],即从 list[l] 开始,每隔 step 个元素取一个,一直取到 r 为止。

li[1:3]     # => [2, 4]         取li[1]~li[3]
li[2:]      # => [4, 3]         取最后面的2个元素
li[:3]      # => [1, 2, 4]      取最前面的3个元素
li[::2]     # => [1, 4]         每隔2个元素取一下
li[::-1]        # => [3, 4, 2, 1]   倒过来(每隔-1个元素取一下)

del 可以删除列表中的任意元素。

del li[2]   # => [1, 2, 3]

列表可以相加,规则与字符串类似。

li + otherLi    # => [1, 2, 3, 4, 5, 6]

extend 拼接列表。

li.extend(otherLi)  # li = [1, 2, 3, 4, 5, 6]

in 查找列表中是否含有某元素。

1 in li     # => True

len 取列表长度。

len(li)     # => 6

元组

元组是不可改变的序列。

除不可改变这一性质外,其余均与列表完全相同。

tup = (1, 2, 3)
tup[0]          # => 1
tup[0] = 3      # 抛出 TypeError
len(tup)        # => 3
tup + (4, 5, 6)         # => (1, 2, 3, 4, 5, 6)
tup[:2]         # => (1, 2)
2 in tup        # => True

特别的,你可以对元组进行解包,赋值给变量。

元组周围的括号是可以省略的。

a, b, c = (1, 2, 3)
d, e, f = 4, 5, 6
e, d = d, e     # 交换两个元素

字典

用字典存储映射关系,与 C++ 的 std::map 类似。

emptyDict = {}
filledDict = {"one": 1, "two": 2, "three": 3}

同样字典也可以使用 [] 取值。

filledDict["one"]   # => 1
filledDict["four"]  # 抛出 KeyError

keys 可以一次性获得所有的键,用 values 可以一次性获得所有的值。

keysvalues 将会返回一个可迭代对象,这里直接将其包在 list 中,就可以获得一个存有所有键/值的 list

注意上述函数返回键/值的顺序可能并不固定,你可能会得到各种不同的排列(可能与下面不同)。

list(filledDict.keys())     # => ["one", "two", "three"]
list(filledDict.values())   # => [1, 2, 3]

可以使用 in 查询字典中是否包含某个键。

"one" in filledDict # => True
1 in filledDict     # => False

我们可以使用 get 来在字典中查找某个键对应的值。

与直接使用 [] 不同的是,这个操作访问不存在的键时会返回 None 而不是抛出异常 KeyError

filledDict.get("one")       # => 1
filledDict.get("four")      # => None
# 可以在函数的第二项加入一个默认值,使得键不存在时返回该默认值
filledDict.get("one",4)     # => 1
filledDict.get("four",r)    # => 4

可以直接使用字典赋值的方式插入新值。

filledDict.update({"four": 4})          # filledDict = {"one": 1, "two": 2, "three": 3, "four": 4}
filledDict["four"] = 4          # 另一种赋值方法

可以使用 setdefault 在键不存在时插入新值。

filledDict.setdefault("five", 5)    # filledDict["five"] = 5
filledDict.setdefault("five", 6)    # filledDict["five"] = 5

del 删除一对键值。

del filled_dict["one"]     # filledDict = {"two": 2, "three": 3, "four": 4}

集合

set 表示集合,与 C++ 的 std::set 类似,自动去重。

emptySet = set()
someSet = {1, 3, 2, 4, 3, 4}    # someSet = {1, 2, 3, 4}

集合也可以直接赋值。

filledSet = someSet

使用 add 在集合中增加元素。

filledSet.add(5)    # filledSet = {1, 2, 3, 4, 5}

使用 & 取交集,| 取并集,- 取补集。

otherSet = {3, 4, 5, 6}
filledSet & otherSet        # => {3, 4, 5}
filledSet | otherSet        # => {1, 2, 3, 4, 5, 6}
{1, 2, 3, 4} - {2, 3, 5}    # => {1, 4}

同样也可以使用 in 来判断集合是否包含某元素。

2 in filledSet      # => True
9 in filledSet      # => False

流程控制与迭代器

请注意缩进在 Python 里是有含义的。

if

if 语句与 C++ 并没有大的区别。

其中 elif = else if

ifelif: 之间的逻辑表达式即为 if 判断的标准。

var = 5
if var > 10:
    print("var is bigger than 10")
elif var < 10:
    print("var is smaller than 10")
else:
    print("var is 10")

for

正常的 for 语句应该这样写。

其中 range(num) 返回 $[0,num)$ 区间内的所有数字。

也可以使用 range(l, r) 返回 $[l,r)$ 区间内的所有数字。

for number in range(4):
    print("{} is a number".format(number))

遍历列表的写法则是这样。

for number in ["one", "two", "three"]:
    print("{} is a number".format(number))

while

while 后的逻辑表达式与 if 相同。

这里展示的是前两例的 while 写法实现。

val = 0
while val < 4:
    print("{} is a number".format(val))
    val += 1    # 不要习惯性写 val++

pass

pass 语句本身无含义,仅作占位语句用。

比如如果你希望写一个空循环。

for i in range(1, 10):

但这样会显示编译错误,你应该写成这样。

for i in range(1, 10):
    pass

这样就写出了一个空循环。

try/except

在下面这段脚本运行时你可以从控制台窗口上看到关于 KeyError 的报错提醒。

dict = {"one": 1}
dict["two"]     # => KeyError

这是因为我们的字典访问到了不存在的键,抛出了 KeyError,并让进程强制结束。

这时我们可以使用 try/except 块捕捉异常。

  • 如果 try 后的语句执行时发生异常,python 就跳回到 try 并执行第一个匹配该异常的 except 子句,异常处理完毕,控制流就通过整个 try 语句(除非在处理异常时又引发新的异常)。
  • 如果在 try 后的语句里发生了异常,却没有匹配的 except 子句,异常将被递交到上层的 try,或者到程序的最上层(这样将结束程序,并打印默认的报错信息)。
  • 如果在 try 子句执行时没有发生异常,python 将执行 else 语句后的语句(如果存在),然后控制流通过整个 try 语句。
try:
    dict["two"]         # 抛出 KeyError
except KeyError:        # 如果捕捉到 KeyError
    print("KeyError")
except IndexError:      # 如果捕捉到 IndexError
    pass
else:               # 如果没有捕捉到异常
    print("all ok")

try 也可以同时对应多个 expect

并且每个 expect 语句也可同时捕捉多个异常。

try:
    dict["two"]
except KeyError:
    print("KeyError")
except IndexError:
    pass
except (NameError, IOError):    # 同时捕捉 NameError 和 IOError
    print("Error")
else:
    print("all ok")

try-finally

try-finally 语句无论是否发生异常都将执行最后的代码。

特别的,try-finally 语句并不会过滤掉异常,在该语句块结束后异常依旧会返回外层。

try:
    fh = open("testfile", "w")              # 尝试打开文件
    try:
        fh.write("这是一个测试文件,用于测试异常!!")       # 尝试写入
    finally:                        # 发生了异常,但是依旧执行下面的语句
        print("关闭文件")
        fh.close()
except IOError:                             # 第4行语句抛出的异常在此处被捕捉
    print("Error: 没有找到文件或读取文件失败")

iterable

Python 提供可迭代对象,一个可迭代对象是可以被当作序列的对象。比如说上面range 返回的对象就是可迭代的。

filledDict = {"one": 1, "two": 2, "three": 3}
ourIterable = filledDict.keys()
print(ourIterable)

以下为输出。

dict_keys(['one', 'two', 'three'])

可迭代对象是可以遍历的。

for i in ourIterable:
    print(i)    # 打印 one two three

但是可迭代对象并不支持随机访问。

ourIterable[1]  # 抛出 TypeError

iterator

我们可以使用可迭代对象生成迭代器。

ourIterator = iter(ourIterable)

此处的迭代器定义与 C++ 相似,类似于指针。

使用 __next__ 可以取得下一个元素。

ourIterator.__next__()  # => "one"
ourIterator.__next__()  # => "two"
ourIterator.__next__()  # => "three"
ourIterator.__next__()  # 抛出 StopIteration

我们可以使用 list 一次性取出迭代器中的所有元素。

for i in list(ourIterator):
    print(i)

函数

函数是这样定义的。

def add(a, b):
    print("{} + {} = {}".format(a, b, a + b))
    return a + b

我们可以通过关键字参数来调用函数。

add(5, 6)
add(b=3, a=2)   # 等价于 add(2, 3)

我们可以通过 * 定义可变参函数。

def func(*a):
    return a

print(func(3, 1, 2, 4))

输出

(3, 1, 2, 4)

我们可以通过 ** 定义关键字可变参数函数。

def func(**a):
    return a

print(func(a="1", b="2"))

输出

{'a': '1', 'b': '2'}

也可以把两个混起来用。

def func(*a, **b):
    print(a)
    print(b)
    return

print(func(1, 2, 3, x=6, y=7))

输出

(1, 2, 3)
{'x': 6, 'y': 7}
None

调用可变参数函数是可以用与上面相同的符号展开序列、字典。

def func(*a, **b):
    print(a)
    print(b)
    return

a = (1, 2, 3, 4)
b = {"x": 6, "y": 7}
func(*a)
func(**b)
func(*a, **b)

输出

(1, 2, 3, 4)
{}
()
{'x': 6, 'y': 7}
(1, 2, 3, 4)
{'x': 6, 'y': 7}

Python 的函数中也有局部变量一说。

x = 1

def func(y):
    x = y
    print(x)
    return

func(3)
print(x)

输出

3
1

我们可以使用 global 关键字将全局变量作用域引入函数,类似于 C++ 的 :: 运算符。

x = 1

def func(y):
    global x
    x = y
    print(x)
    return

func(3)
print(x)

输出

3
3

在 Python 中,也可以使用类似于函数指针的方法传递函数。不过由于这里不需要申明变量类型,显得十分简洁。

def func(x, y):
    def add(x, y):
        return x + y

    print(add(x, y))
    return add

func2 = func(1, 2)
print(func2(3, 4))

输出

3
7

也有匿名函数,与 C++11 中的 lambda 表达式很相似。

print((lambda x, y: x + y)(1, 2))

合理使用匿名函数可以有效减短代码长度压行

map(lambda x: x + 10, [1, 2, 3])            # => [11, 12, 13]
filter(lambda x: x > 5, [3, 4, 5, 6, 7])            # => [6, 7]

将函数带入列表推导式可以简化映射和过滤。

[(lambda i: i + 10)(i) for i in [1, 2, 3]]  # => [11, 12, 13]
[x for x in [3, 4, 5, 6, 7] if x > 5]       # => [6, 7]

高阶

如果你读到了这里,那么恭喜你已经掌握了 Python 的基础语法。你已经拥有用 Python 写常规小程序的能力了。

关于 Python 的高阶操作,可以看以下教程或是在网上参阅相关资料。

作者将会努力为大家提供更多的 Python 高阶教程。

CYaRon(咕)

CYaRon 是一个可以帮助你快速生成随机数据的工具库,目标是帮 OIer 在 5 分钟内快速生成一组测试数据。

如果你想要出题,想必 CYaRon 是你造数据的不二之选。

CYaRon


参考:
1. https://learnxinyminutes.com/docs/python/
2. https://www.runoob.com/python/python-tutorial.html
3. https://github.com/luogu-dev/cyaron/wiki/Python-30%E5%88%86%E9%92%9F%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97

如果有人想看 CYaRon 的介绍的话可以评论,我可能会赶工写完。


我缓慢吐出一串啊吧啊吧并不再想说话