把学过的知识记录下来。
1.安装Python 3.6
目前,Python有两个版本,一个是2.x版,一个是3.x版,这两个版本是不兼容的。自行百度安装3.x。
2.Python基础语法
print()会依次打印每个字符串,遇到逗号“,”会输出一个空格.
Python的语法比较简单,采用缩进方式,如下
# 这个是注释
a = 100
if a >= 0:
print(a)
else:
print(-a)
以#开头的语句是注释,注释是给人看的,可以是任意内容,解释器会忽略掉注释。其他每一行都是一个语句,当语句以冒号:结尾时,缩进的语句视为代码块。按照约定俗成的管理,应该始终坚持使用4个空格的缩进。Python程序是大小写敏感的,Tab和4个空格不一样哦。
2.1 数据类型
整数 Python可以处理任意大小的整数,当然包括负整数
浮点数 科学计数法表示,把10用e替代,1.23x109就是1.23e9,或者12.3e8,0.000012可以写成1.2e-5,等等。
整数和浮点数在计算机内部存储的方式是不同的,整数运算永远是精确的(除法难道也是精确的?是的!),而浮点数运算则可能会有四舍五入的误差。
字符串 字符串是以单引号'或双引号"括起来的任意文本
'I\'m \"OK\"!' #转义字符\来标识 I'm "OK"!
Python还允许用r''表示''内部的字符串默认不转义
Python允许用'''...'''的格式表示多行内容
布尔值 在Python中,可以直接用True、False表示布尔值(请注意大小写)布尔值可以用and、or和not运算。
空值 空值是Python里一个特殊的值,用None表示。None不能理解为0,因为0是有意义的,而None是一个特殊的空值。
变量 理解变量在计算机内存中的表示也非常重要。当我们写:a = 'ABC' 时,Python解释器干了两件事情:
在内存中创建了一个'ABC'的字符串;
在内存中创建了一个名为a的变量,并把它指向'ABC'。
常量 在Python中,通常用全部大写的变量名表示常量:
#在Python中,有两种除法,一种除法是/:
print(10 / 3) #3.3333333333333335
#/除法计算结果是浮点数,即使是两个整数恰好整除,结果也是浮点数
print(9 / 3)
#还有一种除法是//,称为地板除,两个整数的除法仍然是整数:
print(10 // 3) #整数的地板除//永远是整数 //除法只取结果的整数部分
print(10 % 3) #得到两个整数相除的余数
#无论整数做//除法还是取余数,结果永远是整数,所以,整数运算结果永远是精确的。
2.2字符串和编码
字符编码 字符串比较特殊的是还有一个编码问题
因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理。
在最新的Python 3版本中,字符串是以Unicode编码的,也就是说,Python的字符串支持多语言
#对于单个字符的编码
print(ord('A')) #获取字符的整数表示
print(chr(65)) #把编码转换为对应的字符
x = b'ABC' #Python对bytes类型的数据用带b前缀的单引号或双引号表示
#要注意区分'ABC'和b'ABC',前者是str,后者虽然内容显示得和前者一样,但bytes的每个字符都只占用一个字节
#以Unicode表示的str通过encode()方法可以编码为指定的bytes
print('ABC'.encode('ascii')) #纯英文的str可以用ASCII编码为bytes
print('中文'.encode('utf-8')) #含有中文的str可以用UTF-8编码为bytes
#print('中文'.encode('ascii')) #中文的str无法用ASCII编码,因为中文编码的范围超过了ASCII编码的范围
#在bytes中,无法显示为ASCII字符的字节,用\x##显示。
#把bytes变为str,就需要用decode()方法:
print(b'ABC'.decode('ascii'))
print(b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')) #中文
#如果bytes中包含无法解码的字节,decode()方法会报错
#如果bytes中只有一小部分无效的字节,可以传入errors='ignore'忽略错误的字节
print(b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore'))#中
print(len(b'ABC')) #len()函数计算的是str的字符数,如果换成bytes,len()函数就计算字节数
print(len('中文'.encode('utf-8')))
由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。
当Python解释器读取源代码时,为了让它按UTF-8编码读取,我们通常在文件开头写上这两行:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释;
第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码。
格式化
在Python中,采用的格式化方式和C语言是一致的,用%实现,举例如下
#%运算符就是用来格式化字符串的
#%s表示用字符串替换,%d表示用整数替换,%x表示用16进制整数替换,%f表示用浮点数替换
#有几个%?占位符,后面就跟几个变量或者值,顺序要对应好,如果只有一个%?,括号可以省略。
print('Hello, %s' % 'world')
print('Hi, %s, you have $%d.' % ('Michael', 1000000))
#%s永远起作用,它会把任何数据类型转换为字符串
#用%%来表示一个普通%
format() 它会用传入的参数依次替换字符串内的占位符{0}、{1}……,
>>> 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125)
'Hello, 小明, 成绩提升了 17.1%'
2.3使用list和tuple
list列表
# Python内置的一种数据类型是列表:list 是一种有序的集合,可以随时添加和删除其中的元素, 类似js数组
classmates = ['Michael', 123,['asp', 'php'], True] #用len()函数可以获得list元素的个数
#要确保索引不要越界,记得最后一个元素的索引是len(classmates) - 1
print(classmates[-2])#还可以用-1做索引,直接获取最后一个元素 以此类推
classmates.append('Adam')#往list中追加元素到末尾
classmates.insert(1, 'Jack') #把元素插入到指定的位置
classmates.pop() #删除list末尾的元素
classmates.pop(1) #删除指定位置的元素,用pop(i)方法,其中i是索引位置
classmates[1] = 'Sarah' #把某个元素替换成别的元素,可以直接赋值给对应的索引位置
#如果一个list中一个元素也没有,就是一个空的list,它的长度为0
tuple 元组 tuple和list非常类似,但是tuple一旦初始化就不能修改.
classmates = ('Michael', 'Bob', 'Tracy')
#现在,classmates这个tuple不能变了,它也没有append(),insert()这样的方法。
#其他获取元素的方法和list是一样的,你可以正常地使用classmates[0],classmates[-1],但不能赋值成另外的元素。
#不可变的tuple有什么意义?因为tuple不可变,所以代码更安全。如果可能,能用tuple代替list就尽量用tuple。
#tuple的陷阱:当你定义一个tuple时,在定义的时候,tuple的元素就必须被确定下来,比如:
t=(1, 2)
#如果要定义一个空的tuple,可以写成()
t = ()
#要定义一个只有1个元素的tuple,必须加一个逗号,来消除歧义:
t = (1,)
print(t)
#Python在显示只有1个元素的tuple时,也会加一个逗号,以免你误解成数学计算意义上的括号。
2.4条件判断
#if语句的完整形式就是:
if :
elif :
elif :
else:
#if语句执行有个特点,它是从上往下判断,如果在某个判断上是True,把该判断对应的语句执行后,就忽略掉剩下的elif和else
age = 3
if age >= 18:#注意不要少写了冒号:
print('adult')
elif age >= 6:
print('teenager')
else:
print('kid')
2.5循环
#Python的循环有两种,一种是for...in循环,依次把list或tuple中的每个元素迭代出来
names = ['Michael', 'Bob', 'Tracy']
for name in names:
print(name)
#执行这段代码,会依次打印names的每一个元素:
sum = 0
for x in range(101):#range(101)就可以生成0-100的整数序列
sum = sum + x
print(sum)
#第二种循环是while循环,只要条件满足,就不断循环,条件不满足时退出循环
sum = 0
n = 99
while n > 0:
sum = sum + n
n = n - 2
if n > 10: # 当n = 11时,条件满足,执行break语句
break # break语句会结束当前循环
print(n)
#在循环过程中,也可以通过continue语句,跳过当前的这次循环,直接开始下一次循环。
if n % 2 == 0: # 如果n是偶数,执行continue语句
continue # continue语句会直接继续下一轮循环,后续的print()语句不会执行
print(sum)
2.6使用dict和set
dict字典 Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。
d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
d['Adam'] = 67 #赋值
d['Adam'] #获取 如果key不存在,dict就会报错:
#多次对一个key放入value,后面的值会把前面的值冲掉
#要避免key不存在的错误,有两种办法,一是通过in判断key是否存在:
print('Adam' in d) #True/False
print(d.get('Thomas')) #如果key不存在,返回None
print(d.get('Thomas', -1)) #不存在 返回传入的默认值
#要删除一个key,用pop(key)方法,对应的value也会从dict中删除
d.pop('Thomas')
#请务必注意,dict内部存放的顺序和key放入的顺序是没有关系的
和list比较,dict有以下几个特点:
查找和插入的速度极快,不会随着key的增加而变慢;
需要占用大量的内存,内存浪费多。
而list相反:
查找和插入的时间随着元素的增加而增加;
占用空间小,浪费内存很少。
所以,dict是用空间来换取时间的一种方法。
需要牢记的第一条就是dict的key必须是不可变对象。
这个通过key计算位置的算法称为哈希算法(Hash)。
要保证hash的正确性,作为key的对象就不能变。
在Python中,字符串、整数等都是不可变的,因此,可以放心地作为key。而list是可变的,就不能作为key
set set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。
#要创建一个set,需要提供一个list作为输入集合:重复元素在set中自动被过滤:
s = set([1, 2, 3])
#通过add(key)方法可以添加元素到set中,可以重复添加,但不会有效果:
s.add(4)
#通过remove(key)方法可以删除元素:
s.remove(4)
#set可以看成数学意义上的无序和无重复元素的集合,因此,两个set可以做数学意义上的交集、并集等操作:
s1 = set([1, 2, 3])
s2 = set([2, 3, 4])
print(s1 & s2) #{2, 3}
print(s1 | s2) #{1, 2, 3, 4}
#set和dict的唯一区别仅在于没有存储对应的value
#所以,对于不变对象来说,调用对象自身的任意方法,也不会改变该对象自身的内容。相反,这些方法会创建新的对象并返回
#使用key-value存储结构的dict在Python中非常有用,选择不可变对象作为key很重要,最常用的key是字符串
3.函数
调用函数
# 内置函数 http://docs.python.org/3/library/functions.html#abs
print(abs(-2.1)) #求绝对值的函数
#调用函数的时候,如果传入的参数数量不对,会报TypeError的错误
#如果传入的参数数量是对的,但参数类型不能被函数所接受,也会报TypeError的错误
print(max(2, 3, 1, -5)) #max函数可以接收任意多个参数,并返回最大的那个
#数据类型转换
int('123') #int()函数可以把其他数据类型转换为整数
float('12.34') #12.34
str(1.23) #'1.23'
bool(1) #True
bool('') # False
print(hex(23)=='0x17') #函数把一个整数转换成十六进制表示的字符串
#函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”
a = abs # 变量a指向abs函数
a(-1) # 所以也可以通过a调用abs函数
定义函数
#定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,
# 然后,在缩进块中编写函数体,函数的返回值用return语句返回。
def my_abs(x):
if x >= 0:
return x
else:
return -x
print(my_abs(-99))
#函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕
#如果没有return语句,函数执行完毕后也会返回结果,只是结果为None。return None可以简写为return。
#函数执行完毕也没有return语句时,自动return None。
# from xxxx import my_abs来导入my_abs()函数,注意 xxxx 是文件名(不含.py扩展名 )
#空函数 如果想定义一个什么事也不做的空函数,可以用pass语句:
def nop():
pass
#pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。
#pass还可以用在其他语句里,比如:
if age >= 18:
pass
#缺少了pass,代码运行就会有语法错误。
#让我们修改一下my_abs的定义,对参数类型做检查,只允许整数和浮点数类型的参数。
#数据类型检查可以用内置函数isinstance()实现:
def my_abs(x):
if not isinstance(x, (int, float)):
raise TypeError('bad operand type')
if x >= 0:
return x
else:
return -x
#函数可以返回多个值吗?答案是肯定的。
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)
#但其实这只是一种假象,Python函数返回的仍然是单一值:
r = move(100, 100, 60, math.pi / 6)
print(r) #(151.96152422706632, 70.0)
#原来返回值是一个tuple!但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,
# 所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便。
函数的参数
# Python的函数定义非常简单,除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,
# 使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码。
def power(x, n=2):#默认参数
s = 1
while n > 0:
n = n - 1
s = s * x
return s
默认参数可以简化函数的调用。设置默认参数时,有几点要注意:
一是必选参数在前,默认参数在后,
二是如何设置默认参数。
当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。
使用默认参数有什么好处?最大的好处是能降低调用函数的难度。
当不按顺序提供部分默认参数时,需要把参数名写上。比如调用enroll('Adam', 'M', city='Tianjin')
#默认参数有个最大的坑,演示如下:
def add_end(L=[]):
L.append('END')
return L
print(add_end()) # ['END']
print(add_end()) # ['END', 'END']
#很多初学者很疑惑,默认参数是[],但是函数似乎每次都“记住了”上次添加了'END'后的list。
#定义默认参数要牢记一点:默认参数必须指向不变对象!
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
#现在,无论调用多少次,都不会有问题:
#为什么要设计str、None这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改。
#此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。
可变参数 允许你传入0个或任意个参数
def calc(*numbers): #可变参数
sum = 0
for n in numbers:
sum = sum + n * n
return sum
#如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做:
#Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去
nums = [1, 2, 3]
calc(*nums)
# *nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。
关键字参数
#可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,
#这些关键字参数在函数内部自动组装为一个dict。请看示例:
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
person('Michael', 30) #name: Michael age: 30 other: {}
person('Bob', 35, city='Beijing') #name: Bob age: 35 other: {'city': 'Beijing'}
person('Adam', 45, gender='M', job='Engineer') #name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
#和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去
extra = {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, **extra) #name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
# **extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,
# 注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。
命名关键字参数
#仍以person()函数为例,我们希望检查是否有city和job参数:
def person(name, age, **kw):
if 'city' in kw:
# 有city参数
pass
if 'job' in kw:
# 有job参数
pass
print('name:', name, 'age:', age, 'other:', kw)
person('Jack', 24, city='Beijing', addr='Chaoyang', zipcode=123456)
#如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和job作为关键字参数。
# 这种方式定义的函数如下:
def person(name, age, *, city, job):
print(name, age, city, job)
#和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。
person('Jack', 24, city='Beijing', job='Engineer') #Jack 24 Beijing Engineer
#如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:
def person(name, age, *args, city, job):
print(name, age, args, city, job)
#命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错:
def person(name, age, *, city='Beijing', job):
print(name, age, city, job)
#由于命名关键字参数city具有默认值,调用时,可不传入city参数:
person('Jack', 24, job='Engineer') #Jack 24 Beijing Engineer
#使用命名关键字参数时,要特别注意,如果没有可变参数,就必须加一个*作为特殊分隔符。
#如果缺少*,Python解释器将无法识别位置参数和命名关键字参数:
参数组合
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。
但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
f1(1, 2) #a = 1 b = 2 c = 0 args = () kw = {}
f1(1, 2, c=3) #a = 1 b = 2 c = 3 args = () kw = {}
f1(1, 2, 3, 'a', 'b') #a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
f1(1, 2, 3, 'a', 'b', x=99)#a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
f2(1, 2, d=99, ext=None) #a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
#最神奇的是通过一个tuple和dict,你也可以调用上述函数:
args = (1, 2, 3, 4)
kw = {'d': 99, 'x': '#'}
f1(*args, **kw) #a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
#对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。
默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!
要注意定义可变参数和关键字参数的语法:
*args是可变参数,args接收的是一个tuple;
**kw是关键字参数,kw接收的是一个dict。
可变参数既可以直接传入:func(1, 2, 3),又可以先组装list或tuple,再通过args传入:func((1, 2, 3));
关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过kw传入:func({'a': 1, 'b': 2})。
使用args和kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。
命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符,否则定义的将是位置参数。
递归函数
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。