1、安装pyenv
curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash
vim ~/.bash_profile +++
export PATH="/root/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
source ~/.bash_profile
2、安装python
yum -y install gcc patch make
yum -y install gdbm-devel openssl-devel sqlite-devel readline-devel zlib-devel bzip2-devel
apt-get -y install libgdbm-dev libssl-dev libsqlite0-dev libreadline-dev zlib1g-dev libbz2-dev libsqlite3-dev
pyenv install 3.5.2
3、使用pyenv
pyenv local 3.5.2 切换python版本,这个是针对当前目录以及子目录设置python版本
pyenv local system 切换到系统python版本
pyenv global 3.5.2 切换全局python版本,一般不要使用,影响yum等使用
pyenv globan system 切换全局python版本,或者 rm -f ~/.pyenv/version
4、vitrualenv 使用
基于某个版本来创建虚拟环境
pyenv virtualenv 3.5.2 test 创建一个名为test的虚拟环境
pyenv uninstall test 删除一个test虚拟环境
5、ipython安装
pip install ipython 安装ipython
6、修改pip源
vim ~/.pip/pip.conf +++
[global]
index-url = http://mirrors.aliyun.com/pypi/simple/
trusted-host = mirrors.aliyun.com
7、安装jupyter notebook
pip install jupyter
jupyter notebook --ip=0.0.0.0
或者用配置文件来启动
jupyter notebook --generate-config --allow-root
vim /root/.jupyter/jupyter_notebook_config.py
jupyter notebook --allow-root
8、常量,变量
常量:一旦赋值,就不可在改变,换句话说,就是不能对他重新赋值。Python不存在常量。
字面常量:一个单独出现的量,未赋值给任何的变量或常量
变量:是一个名字,在赋值符号的左边
9、类型
Python数强类型语言,不同类型的变量不能做运算
Python是动态类型语言,变量可以重新赋值为其他类型
Python基本类型: int float byte bool none
Python组合类型: str list set
10、运算符
算数运算符: + - * / // ** % 只对int和float运算
python 3 : 3/2 = 1.5
python 3 : 取整除 // 和 python 2 的除法表现一样
python 2 : 3/2 = 1
比较运算符: > < == != >= <= 返回值都是bool类型
逻辑运算符: and or not
逻辑运算符的操作数都是bool类型或者可以隐式转换为bool类型
成员运算符
身份运算符
位运算符: << >> & | ^
赋值运算符: =
可以和算数运算符和位运算符一起使用 += -=,赋值运算符返回none
运算符的优先级
** > */ > % > +- > 比较运算(> < == != >= <= ) > 逻辑运算符(and or not )
11、表达式、语句
表达式:常量、变量、和运算符一起构成,表达式有返回值
语句:关键字和表达式一起组成的语句,语句没有返回值
12、列表以及其常用操作
列表是一个序列,用于顺序的存储数据
定义与初始化
lst = list()
lst = []
lst = [1, 2, 3]
lst = list(range(1, 10))
curd
访问列表元素:lst[0]、lst[-1]
.index(num) # 通过值查找第一个值得索引、
.index(num, start) # 指定从哪个索引开始查找
.index(num, start, end) # 指定到那个索引结束
当值不存在的时候会抛出ValueError
.count(num) # 返回num值得个数
.index 和 .count 两个方法的时间复杂度是O(n)
修改指定元素:lst[5] = 10
增加元素:无法使用所以操作,使用固定方法
lst.append(value),lst.insert(index, value),分别是追加和插入(在index前边),当超出范围,会在距离最近的一个元素前边插入。
lst.extend(iter_obj) 将可迭代对象追加到末尾
lst + [1, 2, 3] = [0, 1, 2, 1, 2, 3] 将两个list对象相加,有返回值,不会修改原来的list
删除
lst.remove(value) 删除列表中的第一个出现的value
lst.pop(index) 不指定index的话删除最后一个值,如果指定index,那么删除索引位置元素
lst.clear() 删除所有元素
其他操作
求长度:len(lst)
反转值:lst.reverse()
排序:lst.sort(reverse=True) 逆序排序,默认是正序,是快速排序算法
复制:lst = list(range(1, 2)) lst2 = lst lst2[0] = x 复制操作传递的是引用,所以修改lst2的时候lst也会被修改,叫浅拷贝
影子拷贝:lst2 = lst.copy() 这种方法如果列表中有list,还是浅拷贝,叫影子拷贝。只对第一层有效
深拷贝:import copy lst2 = copy.deepcopy(lst)
赋值操作,对可变对象是引用传递,对不可变对象是值传递
13、字符串操作以及定义
三引号可以定义多行字符串,而且里边单引号不用转移
path = r'C:/windows/nt/system32' # 加r前缀代表次字符串是自然字符串,不会转义
字符串是不可变对象,可以用下标操作,但是不能改变,是可迭代对象,可以做 for x in str:
常用重点方法:
list(s) 将s字符串转换成list类型
join lst = ['i', 'am', 'styd'] ''.join(lst) 将lst用''中的分隔符链接起来。
split str.split() 默认使用空格来分割,多个空格视为一个空格,如果指定' ' 来分割,多个空格就会去处理,maxsplit=1,指定以后,最多分割1次。默认为-1,表示分割所有分隔符。
rsplit 是split从右往左分割的版本,当不指定maxsplit 的时候,他们两个表现一样,但是split是效率高一些
splitlines str.splitlines() 按行分割,并且默认返回结果不带操作符,如果str.splitlines(True),则返回结果带换行符
partition str.partition() 总是返回一个三元组,他按照传入的分隔符分割一次,得到head、tail,返回结果是 head,sep,tail
rpartition str.rpartition() 是partition从右往左的版本
排版用函数
str.title() 将字符串中的每个单词首字母大写
str.capitalize() 只将字符串中的第一个字母大写
str.center(80) 居中字符串,用空格填充
str.zfill(80) 居右字符串,左边用0填充
str.caseflod() 统一转换成小写,不同平台表现不一样,通常用来忽略大小写来比较。
str.swapcase() 交换大小写,大写变小写,小写变大写。
str.expandtabs() 将\t 转换为四个空格
str.format() #
修改用函数
str.replace() 替换字符串,返回一个新的字符串,例:str.replace('love', 'give up', 3) 将str中的love替换成give up,最多替换3次
str.strip() 删除字符串两边的空格,\t \r \n 都会移除,如果指定字符串,则移除指定,例:s.strip('#{}')
str.lstrip() 只移除左边,str.rstrip()只移除右边
str.ljust() 将字符串填充,左填充空格,也可以指定填充字符,例:str.ljust(10, '#'),填充字符串长度只能为1
str.rjust() 如上
查找用函数
str.find('very', 3, 10) 用于找出一个子串最早的index ,从左往右查找,返回子串首字母的索引,找不到返回-1,可以指定开始位置和结束为止
str.rfind('very', 3,10) 用于找出一个子串最早的index ,从右往左查找,返回子串首字母的索引,找不到返回-1,可以指定开始位置和结束为止
str.index 功能和find 一样,但是如果找不到子字符串,那么抛出valueError
str.rindex 功能和rfind 一样,但是如果找不到子字符串,那么抛出valueError
str.count('s', startposition) 查找字符串中指定字符出现的次数
判断用函数
str.startswith('very', 2) 判断字符串是否以某个前缀开始,返回bool,可以指定start位置和stop位置。
str.endswith('python', start, stop) 判断字符串是否以某个后缀结尾,返回bool,可以指定start和stop位置
str.isalnum() 判断是否仅仅含有数字或者字母的字符串
str.isdecimal() 判断是否仅含数字
str.isidentifier() 判断是否为合法标识符,1、字母或者下划线开头.。2、仅包含字母数字和下划线
字符串格式话是拼接字符串的一种手段
' '.join(['i', 'love', 'python'])
'i' + 'love' + 'python'
'i love %s' % ('python', ) 有几个占位符,就写几个内容的元组,不匹配的话抛出TypeError,当占位符是s/r的时候,隐式的调用了str() /repr()
'my name is {0}, i love {lang}, i am {age} years old'.format(lilei, lang='python', age=19),占位符和参数不匹配的话会抛出异常
{数字i} 会把位置参数当成一个列表args,args[i] 当i不是args的索引的时候,抛出indexError
{关键字k} 会把关键字参数当成一个字典kwargs,使用kwargs[k]当k不是kwargs的key时,会抛出KeyError
'{{}} {}'.format(18) 两层大括号转义了,结果是{} 18
2.6 版本大括号里边的数字或者参数不能省略
14、bytes与字符串
str 是文本序列,bytes是字节序列
文本是有编码的(utf-8,gbk...),字节没有这种说法
文本编码指的是字符如何使用字节来表示
python3默认使用utf-8,在linux上
s = '你好'
s.encode() # 将字符串编码为bytes,bin(s.encode()),将bytes转换为2进制.
b.decode() # 将bytes解码为str,可以指定编码格式
b.hex()转化为16进制
string的所有操作bytes都支持
b'abc'.find(b'b') 结果为1
'你好'.encode().find(b'\xa9') 是按照字节来找的
bytes 由 str通过encode方法转化得到
bytes通过b前缀定义bytes
15、bytearray
是bytes的可变版本,bytes和str是不可变的
b = b'bas'
b[1] = b'c' 会报错
b = bytearray(b)
b[1] = int(b'B'.hex(), 16) 将bytes转换为16进制,然后转化为int,就可以变化了
操作的是单个字节,python没有byte这种类型,但是byte都可以用int表示,而且int必须是0-255范围
b 等于 bytearray(b'aBc')
bytearray 用来做图像处理,用来修改大对象的bytes内容,节省内存
16、线性结构
列表、元组、字符串、bytes、bytearray
特点:
可迭代
len获取长度
可以使用下标操作符通过索引访问
可以切片
lst[start:stop:step] 从start 开始,到stop结束,不包含stop,步进值为step,返回一个新的list
支持负数索引 lst[-5:-3],如果超出索引范围,start=0,stop=-0,当start>=stop时,返回空列表
如果step为负数,则遍历从右边到左边,lst[::-1] = lst.reverse()
相关函数:
enumerate(): 将一个可迭代对象转化为key value迭代器
len():求一个可迭代对象的长度
iter():将一个可迭代对象转化为一个迭代器
next():求一个迭代器的下一个值
17、解构与封装
1、x, y = y, x 这样就可以直接把x、y的值交换
2、lst = [1, 2]
first, second = lst 这样就可以把线性结构赋值给变量
3、t = 1, 2 # t为一个元组 与 t = (1, 2) 等效
封装:定义一个元组,可以省略小括号,封装出来的一定是一个元组
解构的变化:
lst = list(range(1000))
head, *mid, tail = lst 这样的话,head=1,tail=999,mid=剩下的。加*号代表的是剩下的所有元素。
python的一个惯例,用单个下划线_表示丢弃该变量,但是_也是一个合法的标识符,通常不要用_来表示。
当上一个语句有out时候,值就会被主动保存到_这个变量中。(ipython)
多层次解构:
_, (_, val), *_ = lst # 这样val就得到一个值,解构可以支持多层次
用的最多的地方:
key, _, value = 'env = prod'.partition('=')
key=> env
value=> prod
18、集合与集合操作
数学意义上的集合:
定义:
s = set()、s = set(range(3))、s = {1,2,3,4}
增加元素:
s.add(2) 原地修改。
s.update(range(1,30)) 增加一个可迭代对象,原地修改。对于已经存在的元素什么也不做。不存在的话,追加进
删除元素:
s.remove(2) 原地修改。删除不存在的时候,报错keyerror
s.pop(2) 删除并且返回被删除的元素,元素不存在抛出keyerror,随机的pop出元素。
s.clear() 清空set
s.discard(3) 删除不存在的时候,不报错,什么也不做。
修改:
集合不能修改单个元素
查找:
集合不能通过索引来访问,没有访问单个元素的方法,不是线性结构。集合元素没有顺序。
成员运算符:判断一个元素是否在容器中。
in、not in
集合的成员运算符和其他线性结构的时间复杂度不同
做成员运算的时候集合的效率远高于列表
做成员运算时,列表的效率和列表的规模有关O(n)
做成员运算时,集合的效率和集合的规模无关O(1)
%%timeit ipython的功能
集合的运算
s1 = {1, 2, 3}
s2 = {2, 3}
s1.intersection(s2) 交集运算
s1.intersection_update(s2) 交集运算,运算完后将结果赋予s1
s1 & s2 交集运算,set将按位与运算符为求交集运算
s1.difference(s2) 求差集
s1.difference_update(s2) 差集运算,运算完后将结果赋予s1
s1 - s2 差集运算,set重载了 -
s1.symmetric_difference(s2) 对称差集,不同时在两个集合。
s1.symmetric_difference_update(s2) 对称差集,不同时在两个集合。将返回的结果赋值于s1
s1 ^ s2 对称差集,重载了异或
s1.union(s2) 并集计算。
s1.update(s2) 并集的update版本,将球出来的结果赋值给s1
s1 | s2 并集计算,重载了按位或。
集合相关的判断
s1 = {1, 2, 3, 4}
s2 = {2, 3}
s2.issubset(s1) 返回bool,判断s2是否是s1的子集。
s1.issuperset(s2) 返回bool,判断s1是否是s2的超集。
s1.isdisjoint(s2) 是不是不相交的,返回bool。如果两个集合没有交集,返回false
集合的应用
有一个api,它要求有认证,并且有一定权限才可以访问,例如要求满足权限A,B,C中任意,有一个用户具有权限B,C,D ,那么此用户是否有权限访问此api。
有一个任务列表,存储全部的任务,有一个列表,存储已经完成的任务,找出未完成的任务。
集合的限制
集合的元素不能重复
集合的元素不能是list、bytearray、set本身
集合的元素可以是tuple、bytes
集合的元素必须可hash,用hash(obj) 来看是否可hash
19、字典
字典是一种key-value结构,是没有顺序的,不是线性结构。
d = {}
d = dict()
d = {'a': 1, 'b': 2}
d = dict([('a', 1), ('b', 2)]) 可迭代对象的元素必须是一个二元组,二元组的第0个元素为字典的key,第一个元素为字典的value,也可以是一个字典。
d = dict.fromkeys(range(5), 'abc') 传入的可迭代对象的元素为key,值为abc,生成:{0: 'abs', 1: 'abs', 2: 'abs', 3: 'abs', 4: 'abs'}
字典的基本操作
增加与修改:
d['a'] = 1 直接使用key作为下标进行赋值。如果下表不存在,会增加kv对。
d.update([('a', 2), ('b', 0)]) 增加一个可迭代对象,必须为二元组,也可以传入一个dict,如果已经存在key,则更新key的值。通常用来合并字典。
删除:
d.pop(key) 将key=key的元素删除。并返回其value,如果key不存在,那么抛出keyerror。
d.pop(key, 'default') 如果指定默认值,那么key不存在,不会抛出异常,会返回default。
d.popitem() 返回一个元组,随机的删除一个key-value对。
d.clear() 清空一字典。
读取:
d['c'] 取下标为c的值,如果下标不存在,抛出异常
d.get('c','default') 返回下标的值,如果下表不存在,那么返回默认
d.setdefault('c', 'default') 先调用get(k, 'default'),如果存在c,那么不会对c的value产生影响,如果不存在c,那么c的value设置为default。
遍历:
字典的元素是成对出现的。
d.values() 返回字典的值,是一个可迭代对象。
d.items() 返回字典的k-v 对。
d.keys() 返回字典的所有的keys。
python2和python3在上边的返回不同之处为,2返回的是列表。3返回的是生成器,3中不会复制出一份内存。数据规模大,2就会占用很大内存。
python2中对应使用:
d.iterkeys()、d.iteritems()、d.itervalues() 返回对于的迭代器。
for x, y in {'a': 'c', 'b': 1 }.items(): 来遍历。
字典的限制:
key 必须是可 hash
value 没有限制。
字典的变体:
默认字典:
from collections import defaultdict
初始化的时候需要传入一个函数,这个函数也叫工厂函数,当我们使用一个key的时候,如果这个key不存在,defaultdict会自动调用初始化时传入的函数,生成一个对象作为这个key的value
这个工厂函数可以自定义,然后返回一个值。
有序字典:
from collections import OrderedDict
有序字典,会保持插入时的顺序。既要求是一个key-value,又要求是一个有序的,可以用到。
19、列表解析式,得到的结果是列表。
[ x * x for i in [1, 2, 3, 4, 5]] 使用简洁的语法实现一些功能,效率稍微高一些。
[ x for x in range(10) if x % 2 ==0] 列表解析式可以添加if子句。
[ x for x in range(10) if x %2 == 0 if x < 5] 可以写多个if子句。
[ x for x in range(10) if x %2 ==0 and x < 5] 可以加多个逻辑运算
[(x, y, z) for x in range(5) if x > 2 for y in range(5) if y > 1 for z in range(5) if z > 3] 可以存在多个for 和 多个if
使用列表解析让代码更简洁。一眼看不出解析式结果是什么时候,那就不要用了
x ** 2 if x % 2 ==0 else x ** 3
和解析式比较像,叫if表达式代表当条件满足时返回x ** 2,当条件不满足时返回 x ** 3 ,只能是双分支可以,2.7以上可以。
[ x ** 2 if x % 2 == 0 else x ** 3 for x in range(10)]
20、生成器
g = (x ** 2 for x in range(100000)) 如果最外边的是[],那么返回列表,占用内存,如果用小括号,那么返回一个生成器。不占用内存。
next(g) 求这个值得时候才会计算。
生成器不支持下标操作,需要下标访问的时候用列表解析。只需要对结果迭代的时候,优先使用生成器。
21、集合解析
{x for x in range(10)} 外边是大括号,其他和列表解析是完全一样的
22、字典解析
{str(x): x for x in range(10)} 左边的表达式是用:隔开的,所以是字典解析式。
23、可迭代对象与迭代器
可迭代对象都有__iter__方法。这个对象可以在for x in obj中出现。
迭代器是可迭代对象,迭代器都有next方法。list数据类型是一个可迭代对象,但是不是一个迭代器。
可迭代对象可以转换为迭代器。迭代器可以使用next方法。从迭代器中取出下一个元素。
迭代器会保存一个指针,指向迭代对象的当前元素
可迭代对象可以使用iter方法来转换为迭代器。
for in 循环对于可迭代对象:首先调用iter方法转化为迭代器,然后不断地调用next方法,直到抛出异常。
24、函数
函数定义指定多种参数
参数默认值
def inc(base, x=2):
调用时传递的话,就使用传递的,如果不传递,那么就使用默认
调用时默认值写道最后。
可变参数
def sum(*args): 参数前加* 表示这个参数是可变的,传参只能以位置参数的形式,args 构成一个元组。
def connect(*kwargs): 参数前加2个*表示这个参数是可变的,传参只能以关键字参数的形式,kwargs构成一个字典。
通常来说:
默认参数靠后,可变参数靠后,默认参数和可变参数不同时出现。
25、参数解构
函数调用时,使用一个* 来表示将一个可迭代对象解构成位置参数
def add(x,y):
return x + y
t = [1, 2]
add(*t)==> 3
函数调用时,使用两个* 来表示将一个字典解构成关键字参数
d={x:1, y:2}
add(**d) ==>3
26、keyword-only 参数
def fn(*, x): * 之后的参数只能通过关键字参数来赋值。可以有默认值。
print(x)
27、函数
函数 return None 或者 直接return 是一样的,用来结束函数
python规则指定所有在赋值语句左面的变量都是局部变量
作用域:
是一个变量的可见范围叫做这个变量的作用域。函数内部是一个局部作用域,不能直接用全局作用域的变量。
变量的作用域为变量定义同级的作用域。
上级作用域对下级作用域只读可见。下级只能看见上级,不能修改。
全局变量:
xx = 1
def fn():
global xx # global 可以提升变量作用域为全局变量,提升只是一个标记,并没有定义。注意提升支队本作用域有用。如果要在其他非全局作用于使用,也要使用global提升。
xx += 1
print(xx) ==> 2
闭包
函数已经结束,但是函数内部部分变量的引用还存在,python的闭包可以用可变容器实现。py2唯一的方式。
nonlocal关键字
def counter():
x = 0
def inc():
nonlocal x # nonlocal 关键字用于标记一个变量由他的上级作用域定义。通过nonlocal标记的变量,可读可写。
x += 1
return x
return inc
函数默认参数的作用域:
def fn(xxyy=[]):
xxyy.append(1)
print(xxyy)
这个参数多次调用,xxyy的值会一直加,造成这种情况的是,xxyy其实是fn函数的一个对象的变量fn.__defaults__,因为函数也是一个对象。而且函数定义在全局作用域。
def fn(a=0, b=0):
a = 1
b = 1
这个参数多次调用,a、b的值也都是0,因为赋值既定义,上边那个例子没有对xxyy重新赋值,只是做了append。而此例子中,做了重新赋值。
解决方法:
1、使用不可变类型作为默认值,通常如果使用一个可变类型作为默认参数的时候,会使用None来代替。
def fn(lst=None):
if lst is None: # 如果是默认的话,就将其赋值为一个列表,也就实现了默认参数为可变类型的功能。
lst = []
lst.append(3)
print(lst)
2、函数体内不改变默认值