这篇文章主要对以下Python基础语法的一些细节进行介绍.
- 语句和变量
- 对象和类型
- 数字和运算
- 条件和循环
- 函数和可调用对象
1. 语句和变量
1.1 语句折行
- 如果一行代码太长, 可以折成多行来写, 看起来会更清楚
- Python中, 如果一个语句被小括号, 中括号, 大括号包起来, 是可以跨行书写的
server = {
'ip' : '172.16.17.32',
'port' : 8080
}
- 如果没有用括号包起来, 可以使用
\来续行
x = 1
y = 2
if x == 1 and \
y == 2:
print("x and y are equal")
- 双引号
"和单引号'字符串, 都不能折行, 但是三引号'''/"""可以折行
print("""hello
world""")
- 使用
;可以把多个语句写到同一行. 但是强烈不建议这么做
x = 1; y = 3
print(x);print(y)
1.2 缩进规范
- Python中使用缩进表示语句块.
- 同一个语句块中的代码必须保证严格的左对齐(左边有同样数目的空格和制表符).
x = 0
if x == 1:
print(x)
x += 1 # 多缩进一个空格
#执行结果
# /main.py
# File "z:\gitee-study\Python\study\main.py", line 4
# x += 1
# IndentationError: unexpected indent
1.3 多重赋值(链式赋值)
- 可以同时给多个变量赋相同的值
x = y = 1
print(x)
print(y)
1.4 多元赋值
- 可以同时给多个变量赋不同的值
x, y = 1, 2
print(x)
print(y)
- 多元赋值很强大,比如交换两个变量
x, y = 1, 2
x,y = y,x
print(x)
print(y)
1.5 作用域和生命周期
- Python中, def, class, lamda(会改变变量的作用域
- if, else, elif, while, for, try/except不会改变变量的作用域
for i in range(0,10):
print(i)
print(i) # 出了for循环 仍然可以访问到i
def Func():
x = 1
print(x)
print(x) #出了def的函数语句块, 就不再能访问到x变量了
- 内建函数
globals()返回了全局作用域下都有哪些变量, 内建函数locals()返回了局部作用域下都有哪些变量
a = 1
def Func():
x = 0
print(globals())
print(locals())
Func()
print("--------------------------")
print(globals())
print(locals())
# 输出结果
# main.py
# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001F9C6DD6CD0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'z:\\gitee-study\\Python\\study\\main.py', '__cached__': None, 'a': 1, 'Func': <function Func at 0x000001F9C717F280>}
# {'x': 0}
# --------------------------
# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001F9C6DD6CD0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'z:\\gitee-study\\Python\\study\\main.py', '__cached__': None, 'a': 1,: 1, 'Func': <function Func at 0x000001F9C717F280>}
# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001F9C6DD6CD0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'z:\\gitee-study\\Python\\study\\main.py', '__cached__': None, 'a': 1, 'Func': <function Func at 0x000001F9C717F280>}
1.6 特殊标识符
- Python使用下划线
_作为变量的前缀和后缀, 来表示特殊的标识符 _xxx表示一个 "私有变量", 使用from module import *无法导入
# add.py
def _Add(x,y):
return x + y
# main.py
from add import *
print(_Add(1,2))
# 输出
# File "z:\gitee-study\Python\study\main.py", line 3, in <module>
# print(_Add(1,2))
# NameError: name '_Add' is not defined
_xxx_(前后一个下划线)和__xxx__(前后两个下划线) 一般是系统定义的名字. 我们自己在给变量命名时要 避开这种风格. 防止和系统变量冲突
1.7 文档字符串
- 多行注释,使用三引号
'''/"""在函数/类开始位置表示. 这个东西也被称为 文档字符串 - 使用对象的 doc 属性就能看到这个帮助文档了
def Add(x, y):
'''
define function for add two number
'''
return x + y
print(Add.__doc__) # 输出: define function for add two number
- 或者使用内建函数
help也可以做到同样的效果
def Add(x, y):
'''
define function for add two number
'''
return x + y
print(help(Add))
# 输出:
# Help on function Add in module __main__:
# Add(x, y)
# define function for add two number
# None
1.8 模块文档
- 不光一个函数/类可以有一个文档字符串. 一个模块也同样可以
# add.py
'''
define some function for add
'''
def Add(x,y):
return x + y
# main.py
import add
print(add.__doc__) # define some function for add
1.9 Uinx起始行
- 对于Linux或者Mac这类的Unix类系统, 可以给Python代码文件增加一个起始行, 用来指定程序的执行方式.
#!/usr/bin/python
print('haha')
- 和写bash脚本一样的
2. 对象和类型
2.1 一切都是对象
一个Python的对象, 包含三部分信息:
身份: 每一个对象都有一个唯一的身份标识自己. 实用内建函数id可以看到这个标识的具体的值.类型:对象的类型决定了对象保存什么样的值, 可以进行什么样的操作, 以及遵守什么样的规则. 实用内建函 数type可以查看对象的类型. 本质上就是把对象分分类.值: 表示对象中具体保存的内容. 有些对象的值可以修改, 有些对象的值不能修改, 这个称为对象的 "可变性"- Python中任何类型的值其实都是一个对象(判定一个东西是不是对象, 就尝试用id取一下看能否取到). 100 这样的字面值常量, 也是对象; 一个字符串, 也是对象; 一个函数, 也是对象; 一个类型(type函数的返回值), 其实也 是对象; 一个模块, 还是对象;
2.2对象和引用
以下面的代码为例:
a = 2
b = 3
b = 2
- 按照C语言中的理解, a = 2 , 相当于先创建一个变量名a, 给a分配了内存空间, 然后把数字2存到这块地址空间中.
- 但Python中完全不是这样的. 我们在解释器中敲入 a = 2 , 首先有一个 integer class 被唤醒(找到了整数对象的图纸)
- 根据 integer class 这个图纸, 在内存中开辟一段空间(得到了对象id), 并填充入对象的类型和值.
- 在创建变量b = 3,同样的方式进行创建
- 在执行b = 2 ,并不会把b的值修改为2.而是直接访问已经存在的type和value匹配的id.会直接访问对象a,
a = 2
print(id(a)) # 1998012574032
b = 3
print(id(b)) # 1998012574064
b = 2
print(id(b)) # 1998012574032
-
Python中的变量名, 只是一个访问对象的 "钥匙" . 多个不同的变量, 完全可以访问相同的对象, 因此这种变量名也叫对象的 "引用"
-
Python和C/C++的区别:
- 在 Python 中,变量并不直接存储数据。相反,变量名实际上是指向对象的引用(或指针)。当你写下
a = 2时,Python 会创建一个整数对象2,然后让a指向这个对象- 对象模型:所有的值(如
2、字符串、列表等)在 Python 中都是对象。每个对象在内存中都有一个固定的内存地址。 - 整数池(Interning) :对于一些小的、常用的对象(比如整数 -5 到 256、字符串等),Python 会使用 对象池 或 interning 技术来优化内存利用。例如,数字 2 在 Python 中可能只有一个实例,而其他变量指向这个实例。
- 对象模型:所有的值(如
- 在 C/C++ 中,变量通常是一个内存地址的标识符,并且直接存储数据。例如,当你写
int a = 2;时,a直接存储2的值在内存中。- 值传递:对于基础数据类型(如
int、float等),变量a存储的是实际的值。每次赋值时,都是复制值到新的内存位置(如果是基本数据类型的话)。 - 内存模型:C/C++ 更加接近硬件层面,变量通常直接表示内存中的位置,存储的是数据本身。
- 值传递:对于基础数据类型(如
- 在 Python 中,
a = 2只会有一个2对象存在,多个变量(如a和b)可以指向同一个对象。 - 在 C/C++ 中,变量
a和b会各自独立存储2,它们占用不同的内存空间,即使它们的值相同。
- 在 Python 中,变量并不直接存储数据。相反,变量名实际上是指向对象的引用(或指针)。当你写下
这种差异是由于 Python 是一个 动态类型语言,变量更像是对象的引用,而 C/C++ 是静态类型语言,变量直接存储数据。
2.3 对象和类型
- 有些对象是 "相似" 的, 于是我们把对象可以进行归类. 比如把所有的整数归为一类, 把所有的浮点数对象归为一类, 把所有的字符串归为一类.
- 相同的类型的对象, 须有相同的操作. 比如, 所有的整数对象, 都可以进行加减乘除操作. 所有的字符串都可 以使用切片操作.
- Python是一种动态强类型编程语言.
- 动态是指运行时进行变量类型检查; 强类型指类型检查严格, 并且"偏向于"不允许隐式转换
2.3.1 标准类型
- 整型
- 浮点型
- 复数型
- 布尔型
- 字符串
- 列表
- 元组
- 字典
2.3.2 其他内建类型
- 类型
- 类型也是对象
print(type(type(100))) # <class 'type'>
print(id(type(100))) # 140703443525584
- Null对象(None)
- Python有一个特殊的类型, 称为NoneType. 这个类型只有一个对象, 叫做None
print(type(None)) # <class 'NoneType'>- NoneType类似于C语言中的void
- None类似于C语言的空指针NULL
- None这个对象没啥有用的属性, 它的布尔值为False
- 文件
- 函数
- 模块
- 类
2.3.3 内建类型的布尔值
- 所有的标准对象, 均可以用于布尔测试(放到if条件中).
- 下列对象的布尔值是False
- None
- False
- 所有值为0的数字(0, 0.0, 0.0 + 0.0j)
- "" (空字符串)
- [] (空列表)
- () (空元组)
- {} (空字典)
- 其他情况下, 这些内建对象的布尔值就是True
2.3.4 对象值的比较
- 所有内建类型对象都可以进行比较操作来进行值比较.(比较的双方必须是相同类型).
- 比较运算的结果是True或者False.
- 比较运算符包括 ==, !=, <, >, <=, >=
2.3.5 对象身份的比较
- 变量名只是对象的一个引用. 那么两个变量名是否指向同一个对象呢?
- 可以使用 id 这个内建函数来比较,如果id的值相同, 说明是指向同一个对象
a = 100
b = a
print(id(a) == id(b)) # True
- Python还提供了
is和is not关键字, 直接进行判定
a = 100
b = a
print(a is b ) # True
print(a is not b) # False
2.3.6 对象类型比较
- 两个对象比较类型是否相同, 可以使用内建函数type
a = 100
print(type(a) == type(100)) # True
- Python还提供了一个内建函数
isinstance用来判断两个类型是否相同
a = []
print(isinstance(a,list)) # True
a = 100
print(isinstance(a,type(100))) # True
2.3.7 类型工厂函数
- 常见的类型工厂函数
| 函数 | 描述 | 示例 |
|---|---|---|
int() | 将对象转换为整数类型(如果可能的话)。 | int("123") → 123 |
float() | 将对象转换为浮点数类型(如果可能的话)。 | float("3.14") → 3.14 |
str() | 将对象转换为字符串类型。 | str(100) → "100" |
list() | 将可迭代对象转换为列表类型。 | list((1, 2, 3)) → [1, 2, 3] |
tuple() | 将可迭代对象转换为元组类型。 | tuple([1, 2, 3]) → (1, 2, 3) |
set() | 将可迭代对象转换为集合类型。 | set([1, 2, 3, 3]) → {1, 2, 3} |
dict() | 创建一个字典,通常通过键值对的可迭代对象创建。 | dict([("a", 1), ("b", 2)]) → {'a': 1, 'b': 2} |
bool() | 将对象转换为布尔类型。 | bool("") → False |
complex() | 将对象转换为复数类型,接受两个参数,实部和虚部。 | complex(3, 4) → (3+4j) |
int(): 将字符串、浮点数等转换为整数,通常会舍弃小数部分。float(): 将字符串、整数等转换为浮点数。str(): 将其他类型的对象转换为字符串形式。list(): 将可迭代对象(如元组、字符串)转换为列表。tuple(): 将可迭代对象(如列表、字符串)转换为元组。set(): 将可迭代对象转换为集合,集合会去除重复的元素。dict(): 从键值对创建字典,通常接受键值对的可迭代对象(如元组)。bool(): 转换为布尔类型,空值、0、None等为False,其他为True。complex(): 将两个数值转换为复数类型,第一个是实部,第二个是虚部。
2.3.8 Python不支持的类型
- char, byte: 可以使用长度为1的字符串, 或者整数代替;
- 指针: Python替你管理内存, 虽然id()返回的值接近于指针的地址, 但是并不能主动去修改;
- int/short/long: 以前版本的Python中也是区分int和long的, 但是后来统一在一起了; 记住Python中的整数 表示的范围, 只取决于你机器内存的大小.
- float/double: Python的float其实就是C语言的double. Python设计者认为没必要支持两种浮点数
3. 数字和运算
3.1 整数的位运算
- Python 整数的位运算
在 Python 中,整数支持位运算(bitwise operations),这些运算直接操作整数的二进制位。常见的位运算符包括按位与、按位或、按位异或、按位取反、左移和右移。
| 运算符 | 描述 | 示例代码 | 示例输出 |
|---|---|---|---|
& | 按位与:只有两位都是 1 时,结果为 1 | a = 5; b = 3; result = a & b | 1 (二进制: 001) |
^ | 按位异或:两位不同时,结果为 1 | a = 5; b = 3; result = a ^ b | 6 (二进制: 110) |
~ | 按位取反:将 1 变 0,0 变 1 | a = 5; result = ~a | -6 (二进制: ...11111010) |
<< | 左移:将二进制位向左移动,等同于乘以 2^n | a = 5; result = a << 1 | 10 (二进制: 1010) |
>> | 右移:将二进制位向右移动,等同于除以 2^n | a = 5; result = a >> 1 | 2 (二进制: 10) |
-
说明
-
按位与 (
&):只有两个数字的相同位都是1时,结果才为1,否则为0。 -
按位或 (
|):只要两个数字的相同位中有一个是1,结果就为1。 -
按位异或 (
^):只有两个数字的相同位不同(一个是1,另一个是0)时,结果才为1。 -
按位取反 (
~):将每个二进制位反转(1变0,0变1),对于有符号整数,结果为-(x + 1),其中x是原始值。 -
左移 (
<<):将数字的二进制位向左移动,等同于乘以2^n,其中n是移动的位数。 -
右移 (
>>):将数字的二进制位向右移动,等同于除以2^n,其中n是移动的位数。
3.2 常用内置函数/模块
- abs: 求一个数的绝对值.
- divmod: 返回一个元组, 同时计算商和余数
a,b = divmod(10,3)
print(a) # 3
print(b) # 1
- str: 将数字转换成字符串.
- round: 对浮点数进行四舍五入. round有两个参数, 第一个是要进行运算的值, 第二个是保留小数点后多少位
import math
for i in range(0,10):
print(round(math.pi,i))
# 输出:
# 3.0
# 3.1
# 3.14
# 3.142
# 3.1416
# 3.14159
# 3.141593
# 3.1415927
# 3.14159265
# 3.141592654
- 整数进制转换: oct(), hex(), 参数是一个整数, 返回值是对应字面值的字符串.
| 函数 | 描述 | 示例代码 | 输出 |
|---|---|---|---|
bin() | 将整数转换为二进制字符串 | bin(10) | '0b1010' |
oct() | 将整数转换为八进制字符串 | oct(10) | '0o12' |
hex() | 将整数转换为十六进制字符串 | hex(255) | '0xff' |
number = 42
# 转换为二进制、八进制、十六进制
binary = bin(number) # 二进制
octal = oct(number) # 八进制
hexa = hex(number) # 十六进制
print(f"Binary: {binary}, Octal: {octal}, Hexadecimal: {hexa}") # Binary: 0b101010, Octal: 0o52, Hexadecimal: 0x2a
- math/cmath模块: 提供一些方便的数学运算的函数. math是常规数学运算; cmath是复数运算;
| 函数 | 功能 | 语法 | 参数说明 | 返回值说明 | 示例 |
|---|---|---|---|---|---|
sqrt(x) | 返回 x 的平方根 | math.sqrt(x) | x: 非负实数 | 返回 x 的平方根 | math.sqrt(16) 输出: 4.0 |
factorial(x) | 返回 x 的阶乘 | math.factorial(x) | x: 非负整数 | 返回 x 的阶乘 | math.factorial(5) 输出: 120 |
sin(x), cos(x), tan(x) | 三角函数 | math.sin(x) | x: 弧度 | 返回对应的三角函数值 | math.sin(math.pi / 2) 输出: 1.0 |
| 函数 | 功能 | 语法 | 参数说明 | 返回值说明 | 示例 |
|---|---|---|---|---|---|
sqrt(x) | 返回复数 x 的平方根 | cmath.sqrt(x) | x: 复数 | 返回复数 x 的平方根 | cmath.sqrt(1 + 1j) 输出: (1.09868411346781+0.4550898605622279j) |
phase(x) | 返回复数 x 的相位角(弧度) | cmath.phase(x) | x: 复数 | 返回复数的相位角 | cmath.phase(1 + 1j) 输出: 0.7853981633974483 |
polar(x) | 返回复数 x 的极坐标表示 | cmath.polar(x) | x: 复数 | 返回复数的模和相位(极坐标) | cmath.polar(1 + 1j) 输出: (1.4142135623730951, 0.7853981633974483) |
- 随机数random模块
| 函数 | 功能 | 语法 | 参数说明 | 返回值说明 | 示例 |
|---|---|---|---|---|---|
random() | 生成一个 [0.0, 1.0) 范围的随机浮点数 | random.random() | 无参数 | 返回一个浮动值,范围 [0.0, 1.0) | random.random() 输出: 0.5377851432190762 |
randint(a, b) | 生成一个 [a, b] 范围的随机整数 | random.randint(a, b) | a, b: 整数 | 返回一个整数,范围为 [a, b] | random.randint(1, 10) 输出: 7 |
choice(sequence) | 从序列中随机选择一个元素 | random.choice(sequence) | sequence: 可迭代对象 | 从序列中返回一个随机元素 | random.choice(['apple', 'banana', 'cherry']) 输出: 'banana' |
shuffle(sequence) | 打乱序列中的元素 | random.shuffle(sequence) | sequence: 可迭代对象 | 将序列中的元素打乱 | random.shuffle(['apple', 'banana', 'cherry']) 输出: ['cherry', 'apple', 'banana'] |
4. 条件和循环
4.1 缩进和悬挂else
- 在C语言中,下面这段代码
if (x > 0)
if (y > 0)
printf("x > 0 and y > 0\n");
else
printf("x < = 0");
- 在C语言中, 如果不使用{ }来标明代码块, else会和最近的if匹配. 就意味着上面的else, 执行的逻辑其实是 y <= 0 . 在Python中, 就需要使用不同级别的缩进来标明, 这个else和哪个if是配对的.
x = 0
y = 0
if x > 0:
if y > 0:
print('x and y > 0')
else: # 和 x > 0 匹配
print('x <= 0')
x = 0
y = 0
if x > 0:
if y > 0:
print('x and y > 0')
else: # 和 y > 0 匹配
print('x > 0 and y <= 0')
4.2 条件表达式
- Python中并没有 ? : 这样的三目运算符, 理由是Python设计者觉得这个玩意太丑 T_T
- 取而代之的是, 一种叫做条件表达式的东西.
x, y, smaller = 3, 4, 0
if x < y :
smaller = x
else:
smaller = y
# 用条件表达式:
smaller = x if x < y else y
4.3 和循环搭配的else
- else不光可以和if搭伙, 还能和while, for搭伙
# for item in iterable:
# # 循环体
# if condition:
# break
# else:
# # 循环正常结束后执行
nums = [1,2,3,4,5]
target = 6
for i in nums:
if i == target:
print(f"index = {i}")
break
else:
print(f"none index = {i}")
# while condition:
# # 循环体
# if condition_to_break:
# break
# else:
# # 循环正常结束后执行
# 示例: 使用 while 循环查找一个数字
counter = 0
target = 5
while counter < 10:
counter += 1
if counter == target:
print(f"找到了目标 {target}")
break
else:
print(f"没有找到目标 {target}")
- 注意, 和循环搭配的else子句, 只会在循环条件不满足的时候才会执行(对于for来说就是整个序列遍历完成). 如果循环中途break了, 仍然会跳过else
5. 函数和可调用对象
5.1 函数定义和调用
- 使用def关键字定义一个函数
- 函数的定义只是创建了一个函数, 并没有执行函数体中的代码. 要在真正进行函数调用时, 才执行函数体中的代码.
# 函数定义
def Func():
print("Func()")
# 函数调用
Func()
- 函数的定义也可以放在其他函数内部~. 但是这样函数的作用域也就只是在函数内部才有效了
def Func1():
def Func2():
print('Hello')
Func2()
Func2()
# Traceback (most recent call last):
# File "z:\gitee-study\Python\study\main.py", line 6, in <module>
# Func2()
# NameError: name 'Func2' is not defined
5.2 函数的参数
- 函数定义时, 可以在 () 中填入这个函数都需要接受哪些参数. 注意, 此处不需要指定参数类型
- Python是动态类型语言, 所以在你写下代码的时候, 解释器并不知道参数的类型是什么. 而是在运行时(调用 函数的时候)函数才知道了类型
def Func(x):
print(x)
Func(1) # 1
Func("Hello") # Hello
Func([1,2,3]) # [1, 2, 3]
- 只要传入的参数, 能够支持函数体中的各种操作就可以了. 否则就会运行时报错.
def Add(x,y):
return x + y
print(Add(1,2)) # 3
print(Add('Hello',"world")) # Helloworld
print(Add([1,2,3],[4,5,6])) # [1,2,3,4,5,6]
print(Add(1,"Hello")) # error
- 定义函数时, 支持给函数指定默认参数. 这样如果调用函数时不显式的指定参数, 就会使用默认参数作为参数值.
- 默认参数是非常有用的, 尤其是一些库的接口, 可能需要传入很多参数, 那么默认参数就可以帮我们减轻使用负担.
- 对于多个默认参数的函数, 可以按照顺序给函数的某几个参数进行传参
def Func(x = 10,y = 20, z = 30):
print(x,y,z)
Func() # 10 20 30
Func(100) # 100 20 30
5.3 关键字参数
- 当我们有多个默认参数, 同时又只想传其中的某几个的时候, 还可以使用关键字参数的方式进行传参.
- 例如内建函数 sorted (用来给序列进行排序), 函数原型为:
sorted(iterable[, cmp[, key[, reverse]]])
- 函数有四个参数. 第一个参数表示传入一个可迭代的对象(比如列表, 字符串, 字典等); 剩余三个参数都具备默认参数, 可以不传.
a = [1,4,3,6]
print(sorted(a)) # [1, 3, 4, 6]
- 对于这几个默认参数, 可以通过现实的指定关键字, 来说明接下来这个参数是传给哪个参数.
- sorted可以支持自定制排序规则
# 1. 逆序排序
a = [1,4,3,6]
print(sorted(a,reverse = True)) # [6, 4, 3, 1]
# 2. 按元素的绝对值排序
a = [1,3,4,2]
print(sorted(a,key = abs))
# 3. 按字符串长度
a = ['aa','bbbb','c']
print(sorted(a,key = len))
- 和其他编程语言不同, Python的函数形参, 变量名不是随便写的. 尤其是一个默认参数的时候, 形参名可能会随时被拎出来, 作为关键字参数协助函数调用时传入实参.
5.4 参数组
- 还可以将一个元组或者字典, 作为参数组, 来传给函数. 这样就可以帮助我们实现 "可变长参数"
- 通过将参数名前加一个
*号,*之后的内容表示是一个元组.
def Log(prefix,*data):
print(prefix)
# 提取参数 (遍历数组即可)
for i in range(0,len(data)):
print(data[i])
# 提取参数
print(prefix + '\t'.join(data))
Log('[INFO]',"hello","world")
- 通过在参数名前加两个星号
**, 星号后面的部分表示传入的参数是一个字典. 这时候调用函数就可以按照关键字参数的方式传参了.
def Log(prefix, **data):
print(prefix +'\t'.join(data.values())) #[INFO]127.0.0.1 80 1234
Log('[INFO]', ip = '127.0.0.1', port = '80', userid = '1234')
5.5 函数重载
- 如果Python中有两个相同名字的函数,但是参数不同,这种在C++中构成函数重载的情况.在python中并不会构成重载
def Func():
print("1")
def Func(x = 1):
print("2")
Func() # 2
- 因为在Python中,函数也是对象. 代码中定义两个相同名字的函数, 这样的操作类似于
a = 1
a = 2
print(a) # 2
- 相当于是对Func这个变量重新进行了绑定
- Python不支持重载归根结底是为了同一个函数, 能够适应几种不同类型的输入数据.
- 重载的关键词有两个: 不同参数类型; 不同参数数目.
- Python的变量类型是在运行时检查的, 同一个函数, 就已经可以处理不同类型的参数了.
- 通过参数组和默认参数, 解决处理不同数目的参数的能力.
- 通过关键字参数, 也极大的加强了传参的灵活性, 而不比像C++那样只能按顺序传参.
- 所以Python完全没有任何必要再去支持 "重载" 这样的语法了. 包括后续出现的一系列动态类型语言, 都不再支持重载了.
5.6 函数返回值
- 通过return关键字返回一个对象.
- 如果没有return 语句 ,则返回None对象
- 可以同时返回N个对象, 通过分割(本质上是在返回一个元组)
def Func():
print("Hello World")
print(Func())
# 输出:
# Hello World
# None
5.7 函数也可以做为函数的参数
- 函数也是一个对象, 因此可以作为其他函数的参数
- 以sorted函数为例, 给一个序列进行排序. 这个函数可以支持自定制比较规则.
a = [1,3,4,2]
print(sorted(a)) # [1,2,3,4]
from functools import cmp_to_key
a = [1,-3,4,2]
# 自定义比较规则
def Cmp(x,y):
if abs(x) < abs(y):
return -1
elif abs(x) > abs(y):
return 1
else:
return 0
print(sorted(a,key=cmp_to_key(Cmp))) # [1, 2, -3, 4]