2024年6月16日 Python - 基础
基础语法
编码
默认情况下,Python 3 源码文件以 UTF-8 编码,所有字符串都是 unicode 字符串。 当然你也可以为源码文件指定不同的编码:
# -*- coding: cp-1252 -*-
标识符
- 第一个字符必须是字母表中字母或下划线
_
- 标识符的其他的部分由字母、数字和下划线组成
- 标识符对大小写敏感
在 Python 3 中,可以用中文作为变量名,非 ASCII 标识符也是允许的
Python 保留字
保留字即关键字,我们不能把它们用作任何标识符名称。Python 的标准库提供了一个 keyword 模块,可以输出当前版本的所有关键字:
>>> import keyword
>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
注释
Python 中单行注释以 #
开头
多行注释可以用多个 #
号,还有 '''
和 """
#!/usr/bin/python3
# 第一个注释
# 第二个注释
'''
第三个注释
第四个注释
'''
"""
第五个注释
第六个注释
"""
print("Hello, Python!")
行与缩进
Python 最具特色的就是使用缩进来表示代码块,不使用大括号 {}
缩进的空格数是可变的,但是同一个代码块的语句必须包含相同的缩进空格数。
以下代码最后一行语句缩进数的空格数不一致,会导致运行错误:
if True:
print("Answer")
print("True")
else:
print("Answer")
print("False") # 缩进不一致,会导致运行错误
报错信息:
IndentationError: unindent does not match any outer indentation level
多行语句
Python 通常是一行写完一条语句,但如果语句很长,我们可以使用反斜杠 \
来实现多行语句
在 []
, {}
, 或 ()
中的多行语句,不需要使用反斜杠 \
total = item_one + \
item_two + \
item_three
total = ['item_one', 'item_two', 'item_three',
'item_four', 'item_five']
空行
函数之间或类的方法之间用空行分隔,表示一段新的代码的开始。类和函数入口之间也用一行空行分隔,以突出函数入口的开始。
空行与代码缩进不同,空行并不是 Python 语法的一部分。书写时不插入空行,Python 解释器运行也不会出错。但是空行的作用在于分隔两段不同功能或含义的代码,便于日后代码的维护或重构。
记住:空行也是程序代码的一部分。
同一行使用多条语句
Python 可以在同一行中使用多条语句,语句之间使用分号 ;
分割
#!/usr/bin/python3
import sys; x = 'runoob'; sys.stdout.write(x + '\n')
使用交互式命令行执行,输出结果为:
>>> import sys; x = 'runoob'; sys.stdout.write(x + '\n')
runoob
7
此处的 7
表示字符数,runoob 有 6 个字符,\n 表示一个字符,加起来 7 个字符。
多个语句构成代码组
缩进相同的一组语句构成一个代码块,我们称之 代码组
像 if
、while
、def
和 class
这样的复合语句,首行以关键字开始,以冒号 :
结束,该行之后的一行或多行代码构成代码组
我们将首行及后面的代码组称为一个 子句(clause)
多个变量赋值
a = b = c = 1
a, b, c = 1, 2, "runoob"
Python3 解释器
Linux/Unix的系统上,一般默认的 python 版本为 2.x,我们可以将 python3.x 安装在 /usr/local/python3 目录中。
安装完成后,我们可以将路径 /usr/local/python3/bin 添加到您的 Linux/Unix 操作系统的环境变量中,这样您就可以通过 shell 终端输入下面的命令来启动 Python3
$ PATH=$PATH:/usr/local/python3/bin/python3 # 设置环境变量
$ python3 --version
Python 3.4.0
在 Window 系统下你可以通过以下命令来设置 Python 的环境变量,假设你的 Python 安装在 C:\Python34 下:
set path=%path%;C:\python34
交互式编程
Linux 下:
$ python3
Python 3.6.8 (default, Apr 19 2021, 17:20:37)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Windows 下:
> python
Python 3.10.1 (tags/v3.10.1:2cd268a, Dec 6 2021, 19:10:37) [MSC v.1929 64 bit (AMD64)] on win32
脚本式编程
通过以下命令执行该脚本:
$ python3 hello.py
在 Linux/Unix 系统中,你可以在脚本顶部添加以下命令让 Python 脚本可以像 SHELL 脚本一样可直接执行:
#! /usr/bin/env python3
然后修改脚本权限,使其有执行权限,命令如下:
$ chmod +x hello.py
执行以下命令:
./hello.py
运算符
Python 语言支持以下类型的运算符:
- 算术运算符
- 比较(关系)运算符
- 赋值运算符
- 逻辑运算符
- 位运算符
- 成员运算符
- 身份运算符
- 运算符优先级
算术运算符
以下假设变量 a=10
,变量 b=21
:
运算符 | 描述 | 实例 |
---|---|---|
+ | 加 - 两个对象相加 | a + b 输出结果 31 |
- | 减 - 得到负数或是一个数减去另一个数 | a - b 输出结果 -11 |
* | 乘 - 两个数相乘或是返回一个被重复若干次的字符串 | a * b 输出结果 210 |
/ | 除 - x 除以 y | b / a 输出结果 2.1 |
% | 取模 - 返回除法的余数 | b % a 输出结果 1 |
** | 幂 - 返回x的y次幂 | a**b 为 10 的21次方 |
// | 取整除 - 向下取接近商的整数 | >>> 9//2 4 >>> -9//2 -5 |
#!/usr/bin/python3
a = 21
b = 10
c = 0
print("a 的值位:", a) # 21
print("b 的值位:", b) # 10
c = a + b
print("a + b 的值为:", c) # 31
c = a - b
print("a - b 的值为:", c) # 11
c = a * b
print("a * b 的值为:", c) # 210
c = a / b
print("a / b 的值为:", c) # 2.1
c = a % b
print("a % b 的值为:", c) # 1
# 修改变量 a 、b 、c
a = 2
b = 3
c = a ** b
print("a ** b 的值为:", c) # 8
a = 10
b = 5
c = a // b
print("a // b 的值为:", c) # 2
比较运算符
以下假设变量 a 为 10 ,变量 b 为 20 :
运算符 | 描述 | 实例 |
---|---|---|
== | 等于 - 比较对象是否相等 | (a == b) 返回 False |
!= | 不等于 - 比较两个对象是否不相等 | (a != b) 返回 True |
> | 大于 - 返回 x 是否大于 y | (a > b) 返回 False |
< | 小于 - 返回 x 是否小于 y 。所有比较运算符返回 1 表示真,返回0表示假。这分别与特殊的变量 True 和 False 等价。注意,这些变量名的大写。 | (a < b) 返回 True |
>= | 大于等于 - 返回 x 是否大于等于 y | (a >= b) 返回 False |
<= | 小于等于 - 返回 x 是否小于等于 y | (a <= b) 返回 True |
赋值运算符
以下假设变量 a 为 10 ,变量 b 为 20 :
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符 | c = a + b 将 a + b 的运算结果赋值为 c |
+= | 加法赋值运算符 | c += a 等效于 c = c + a |
-= | 减法赋值运算符 | c -= a 等效于 c = c - a |
*= | 乘法赋值运算符 | c *= a 等效于 c = c * a |
/= | 除法赋值运算符 | c /= a 等效于 c = c / a |
%= | 取模赋值运算符 | c %= a 等效于 c = c % a |
**= | 幂赋值运算符 | c **= a 等效于 c = c ** a |
//= | 取整除赋值运算符 | c //= a 等效于 c = c // a |
:= | 海象运算符,可在表达式内部为变量赋值。Python3.8 版本新增运算符 | 在这个示例中,赋值表达式可以避免调用 len() 两次:if (n := len(a)) > 10: print(f"List is too long ({n} elements, expected <= 10)") |
位运算符
按位运算符是把数字看作二进制来进行计算的。Python中的按位运算法则如下:
下表中变量 a 为 60,b 为 13二进制格式如下:
a = 0011 1100
b = 0000 1101
-----------------
a&b = 0000 1100
a|b = 0011 1101
a^b = 0011 0001
~a = 1100 0011
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与运算符:参与运算的两个值,如果两个相应位都为 1 ,则该位的结果为 1 ,否则为 0 | (a & b) 输出结果 12 ,二进制解释: 0000 1100 |
| | 按位或运算符:只要对应的二个二进位有一个为 1 时,结果位就为 1 | (a | b) 输出结果 61 ,二进制解释: 0011 1101 |
^ | 按位异或运算符:当两对应的二进位相异时,结果为 1 | (a ^ b) 输出结果 49 ,二进制解释: 0011 0001 |
~ | 按位取反运算符:对数据的每个二进制位取反,即把 1 变为 0 ,把 0 变为 1。~x 类似于 -x-1 | (~a) 输出结果 -61 ,二进制解释: 1100 0011, 在一个有符号二进制数的补码形式。 |
<< | 左移动运算符:运算数的各二进位全部左移若干位,由 << 右边的数指定移动的位数,高位丢弃,低位补 0 |
a << 2 输出结果 240 ,二进制解释: 1111 0000 |
>> | 右移动运算符:把 >> 左边的运算数的各二进位全部右移若干位, >> 右边的数指定移动的位数 |
a >> 2 输出结果 15 ,二进制解释: 0000 1111 |
逻辑运算符
Python 语言支持逻辑运算符,以下假设变量 a 为 10 ,b为 20 :
运算符 | 逻辑表达式 | 描述 | 实例 |
---|---|---|---|
and | x and y | 布尔"与" - 如果 x 为 False,x and y 返回 x 的值,否则返回 y 的计算值。 | (a and b) 返回 20 |
or | x or y | 布尔"或" - 如果 x 是 True,它返回 x 的值,否则它返回 y 的计算值。 | (a or b) 返回 10 |
not | not x | 布尔"非" - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True | not(a and b) 返回 False |
成员运算符
除了以上的一些运算符之外,Python 还支持成员运算符,测试实例中包含了一系列的成员,包括字符串,列表或元组。
运算符 | 描述 | 实例 |
---|---|---|
in | 如果在指定的序列中找到值返回 True ,否则返回 False | x 在 y 序列中 , 如果 x 在 y 序列中返回 True |
not in | 如果在指定的序列中没有找到值返回 True ,否则返回 False | x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True |
#!/usr/bin/python3
a = 10
b = 20
list = [1, 2, 3, 4, 5]
if (a in list):
print("1 - 变量 a 在给定的列表中 list 中")
else:
print("1 - 变量 a 不在给定的列表中 list 中") # true
if (b not in list):
print("2 - 变量 b 不在给定的列表中 list 中") # true
else:
print("2 - 变量 b 在给定的列表中 list 中")
# 修改变量 a 的值
a = 2
if (a in list):
print("3 - 变量 a 在给定的列表中 list 中") # true
else:
print("3 - 变量 a 不在给定的列表中 list 中")
身份运算符
身份运算符用于比较两个对象的存储单元
运算符 | 描述 | 实例 |
---|---|---|
is | is 是判断两个标识符是不是引用自一个对象 | x is y , 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False |
is not | is not 是判断两个标识符是不是引用自不同对象 | x is not y , 类似 id(x) != id(y)。如果引用的不是同一个对象则返回结果 True,否则返回 False |
id()
函数用于获取对象内存地址
#!/usr/bin/python3
a = 20
b = 20
if (a is b):
print("1 - a 和 b 有相同的标识") # true
else:
print("1 - a 和 b 没有相同的标识")
if (id(a) == id(b)):
print("2 - a 和 b 有相同的标识") # true
else:
print("2 - a 和 b 没有相同的标识")
# 修改变量 b 的值
b = 30
if (a is b):
print("3 - a 和 b 有相同的标识")
else:
print("3 - a 和 b 没有相同的标识") # true
if (a is not b):
print("4 - a 和 b 没有相同的标识") # true
else:
print("4 - a 和 b 有相同的标识")
is
与 ==
区别:is
用于判断两个变量引用对象是否为同一个, ==
用于判断引用变量的值是否相等
运算符优先级
以下表格列出了从最高到最低优先级的所有运算符, 相同单元格内的运算符具有相同优先级。
运算符 | 描述 |
---|---|
(expressions...) , [expressions...] , {key: value...} , {expressions...} |
圆括号的表达式 |
x[index] , x[index:index] , x(arguments...) , x.attribute |
读取,切片,调用,属性引用 |
await x |
await 表达式 |
** |
乘方(指数) |
+x , -x , ~x |
正,负,按位非 NOT |
* , @ , / , // , % |
乘,矩阵乘,除,整除,取余 |
+ , - |
加和减 |
<< , >> |
移位 |
& |
按位与 AND |
^ |
按位异或 XOR |
| |
按位或 OR |
in , not in , is , is not , < , <= , > , >= , != , == |
比较运算,包括成员检测和标识号检测 |
not x |
逻辑非 NOT |
and |
逻辑与 AND |
or |
逻辑或 OR |
if -- else |
条件表达式 |
lambda |
lambda 表达式 |
:= |
赋值表达式 |
Pyhton3 已不支持 <>
运算符,可以使用 !=
代替
条件控制
if 语句
Python 中用 elif
代替了 else if
,所以 if 语句的关键字为:if – elif – else
注意:
- 每个条件后面要使用冒号
:
,表示接下来是满足条件后要执行的语句块 - 使用缩进来划分语句块,相同缩进数的语句在一起组成一个语句块
简单的 if 实例:
#!/usr/bin/python3
var1 = 100
if var1: # true
print("1 - if 表达式条件为 true")
print(var1)
var2 = 0
if var2: # false
print("2 - if 表达式条件为 true")
print(var2)
print("Good bye!")
狗的年龄计算判断:
#!/usr/bin/python3
age = int(input("请输入你家狗狗的年龄: "))
print("")
if age <= 0:
print("你是在逗我吧!")
elif age == 1:
print("相当于 14 岁的人。")
elif age == 2:
print("相当于 22 岁的人。")
elif age > 2:
human = 22 + (age - 2) * 5
print("对应人类年龄: ", human)
### 退出提示
input("点击 enter 键退出")
数字的比较运算:
#!/usr/bin/python3
# 该实例演示了数字猜谜游戏
number = 7
guess = -1
print("数字猜谜游戏!")
while guess != number:
guess = int(input("请输入你猜的数字:"))
if guess == number:
print("恭喜,你猜对了!")
elif guess < number:
print("猜的数字小了...")
elif guess > number:
print("猜的数字大了...")
if 嵌套
# !/usr/bin/python3
num = int(input("输入一个数字:"))
if num % 2 == 0:
if num % 3 == 0:
print("你输入的数字可以整除 2 和 3")
else:
print("你输入的数字可以整除 2,但不能整除 3")
else:
if num % 3 == 0:
print("你输入的数字可以整除 3,但不能整除 2")
else:
print("你输入的数字不能整除 2 和 3")
match
Python中的match语句是Python 3.10及以后版本中引入的新特性,用于模式匹配。
它允许你根据对象的模式来检查对象,并执行相应的代码块。
x = 2
match x:
case 1:
print(1)
case 2:
print(2)
case _:
print('other')
循环语句
Python 中的循环语句有 for
和 while
while 循环
同样需要注意冒号和缩进。另外,在 Python 中没有 do..while
循环。
无限循环
#!/usr/bin/python3
var = 1
while var == 1: # 表达式永远为 true
num = int(input("输入一个数字 :"))
print("你输入的数字是: ", num)
print("Good bye!")
无限循环在服务器上客户端的实时请求非常有用。
简单语句组
类似 if 语句的语法,如果你的 while 循环体中只有一条语句,你可以将该语句与 while 写在同一行中
#!/usr/bin/python
flag = 1
while (flag): print('欢迎访问菜鸟教程!')
print("Good bye!")
while-else
else的下级代码:
没有通过 break 退出循环,循环结束后,会执行的代码
num = 1
sum = 5
while num < 5:
sum += num
if sum == 10:
break
num += 1
else:
print('没有执行break语句')
for 语句
for 循环可以遍历任何可迭代对象,如一个列表或者一个字符串
break 语句用于跳出当前循环体
#!/usr/bin/python3
sites = ["Baidu", "Google", "Runoob", "Taobao"]
for site in sites:
if site == "Runoob":
print("菜鸟教程!")
break
print("循环数据 " + site)
else:
print("没有循环数据!")
print("完成循环!")
for-else
同 while-else
for i in range(5):
if i == 3:
print("Found 3, breaking the loop")
# break
print(i)
else:
print("Loop completed without breaking")
range() 函数
如果你需要遍历数字序列,可以使用内置 range()
函数。它会生成数列
# 指定上限,下限默认 0
for i in range(5): # [0,4]
print(i)
# 指定上下限
for i in range(5, 9): # [5,8]
print(i)
# 指定步长
for i in range(0, 10, 3): # {0,3,6,9}
print(i)
# 负数
for i in range(-10, -100, -30): # {-10,-40,-70}
print(i)
结合 range()
和 len()
函数以遍历一个序列的索引
a = ['Google', 'Baidu', 'Runoob', 'Taobao', 'QQ']
for i in range(len(a)):
print(i, a[i])
输出结果:
0 Google
1 Baidu
2 Runoob
3 Taobao
4 QQ
使用 range()
函数来创建一个列表
print(list(range(5))) # [0, 1, 2, 3, 4]
break 和 continue 语句及循环中的 else 子句
break 语句可以跳出 for 和 while 的循环体。如果你从 for 或 while 循环中终止,任何对应的循环 else 块将不执行。
continue 语句被用来告诉 Python 跳过当前循环块中的剩余语句,然后继续进行下一轮循环。
用于查询质数的循环例子:
#!/usr/bin/python3
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, '等于', x, '*', n // x)
break
else:
# 循环中没有找到元素
print(n, ' 是质数')
pass 语句
pass 是空语句,是为了保持程序结构的完整性。
pass 不做任何事情,一般用做占位语句
以下实例在字母为 o
时,执行 pass 语句块:
#!/usr/bin/python3
for letter in 'Runoob':
if letter == 'o':
pass
print('执行 pass 块')
print('当前字母 :', letter)
print("Good bye!")
输出结果为:
当前字母 : R
当前字母 : u
当前字母 : n
执行 pass 块
当前字母 : o
执行 pass 块
当前字母 : o
当前字母 : b
Good bye!
输入和输出
print 输出
print 默认输出是换行的,如果要实现不换行需要在变量末尾加上 end=""
#!/usr/bin/python3
x = "a"
y = "b"
# 换行输出
print(x)
print(y)
print('---------')
# 不换行输出
print(x, end=" ")
print(y, end=" ")
print()
执行结果为:
a
b
---------
a b
输出格式美化
Python 两种输出值的方式: 表达式语句和 print()
函数。
第三种方式是使用文件对象的 write()
方法,标准输出文件可以用 sys.stdout
引用。
如果你希望输出的形式更加多样,可以使用 str.format()
函数来格式化输出值。
如果你希望将输出的值转成字符串,可以使用 repr()
或 str()
函数来实现。
str()
: 函数返回一个用户易读的表达形式repr()
: 产生一个解释器易读的表达形式
s = 'Hello, Runoob'
print(str(s)) # Hello, Runoob
print(repr(s)) # 'Hello, Runoob'
print(str(1 / 7)) # 0.14285714285714285
x = 10 * 3.25
y = 200 * 200
s = 'x 的值为: ' + repr(x) + ', y 的值为:' + repr(y) + '...'
print(s) # x 的值为: 32.5, y 的值为:40000...
# repr() 函数可以转义字符串中的特殊字符
hello = 'hello, runoob\n'
hellos = repr(hello)
print(hellos) # 'hello, runoob\n'
# repr() 的参数可以是 Python 的任何对象
print(repr((x, y, ('Google', 'Runoob')))) # (32.5, 40000, ('Google', 'Runoob'))
两种方式输出一个平方与立方的表
for x in range(1, 11):
print(repr(x).rjust(2), repr(x * x).rjust(3), end=' ')
# 注意前一行 'end' 的使用
print(repr(x * x * x).rjust(4))
print("==============================")
for x in range(1, 11):
print('{0:2d} {1:3d} {2:4d}'.format(x, x * x, x * x * x))
字符串对象的 rjust()
方法, 它可以将字符串靠右, 并在左边填充空格。
还有类似的方法, 如 ljust()
和 center()
。 这些方法并不会写任何东西, 它们仅仅返回新的字符串。
另一个方法 zfill()
, 它会在数字的左边填充 0
,如下所示:
z = '12'.zfill(5)
print(z) # 00012
z = '-3.14'.zfill(7)
print(z) # -003.14
z = '3.14159265359'.zfill(5)
print(z) # 3.14159265359
str.format()
的基本使用如下:
print('{}网址: "{}!"'.format('菜鸟教程', 'www.runoob.com')) # 菜鸟教程网址: "www.runoob.com!"
在括号中的数字用于指向传入对象在 format()
中的位置,如下所示:
print('{0} 和 {1}'.format('Google', 'Runoob')) # Google 和 Runoob
print('{1} 和 {0}'.format('Google', 'Runoob')) # Runoob 和 Google
如果在 format()
中使用了关键字参数, 那么它们的值会指向使用该名字的参数。
print('{name}网址: {site}'.format(name='菜鸟教程', site='www.runoob.com'))
菜鸟教程网址: www.runoob.com
位置及关键字参数可以任意的结合:
>>> print('站点列表 {0}, {1}, 和 {other}。'.format('Google', 'Runoob', other='Taobao'))
站点列表 Google, Runoob, 和 Taobao。
!a
(使用 ascii()
), !s
(使用 str()
) 和 !r
(使用 repr()
) 可以用于在格式化某个值之前对其进行转化
可选项 :
和格式标识符可以跟着字段名。 这就允许对值进行更好的格式化
在 :
后传入一个整数,可以保证该域至少有这么多的宽度。 用于美化表格时很有用。
如果你有一个很长的格式化字符串,而你不想将它们分开, 那么在格式化时通过变量名而非位置会是很好的事情。
最简单的就是传入一个字典, 然后使用方括号 []
来访问键值
也可以通过在 table 变量前使用 **
来实现相同的功能:
import math
print('常量 PI 的值近似为: {}。'.format(math.pi)) # 常量 PI 的值近似为: 3.141592653589793。
# !r 使用 repr()
print('常量 PI 的值近似为: {!r}。'.format(math.pi)) # 常量 PI 的值近似为: 3.141592653589793。
# 可选项 : 和格式标识符可以跟着字段名
print('常量 PI 的值近似为 {0:.3f}。'.format(math.pi)) # 常量 PI 的值近似为 3.142。
# 在 : 后传入一个整数, 可以保证该域至少有这么多的宽度
table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
for name, number in table.items():
print('{0:10} ==> {1:10d}'.format(name, number))
"""
Google ==> 1
Runoob ==> 2
Taobao ==> 3
"""
# 传入一个字典, 然后使用方括号 [] 来访问键值
table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
print('Runoob: {0[Runoob]:d}; Google: {0[Google]:d}; Taobao: {0[Taobao]:d}'.format(table)) # Runoob: 2; Google: 1; Taobao: 3
# 也可以通过在 table 变量前使用 ** 来实现相同的功能
table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
print('Runoob: {Runoob:d}; Google: {Google:d}; Taobao: {Taobao:d}'.format(**table)) # Runoob: 2; Google: 1; Taobao: 3
老版本的字符串格式化
%
操作符也可以实现字符串格式化。 它将左边的参数作为类似 sprintf()
式的格式化字符串,而将右边的代入,然后返回格式化后的字符串
import math
print('常量 PI 的值近似为:%5.3f。' % math.pi) # 常量 PI 的值近似为:3.142。
因为 str.format()
是比较新的函数, 大多数的 Python 代码仍然使用 %
操作符。但是因为这种旧式的格式化最终会从该语言中移除, 应该更多的使用 str.format()
读取键盘输入
Python 提供了 input() 内置函数 从标准输入读入一行文本,默认的标准输入是键盘。
#!/usr/bin/python3
str = input("请输入:")
print("你输入的内容是: ", str)
命名空间和作用域
命名空间
命名空间(Namespace) 是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的。
命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。
一般有三种命名空间:
- 内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
- 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
- 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
命名空间查找顺序:
假设我们要使用变量 runoob
,则 Python 的查找顺序为:局部的命名空间 -> 全局命名空间 -> 内置命名空间
如果找不到变量 runoob
,它将放弃查找并引发一个 NameError
异常
命名空间的生命周期:
命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。
因此,我们无法从外部命名空间访问内部命名空间的对象。
# var1 是全局名称
var1 = 5
def some_func():
# var2 是局部名称
var2 = 6
def some_inner_func():
# var3 是内嵌的局部名称
var3 = 7
作用域
作用域就是一个 Python 程序可以直接访问命名空间的正文区域。
在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。
Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。
变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python 的作用域一共有4种,分别是:
有四种作用域:
- L(Local):最内层,包含局部变量,比如一个函数/方法内部。
- E(Enclosing):包含了非局部(non-local) 也非全局(non-global) 的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal
- G(Global):当前脚本的最外层,比如当前模块的全局变量。
- B(Built-in): 包含了内建的变量/关键字等,最后被搜索。
规则顺序: L –> E –> G –> B
在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。
g_count = 0 # 全局作用域
def outer():
o_count = 1 # 闭包函数外的函数中
def inner():
i_count = 2 # 局部作用域
内置作用域是通过一个名为 builtin
的标准模块来实现的,但是这个变量名自身并没有放入内置作用域内,所以必须导入这个文件才能够使用它。在 Python3.0 中,可以使用以下的代码来查看到底预定义了哪些变量:
>>> import builtins
>>> dir(builtins)
Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问
>>> if True:
... msg = 'I am from Runoob'
...
>>> msg
'I am from Runoob'
实例中 msg 变量定义在 if 语句块中,但外部还是可以访问的。
如果将 msg 定义在函数中,则它就是局部变量,外部不能访问
全局变量和局部变量
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。
局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中
#!/usr/bin/python3
total = 0 # 这是一个全局变量
# 可写函数说明
def sum(arg1, arg2):
# 返回2个参数的和."
total = arg1 + arg2 # total在这里是局部变量.
print("函数内是局部变量 : ", total) # 30
return total
# 调用sum函数
sum(10, 20)
print("函数外是全局变量 : ", total) # 0
global 和 nonlocal 关键字
当内部作用域想修改外部作用域的变量时,就要用到 global
和 nonlocal
关键字了。
#!/usr/bin/python3
num = 1
def fun1():
global num # 需要使用 global 关键字声明
print(num)
num = 123
print(num)
fun1()
print(num)
输出结果:
1
123
123
如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal
关键字了
#!/usr/bin/python3
def outer():
num = 10
def inner():
nonlocal num # nonlocal关键字声明
num = 100
print(num)
inner()
print(num)
outer()
输出结果:
100
100
有一种特殊情况:
#!/usr/bin/python3
a = 10
def test():
a = a + 1
print(a)
test()
以上程序执行,报错信息如下:
Traceback (most recent call last):
File "test.py", line 7, in <module>
test()
File "test.py", line 5, in test
a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment
错误信息为局部作用域引用错误,因为 test 函数中的 a 使用的是局部,未定义,无法修改。