廖老师的教程https://www.liaoxuefeng.com
第一部分
python简介
优缺点
安装python
python解释器:
Python
IPython
JPython
CPython
ironPython
第一个python程序
使用文本编辑器
推荐两个:
Sublime Text——免费
Notepad++——免费 中文界面
运行py
终端如何使用py文件:
##定位到根目录下
cd ...untitled
##然后 python helloworld.py
怎么直接运行py
#!/usr/bin/env python ##首先要在.py文件的第一行加上
$ chmod a+x hello.py ##然后通过命令
输入和输出
输出:print
输入:raw_input()
python基础
关于缩进
缩进的坏处是“复制-粘贴”功能失效了。
粘贴后必须重新检查缩进是否正确。
数据类型和变量
数据类型
整数,浮点数,字符串,布尔值,空值
计算机使用二进制,所以有时候使用十六进制表示整数比较方便。
十六进制用0x前缀和0-9,a-f表示。例如:0xff00
变量
1.同一个变量可以被反复赋值,而且可以是不同类型的变量
这种变量本身不固定的语言称之为动态语言。
与之对应的是静态语言
静态语言在定义变量时必须制定变量类型,如果不匹配就会报错。例如java。
例如:
int a =123 ##a 是整数类型变量
a = "ABC" ##会报错
2.理解变量在计算机内存中的表示
当我们写:a = ‘ABC’时,python干了两件事:
在内存中创建了一个‘ABC'的字符串
在内存中创建了一个名为a的变量,并指向‘ABC’
也可以把一个变量a赋值给另一个变量b,这个操作实际上是把变量b指向变量a所指向的数据。
所以当给a重新赋值,就是让a指向别的值,对b无影响。
常量
通常用全部大写的变量名表示常量
字符串和编码
字符编码
因为计算机只能处理数字,要处理文本,就必须将文本转换为数字。
最早计算机设计采用8个比特作为一个字节,所以一个字节能表示最大的整数是255。二进制11111111=十进制255。如果要表示更大的整数,就必须用更多字节
最早美国英文、数字、符号,使用ASCII编码。比如A的编码是65.小写字母z是122,127个字母。
GB2312——中文
Shift_JIS——日文
Euc-kr——韩文
Unicode——所有语言
UTF-8——可变长编码
如果统一用unicode,虽然解决乱码问题
如果写的文本都是英文的话,使用unicode比ASCII需要多一倍的空间。
因此出现了把unicode编码转化成“可变长编码”的UTF-8。
总结下现在计算机系统通用的字符编码工作方式
计算机内存中,统一使用Unicode编码
当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码
用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符存到内存里,编辑完成后,保存的时候再把Unicode转化为UTF-8保存到文件
浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器
字符串
1.最早python支持ASCII编码
把字母和对应的数字相互转换
ord()
chr()
2.后来添加了对Unicode的支持
print u'中文'——中文
u'中'——u'\u4e2d'
##写u'中'和u'\u4e2d'是一样的
##\u后面是十六进制的Unicode码
两种字符串如何转换?
字符串‘xxx’虽然是ASCII编码,但也可以看成UTF-8编码。但u’xxx’只能使Unicode编码。
把u’xxx’转换为UTF-8编码的‘xxx’用encode(‘utf-8’)方法:
u'ABC'.encode('utf-8')——'ABC'
##英文字符转换后表示的UTF-8的值和Unicode值相等(但占据的储存空间不同)
u'中文‘.encode('utf-8')——'\xe4\xb8\xad\xe6\x96\x87'
##中文字符转换后1个Unicode字符将变为3个UTF-8字符
##\xe4就是其中一个字节,它的值是228.没有对应字母可以显示,所以十六进制显示字节的数值
len('\xe4\xb8\xad\xe6\x96\x87')——6
##len()函数可以返回字符串的长度
反过来把UTF-8编码表示的字符串’xxx’转换为Unicode字符串u’xxx’用decode(‘utf-8’)方法:
'abc'.decode('utf-8')——u'abc'
'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')——u'\u4e2d\u6587'
print '\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')——中文
3.保存为UTF-8编码
由于python源代码也是一个文本文件,所以,当你源代码中包含中文的时候,在保存源代码时,务必制定保存为UTF-8编码。
通常在文件开头写两行:
#!/usr/bin/env python
告诉Linux/OS X系统,这是一个python可执行程序,windows系统会忽略这个注释
# -*- coding:utf-8 -*-
告诉python解释器,按照UTF-8编码读取源代码,否则,在源代码中写的中文输出可能会有乱码
如果你使用Notepad++进行编辑,除了要加上#-- coding:utf-8 --外,中文字符串必须是Unicode字符串。
声明了UTF-8编码也并不意味着你的.py文件就是UTF-8编码,必须却把Notepad++正在使用UTF-8without BOM编码
4.格式化
%?占位符
常见占位符:
%d整数、%f浮点数、%s字符串、%x十六进制整数
其中整数还有浮点数能指定是否补0和整数与小数之间的位数
'%2d-%02d' % (3,1)——'3-01'
'%.2f' % 3.1415926——'3.14'
如果不确定用什么,用%s,%s把任何类型转化为字符串。
对于unicode字符串,用法一样,最好替换的字符串也是Unicode :
u'Hi, %s' % u'Michael——u'Hi,Michael'
那怎么表示%?
转义,用%%表示一个%
'growth rate: %d %%' % 7
'growth rate :7%'
5.python也支持其他编码方式,没有特殊要求不用
使用list和tuple
list
属性
1.最后一个元素的索引是
len(classmates)-1
2.list里面的元素数据类型可以不同
L=['Apple',123,,True]
3.list里面的元素可以是另一个list
二维数组概念
查
用索引
增
1.添加到末尾
append
classmates.append('Adam')
2.插入指定位置
insert
classmates.insert(1,'jack')
删
1.要删除list末尾的元素
pop
classmates.pop()
2.删除指定位置的元素
pop(i)
classmates.pop(1)
改
替换
直接赋值给对应索引位置
classmates[1] = 'Sarah'
tuple
属性
1.初始化后不可修改
2.因为不可变,所以代码更安全,如果可能,尽量用tuple
3.当tuple中只有一个元素,初始化的时候必须加逗号
t = (1,)
查
用索引
没有增删改
可变的 tuple
1.当tuple中包含可变元素例如list
2.tuple指向不变
3.如果要创建一个内容也不不变的tuple怎么做?
必须保证tuple中每个元素也不可变
条件判断和循环
条件判断
if
循环
1.for
range()
##生成整数序列[0,1,2,3,4]
2.while
raw_input
##注意该方法永远以字符串的形式返回
##如果有需要要将字符串转换
birth= int (raw_input('birth: '))
使用dict和set
dict
属性
1.键值对
2.需要牢记
- dict的key必须是不可变对象
- 这种通过key计算位置的算法称为哈希算法(Hash)
3.如果key不存在会报错
##通过in判断是否存在
'Thomas' in d——False
##通过dict提供的get方法,不存在,返回None或者自己指定value
d.get('Thomas') ##返回None的时候,交互式命令行不显示结果
d.get('Tmoas',-1) ##-1
4.和list区别
查找、插入速度极快,不会随着Key的增加而增加。
需要占用大量内存,内存浪费多。
5.list特点
查找和插入时间随元素的增加而增加。
占用时间小,浪费内存少。
查
用key
增
1.初始化指定
2.通过key放入
d['Adam']=67
删
pop(key)方法
d.pop('Bob') ##75
改
一个key对应一个value,多次放入,后面的值会把前面的值冲掉
set
属性
1.和dict类似,也是一组Key的集合,但不储存value。由于key不能重复,所以,在set中,没有重复的key
2.重复的元素自动被过滤
3.set可以看成数学意义上的无序和无重复元素的集合
因此两个set可以做数学意义上的交集、并集等操作
4.与dict相比
唯一区别仅在于没有存储对应的value
同样不可以放入可变对象,因为无法判断两个可变对象是否相等,也就无法保证set内部不会有重复元素。
增
1.初始化创建
需提供一个list作为输入集合
s=set([1,2,3])
s ——set([1,2,3])
##注意,传入的参数【1,2,3】是一个list,而显示的set([1,2,3])只是告诉你这个set内部有1,2,3这些元素,显示的[]不表示这是一个list
2.add(key)方法添加
s.add(4)
s ——set([1,2,3,4])
删
remove(key)方法
s.remove
s ——set([1,2,3])
改
1.交集
s1=set([1,2,3])
s2=set([2,3,4])
s1 & s2 ——set([2,3])
2.并集
s1 | s2 ——set([1,2,3,4])
查
再议不可变对象
list是可变
a=['c','b','a']
a.sort()
a ——['a','b','c']
str是不变对象
案例1
a='abc'
a.replace('a','A') ——'Abc'
a ——'abc'
案例2
a = 'abc'
b=a.replace('a','A')
b ——'Abc'
a ——'abc'
解释:
当调用replace时,replace作用在字符串对象‘abc’上,但是没有改变字符串‘abc’的内容,而是创建了一个新字符串’Abc’并返回。
用变量b指向新字符串就容易理解。
a仍然指向原有字符串,b则指向新字符串。
结论:
所以对于不变对象来说,调用对象自身的任意方法,都不会改变该对象自身的内容。
相反,这些方法会创建新的对象并返回。这样,就保证了不可变对象本身永远是不可变的。
函数
调用函数
1.数据类型转换函数——工厂函数+解码
2.将函数赋值给变量
定义函数
1.def
return返回
2.空函数
pass
3.参数检查
添加参数检查后,如果传入错误的参数诶性,函数就可以抛出一个错误
raise TypeError('bad operand type')
4.返回多个值
其实是返回一个tuple
函数的参数
默认参数
1.当函数有多个参数时,把变化大的参数放前面变化小的参数放后面,使用默认函数最大的好处是能降低调用函数的难度。
2.默认函数的坑
必须指向不可变对象
例如参数为list,每次调用list可能都会变化。
如何优化,调用前先把list归零。
可变参数
1.定义参数时在参数前加*
def calc(*numbers)
##在函数内部,参数numbers接收到的是一个tuple
2.可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。
关键词参数
1.定义参数时在参数前加**
可以扩展函数的功能,如果调用者愿意提供更多的参数。
2.关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
参数组合
必选参数、默认参数、可变参数、关键字参数可以混合使用。
必须按照这种顺序定义。
另外,对于任意参数都可以通过类似func(*args,**kw)的形式调用它。
递归函数
1.在函数内部,可以调用其他函数,如果一个函数在内部调用自己本身,这个函数就是递归函数
2.理论上,所有递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰
def fact(n)
return n*fact(n-1)
3.使用递归函数需要注意防止栈溢出
在计算机中,函数调用是通过栈(stack)这种数据结构实现的。
每当进入一个函数调用,栈就会加一层栈帧,当函数返回,栈就会减一层栈帧。
由于栈的大小不是无限的,所以递归调用的次数过多,会导致栈溢出。
试试fact(1000)
解决递归调用栈溢出的方法是通过尾递归优化
事实上尾递归和循环的效果是一样的,所以把循环看成一种特殊的尾递归函数也是可以的。
尾递归是指,在函数返回的时候,调用自身本身,并且return语句不能包含表达式。
这样编译器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
遗憾的是,大部分编程语言没有针对尾递归做优化,python解释器也没有优化,所以即使把上面的函数改成尾递归方式,也会导致栈溢出