Java好久没看了,暂时放一放,先做实验。
简单回顾一下python知识。
数据类型
常见数据类型:整数、浮点数、字符串、布尔值、空值
整数
Python允许在数字中间以_
分隔:1000_0000
。
运算:/
:除法;//
:地板除/整除;%
:去余
- 十进制:
123
- 二进制:
0b1111011
- 八进制:
0o173
- 十六进制:
0x7b
浮点数
浮点数支持科学计数法:1.23e9
或1.23e-8
字符串
用''
或""
括起来表示字符串。
转义字符:\
Python允许用r''
表示''
内部的字符串默认不转:
>>> print('\\\t\\')
\ \
>>> print(r'\\\t\\')
\\\t\\
可以用'''...'''
表示多行文本:
print('''line1
line2
line3''')
# line1
# line2
# line3
布尔值
布尔值只有True
、False
两个值。
常用逻辑运算:and
、or
、not
空值
空值用none
表示
字符串和编码
字符集
常用编码:ASCII(1字节)、Unicode(2字节)、UTF-8(可变长:1-6字节)
字符 | ASCII | Unicode | UTF-8 |
---|---|---|---|
A | 01000001 | 00000000 01000001 | 01000001 |
中 | x | 01001110 00101101 | 11100100 10111000 10101101 |
字符串
ord()
函数获取字符的整数表示
chr()
函数把编码转换为对应的字符
>>> ord('A')
65
>>> ord('中')
20013
>>> chr(66)
'B'
>>> chr(25991)
'文'
Python的字符串类型是str
,在网络上传输,或者保存时,需要把str变为以字节为单位的bytes
encode()
函数将str
编码为指定的bytes
decode()
函数把bytes
转换为对应的str
>>> 'abc'.encode()
b'abc'
>>> '流樱'.encode()
b'\xe6\xb5\x81\xe6\xa8\xb1'
>>> b'abc'.decode()
'abc'
>>> b'\xe6\xb5\x81\xe6\xa8\xb1'.decode()
'流樱'
格式化输出
- 使用%占位符:
%d
:整数;%f
:浮点数;%s
:字符串;%x
:十六进制整数 - 使用format()方法:使用
{0}
、{1}
占位,使用format()填入参数>>> 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125) 'Hello, 小明, 成绩提升了 17.1%'
- 使用f-string:以f开头的字符串,称为f-string,字符串中,就会替换为对应的变量
>>> name = '小明' >>> print(f'hello {name}') hello 小明
常用容器
- list:是一种有序、可变的集合
- append():在队尾添加元素
- pop():删除队尾的元素
- insert(inx, value):在指定的位置添加元素
- tuple:是一种有序、不可变的集合
- tuple的元素可以包含list
- 定义只有1个元素的tuple时要加逗号
,
,消除歧义:(1,)
- dict:是一种无序的键值对集合,查找速度快
- 可以通过in判断key是否存在
- get()方法,可以根据key获取值,若key不存在,可以返回None,或者指定的value:
d.get('key', -1)
- pop()方法,可以删除指定key对应的键值对
- dict的key必须是不可变对象,list不能作为key
- set:是一种无序、不重复的集合
- set类似只存储key的dict,所以也不能存入可变对象(如list)
- add()方法:添加元素
- remove()方法:删除元素
流程控制
条件判断
if
、elif
、else
if a > 0:
print(a)
elif:
print(0)
else:
print(-a)
循环
for...in
、while
names = ['Michael', 'Bob', 'Tracy']
for name in names:
print(name)
sum = 0
n = 99
while n > 0:
sum = sum + n
n = n - 2
print(sum)
函数
定义函数
def 函数名(参数):
def my_abs(x):
if x >= 0:
return x
else:
return -x
pass
想定义一个什么事也不做的空函数,可以用pass语句:
pass可以用来作为占位符,还没想好怎么写函数的代码时,可以放一个pass,让代码能运行起来。
def nop():
pass
pass还可以用在其他语句里,比如:
if age >= 18:
pass
缺少了pass,代码运行就会有语法错误。
返回多值
python函数返回多个值时,使用tuple作为返回值。
>>> import math
>>> def quadratic(a,b,c):
... x = -b
... y = math.sqrt(b*b - 4*a*c)
... z = 2*a
... rst1 = (x + y) / z
... rst2 = (x - y) / z
... return rst1, rst2
...
>>> print('quadratic(2, 3, 1) =', quadratic(2, 3, 1))
quadratic(2, 3, 1) = (-0.5, -1.0)
>>> print('quadratic(1, 3, -4) =', quadratic(1, 3, -4))
quadratic(1, 3, -4) = (1.0, -4.0)
函数的参数
- 位置参数:
def power(x, n):pass
- 默认参数:
def power(x, n=2):pass
- 默认参数可以简化函数的调用
- 必选参数在前,默认参数在后
- 默认参数必须指向不变对象
- 可变参数:
def calc(*numbers):pass
- 传入的参数个数是可变的,可变参数会组装为一个tuple
- 在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:
calc(*nums)
- 关键字参数:
def person(name, age, **kw):pass
- 关键字参数允许传入0个或任意个含参数名的参数,关键字参数会组装为一个dict
- 在dict前面加两个*号,把dict的key-value变成关键字参数传进去:
person('Jack', 23, **info)
- kw获得的dict是info的拷贝,对kw的改动不会影响到函数外的extra
- 命名关键字参数:
def person(name, age, *, city, job):pass
- 用于限制关键字参数的名字,只接收city和job作为关键字参数,同时可以提供默认值
- 命名关键字参数需要特殊分隔符*,*后面的参数为命名关键字参数
- 如果函数定义中已经有了一个可变参数,后面的命名关键字参数就不再需要*了:
def person(name, age, *args, city, job):pass
- 命名关键字参数必须传入参数名
参数组合
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。
但是,参数定义的顺序必须是:
必选参数 > 默认参数 > 可变参数 > 命名关键字参数 > 关键字参数
def f1(a, b, c=0, *args, **kw):pass
def f2(a, b, c=0, *, d, **kw):pass
def mul(*args):
if len(args) == 0:
raise TypeError('no args')
num = 1
for arg in args:
num *= arg
return num
虽然可以组合多达5种参数,但不要同时使用太多的组合,否则函数接口的可理解性很差。
递归函数
递归函数:在函数内部调用自身本身的函数。
例如,可以用递归实现累加:
def sum(x):
if x == 1:
return 1
return x + sum(x - 1)
递归函数的优点是定义简单,逻辑清晰。
理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
使用递归函数需要注意防止栈溢出。
解决递归调用栈溢出的方法是通过尾递归优化。
尾递归:在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。
这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
使用尾递归优化累加函数:
def sum(n):
return sum_iter(n, 0)
def sum_iter(num, product):
if num == 0:
return product
return sum_iter(num - 1, num + product)
其中,return sum_iter(num - 1, num + product)
仅返回递归函数本身。
num - 1
和num + product
在函数调用前就会被计算,不影响函数调用。
递归经典:汉诺塔
思路:
- 如果是1个盘子,直接将A柱子上的盘子从A移到C
- 大于1个盘子:
- 先将A柱子上的n-1个盘子借助C移到B
- 直接将A柱子上的盘子从A移到C
- 最后将B柱子上的n-1个盘子借助A移到C
实现:
def move(n, a, b, c):
if n == 1:
print(a, '-->', c)
else:
move(n-1, a, c, b)
move(1, a, b, c)
move(n-1, b, a, c)