MYF

Python学习笔记

本文内容(文字及代码)部分摘录自廖雪峰的Python教程

本课程学习时间:2016.2.12~? 累计学习时间4h0min(每次学习后再加)

Python基础

数据类型和变量

分为整数、浮点数、字符串、布尔型、空值(None)

转义字符表示方式:

1
2
3
4
# 转义字符'\'表示方式
'I\'m \"OK\"!' #输出:I'm "OK"!
# 用r''表示''内部的字符串默认不转义
print(r'\\\t\\') #输出:\\\t\\

多行内容表示方式’’’…’’’

1
2
3
4
5
6
7
>>>print('''line1
... line2
... line3''')
#output:
line1
line2
line3

除法运算:

1
2
3
4
5
6
7
8
# / 结果为浮点数
>>> 9/3
3.0
>>> 10/3
3.3333333333333335
# // 结果为整数
>>> 10//3
3

字符串和编码

字符编码

  • ASCII:只有127个字母被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码
  • Unicode:统一的一套编码,存储上比ASCII编码需要多一倍的存储空间
  • UTF-8:UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。

Python的字符串

在最新的Python 3版本中,字符串是以Unicode编码的

Unicode码的获取与转换

  • ord():获取字符的整数表示

    1
    2
    3
    4
    >>> ord('A')
    65
    >>> ord('中')
    20013
  • chr():获取编码对应的字符

    1
    2
    3
    4
    >>> chr(66)
    'B'
    >>> chr(25991)
    '文'

编码的转换

前缀b的使用
1
2
x = 'ABC'	# str类型: 在内存中以Unicode表示,一个字符对应若干个字节
y = b'ABC' # bytes: 每个字符都只占用一个字节,网络传输和磁盘保存的格式
encode()

以Unicode表示的str通过encode()方法可以编码为指定的bytes

1
2
3
4
5
6
7
8
>>> 'ABC'.encode('ascii')
b'ABC'
>>> '中文'.encode('utf-8')
b'\xe4\xb8\xad\xe6\x96\x87'
>>> '中文'.encode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
decode()

从网络或磁盘上读取了字节流变为Unicode的str

1
2
3
4
>>> b'ABC'.decode('ascii')
'ABC'
>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
'中文'
len()

对于str,计算包含多少个字符。对于bytes,计算包含多少个字节。

1
2
3
4
5
6
>>> len('中文')
2 # 2个字符
>>> len(b'\xe4\xb8\xad\xe6\x96\x87')
6 # 6个字符
>>> len('中文'.encode('utf-8'))
6 # 等价于上一个

UTF-8的使用

为了避免乱码问题,应当始终坚持使用UTF-8编码对strbytes进行转换。

1
2
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释;

第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码。

格式化

在Python中,采用的格式化方式和C语言是一致的,用%实现,举例如下:

1
2
3
4
5
6
7
8
>>> 'Hello, %s' % 'world'
'Hello, world'
>>> 'Hi, %s, you have $%d.' % ('Michael', 1000000)
'Hi, Michael, you have $1000000.'
>>> '%2d-%02d' % (3, 1) # 补空格、补零
' 3-01'
>>> '%.2f' % 3.14159 # 固定保留位数
'3.14'
占位符 含义
%d 整数
%f 浮点数
%s 字符串
%x 十六进制整数
%% 百分号%

使用list和tuple

list(可变有序集合)

Python内置的一种数据类型是列表:list。list是一种有序的集合,可以随时添加和删除其中的元素。索引范围为0~len(LIST)-1也可以为-1~-len(LIST)

classmates Michael Bob Tracy
表示方法1 0 1 2(len-1)
表示方法2 -3(-len) -2 -1
1
2
3
4
5
6
7
8
9
10
11
12
13
>>> classmates = ['Michael', 'Bob', 'Tracy']
>>> classmates
['Michael', 'Bob', 'Tracy']
>>> classmates[0]
'Michael'
>>> classmates[1]
'Bob'
>>> classmates[2]
'Tracy'
>>> classmates[1] = 'Sarah' # 元素的替换
>>> L = ['Apple', 123, True] # 元素类型可不同
>>> s = ['python', 'java', ['asp', 'php'], 'scheme'] # list类型的对象可以作为list的一个元素
>>>

len()函数

求list的长度

1
2
3
4
>>> classmates
['Michael', 'Bob', 'Tracy']
>>> len(classmates)
3

append()

尾部添加

1
2
3
4
5
>>> classmates
['Michael', 'Bob', 'Tracy']
>>> classmates.append('Adam')
>>> classmates
['Michael', 'Bob', 'Tracy', 'Adam']

insert()

把元素插入到指定的位置,比如索引号为1的位置:

1
2
3
4
5
>>> classmates
['Michael', 'Bob', 'Tracy', 'Adam']
>>> classmates.insert(1, 'Jack')
>>> classmates
['Michael', 'Jack', 'Bob', 'Tracy', 'Adam']

pop()

删除尾部元素
1
2
3
4
5
6
>>> classmates
['Michael', 'Bob', 'Tracy', 'Adam']
>>> classmates.pop()
'Adam'
>>> classmates
['Michael', 'Bob', 'Tracy']
删除指定位置的元素
1
2
3
4
5
6
>>> classmates
['Michael', 'Jack', 'Bob', 'Tracy']
>>> classmates.pop(1)
'Jack'
>>> classmates
['Michael', 'Bob', 'Tracy']

tuple(不可变有序集合)

tuple和list非常类似,但是tuple一旦初始化就不能修改。classmates这个tuple不能变了,它也没有append()insert()这样的方法,其他获取元素的方法和list是一样的。不可变的tuple有什么意义?因为tuple不可变,所以代码更安全。如果可能,能用tuple代替list就尽量用tuple。

tuple的陷阱:当你定义一个tuple时,在定义的时候,tuple的元素就必须被确定下来:

1
2
3
>>> t = (1, 2)
>>> t
(1, 2)

要定义一个只有1个元素的tuple,如果你这么定义:

1
2
3
>>> t = (1)
>>> t
1

定义的不是tuple,是1这个数!这是因为括号()既可以表示tuple,又可以表示数学公式中的小括号,这就产生了歧义,因此,Python规定,这种情况下,按小括号进行计算,计算结果自然是1。

所以,只有1个元素的tuple定义时必须加一个逗号,,来消除歧义:

1
2
3
>>> t = (1,)
>>> t
(1,)

Python在显示只有1个元素的tuple时,也会加一个逗号,,以免你误解成数学计算意义上的括号。

帮助你深入理解tuple和list:“可变的”tuple。这部分内容请参阅廖雪峰的python教程

条件判断

条件判断

if-elif-else

1
2
3
4
5
6
7
age = 20
if age >= 6:
print('teenager')
elif age >= 18:
print('adult')
else:
print('kid')

特别地,如果x为非零数值、非空字符串、非空list等,则判断为True,否则判断为False:

1
2
3
4
if x:
print('True')
else:
print('False')

再议 input

input的输入类型为str,如果输入数字进行比较则会报错,应使用int()函数,示例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# test1.py
if birth<2000:
print('00前')
else:
print('00后')
>>>birth:1982
Traceback (most recent call last):
File "test1.py", line 4, in <module>
if birth<2000:
TypeError: unorderable types: str() < int()

# test2.py
birth = int(s)
if birth<2000:
print('00前')
else:
print('00后')
>>>birth:1984
00

int()可以将str类型的变量转化为int类型变量,但是如果str内变量无法转换成一个int时,则会报错,如下:

1
2
3
4
>>> int('abc')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'abc'

循环

for-in

1
2
3
4
# 遍历一个list
names = ['Michael', 'Bob', 'Tracy']
for name in names:
print(name)

输出:

1
2
3
Michael
Bob
Tracy

range()函数

语法: range(x, y),表示一个[x, y)区间,x缺省为0

1
2
3
4
5
6
>>> range(5)
range(0, 5)
>>> range(1,5)
range(1, 5)
>>> list(range(1,5)) # 强制转化为list类型
[1, 2, 3, 4]

range(101)就可以生成0-100的整数序列,计算如下:

1
2
3
4
sum = 0
for x in range(101):
sum = sum + x
print(sum)

while

1
2
3
4
5
6
sum=0
n=100
while n>0:
sum=sum+n
n=n-1
print(sum)

使用dict和set

dict

dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。

1
2
3
4
>>> d = {'Michael':95, 'Bob':75, 'Tracy':85}
>>> d['Michael']
95
>>> d['Adam'] = 67 # 直接添加的方式

一个key只对应一个value,后加入的value会替代原来的value

1
2
3
4
5
6
>>> d['Jack'] = 90
>>> d['Jack']
90
>>> d['Jack'] = 88
>>> d['Jack']
88

如key不存在,则报错,如

1
2
3
4
>>> d['Thomas']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'Thomas'

in

使用in确定该key值是否存在于该dict中

1
2
3
4
>>> 'Thomas' in d
False
>>> 'Tracy' in d
True

get

使用get方法确定value

1
2
3
4
5
>>> d.get('Tracy')
85
>>> d.get('Thomas') # 返回值为none,在python的交互式命令行不显示结果
>>> d.get('Thomas','not exist')
'not exist'

pop()

使用pop(key)删除对应的映射

1
2
3
4
5
6
>>> d
{'Michael': 95, 'Bob': 75, 'Tracy': 85}
>>> d.pop('Bob')
75
>>> d
{'Michael': 95, 'Tracy': 85}

dict和list对比

和list比较,dict有以下几个特点:

  • 查找和插入的速度极快,不会随着key的增加而增加;
  • 需要占用大量的内存,内存浪费多。

而list相反:

  • 查找和插入的时间随着元素的增加而增加;
  • 占用空间小,浪费内存很少。

所以,dict是用空间来换取时间的一种方法

dict可以用在需要高速查找的很多地方,在Python代码中几乎无处不在,正确使用dict非常重要,需要牢记的第一条就是dict的key必须是不可变对象

这是因为dict根据key来计算value的存储位置,如果每次计算相同的key得出的结果不同,那dict内部就完全混乱了。这个通过key计算位置的算法称为哈希算法(Hash)

要保证hash的正确性,作为key的对象就不能变。在Python中,字符串、整数等都是不可变的,因此,可以放心地作为key。而list是可变的,就不能作为key

1
2
3
4
5
>>> key = [1, 2, 3]
>>> d[key] = 'a list'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

set

set是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key,重复元素在set中自动被过滤,同时,显示的顺序不表示set是有序的。

1
2
3
4
5
6
>>> s = set([1, 2, 3])
>>> s
{1, 2, 3}
>>> s=set([4,1,1,2,3,5])
>>> s
{1, 2, 3, 4, 5}

add(key)

通过add(key)方法可以添加元素到set中,可以重复添加,但不会有效果:

1
2
3
4
5
6
>>> s.add(4)
>>> s
{1, 2, 3, 4}
>>> s.add(4)
>>> s
{1, 2, 3, 4}

remove(key)

删除元素

1
2
3
4
5
>>> s
{1, 2, 3, 4, 5}
>>> s.remove(4)
>>> s
{1, 2, 3, 5}

交集&与并集|

两个set可以做数学意义上的交集、并集等操作:

1
2
3
4
5
6
>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s1 & s2
{2, 3}
>>> s1 | s2
{1, 2, 3, 4}

set与dict

set和dict的唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样,所以,同样不可以放入可变对象,因为无法判断两个可变对象是否相等,也就无法保证set内部“不会有重复元素”。

1
2
3
4
>>> s.add([1,2,3])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

再议不可变对象

对于不变对象来说,调用对象自身的任意方法,也不会改变该对象自身的内容。相反,这些方法会创建新的对象并返回,这样,就保证了不可变对象本身永远是不可变的。

本小节内容请参阅 再议不可变对象——廖雪峰的python教程

函数

调用函数

查看帮助文档

查看函数帮助文档的信息的方式,以abs为例

TypeError

调用函数的时候,如果传入的参数数量不对,会报TypeError的错误

1
2
3
4
5
6
7
8
9
10
11
# example 1
>>> abs(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: abs() takes exactly one argument (2 given)

# example 2
>>> abs('a')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bad operand type for abs(): 'str'

数据类型转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> int('123')
123
>>> int(12.34)
12
>>> float('12.34')
12.34
>>> str(1.23)
'1.23'
>>> str(100)
'100'
>>> bool(1)
True
>>> bool('')
False

特别地,函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”:

1
2
3
>>> h=hex	# 变量h指向hex函数
>>> h(255) # 等价于调用hex(hex)
'0xff'

定义函数

示例:

1
2
3
4
5
def my_abs(x):
if x >= 0:
return x
else:
return -x

在Python解释器中导入自定义函数,示例:

  1. my_abs()的函数定义保存为abstest.py文件
  2. 启动Python解释器,用from abstest import my_abs以导入my_abs()函数

空函数

定义一个什么事也不做的空函数,可以用pass语句:

1
2
def nop():
pass

pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。

pass还可以用在其他语句里,比如:

1
2
if age >= 18:
pass

缺少了pass,代码运行就会有语法错误。

参数检查isinstance()

示例:

1
2
3
4
5
6
7
8
# 如果x的类型不是int或者float,TypeError会提示"bad operand type"
def my_abs(x):
if not isinstance(x, (int, float)):
raise TypeError('bad operand type')
if x >= 0:
return x
else:
return -x

返回多个值

函数的返回类型为tuple,可按位置赋值给对应变量。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
import math
def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny

>>> x, y = move(100, 100, 60, math.pi / 6)
>>> print(x, y)
151.96152422706632 70.0

>>> r = move(100, 100, 60, math.pi / 6)
>>> print(r)
(151.96152422706632, 70.0)

函数的参数

位置参数

调用函数时,传入的两个值按照位置顺序依次赋给参数。

默认参数

设置函数缺省值,在对应位置加上=C,对应位置参数默认为C

  • 必选参数在前,默认参数在后,否则Python的解释器会报错
  • 当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。

示例:

1
2
3
4
5
def enroll(name, gender, age=6, city='Beijing'):
print('name:', name)
print('gender:', gender)
print('age:', age)
print('city:', city)

正确调用方式:

1
2
enroll('Bob', 'M', 7)
enroll('Adam', 'M', city='Tianjin') # 当不按顺序提供部分默认参数时,需要把参数名写上

默认参数必须指向不变对象

反例:

1
2
3
4
5
6
7
8
9
10
11
12
# 定义
def add_end(L=[]):
L.append('END')
return L

# 执行
>>> add_end()
['END']
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']

原因:

Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。

所以,定义默认参数要牢记一点:默认参数必须指向不变对象

修正之后的函数定义:

1
2
3
4
5
6
7
8
9
10
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
```

### 可变参数

定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。

正常定义

def calc(numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum

使用可变参数定义

def calc(numbers):
sum = 0
for n in numbers:
sum = sum + n
n
return sum

使用可变参数定义的调用方法

calc(1, 2)
5
calc()
0

Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传入

nums = [1, 2, 3]
calc(*nums)
14

1
2
3
4
5
    


# 备注
<!--打卡!-->

a^n 的表示方法: a**n
max的参数可为任意个数
import math语句表示导入math包,并允许后续代码引用math包里的sin、cos等函数。
```