0%

Python语法笔记

python语法笔记


  • 文档中outs:为终端输出的内容

py基本元素(变量,数字,字符串)

python的内建数据类型包括布尔,整形,浮点及字符串

变量(variable)

py的变量本质上是一个c语言的结构体(struct),就像在一个盒子中预先分配好了布尔类型的空间,整形的空间,浮点的空间,字符串的空间。因此py的变量本身可以看成是一个对象(object)的实现,所以使用时不需要实现定义变量类型

1
2
3
4
5
6
7
8
9
10
#因为以上特性,以下的操作时合法的
a = 7
print(a)
a = "abc" #值得注意的时py中表示字符串既可以用‘也可以“
print(a)
a = 'abc'
print(a)
#out: 7
#out: abc
#out: abc

关于变量名,同样由大、小写字母,下划线,数组组成,且数字不能在变量名中作为首个字符。另外,py的保留字符也不可作为变量名出现,如下图:

![reserved keyword](C:\Users\83487\Pictures\programmer path\reserved keyword.jpg)

str-byte

1
2
bytes(string,'utf-8')
string.encode('utf-8')

byte-str

1
string.decode('utf-8')

字符串(string)

  • 用方法对字符串进行操作(usage:变量名.方法名()
  1. 获取长度可以使用len()

  2. 提取字符串使用[](这并不是一个方法)(允许负值)

  3. 拼接 字符串可以直接用+

  4. 复制字符串可以使用*

  5. 分片 (silce)usage:[start:stop:step] 3s法(

  6. 删除 字符串末尾的空白可以用方法rstrip()

    删开头的空白lstrip()

    删两头的空白strip()

  7. 转义 使用反斜杠 \ ,可以用\t或者\n

  8. 分割 字符串spilt(),返回一个列表(之后会介绍)

  9. 合并字符串可以使用join(),本质是将列表还原成字符串

  10. 字符串中单词首字母大写 使用title(),同样的,.upper()&.lower()是变成整个字符串大写和小写

  11. 字符串转数字 使用eval函数,只接收字符串,如果输入123py会解释是一个123的数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#一个简单的字符串例子
id_info = "my name is Atuoa"
print(len(id_info)) #len
#outs:16

new_idinfo = id_info.replace('Atuoa',"harry")
print(new_idinfo) #replace,也可以使用正则表达式匹配
#outs:my name is harry

print(id_info[11:16]) #slice
#outs:Atuoa #这里注意一下,第一个字符下标为0,实际取值范围[11,16)
#如果id_info[0]则是'm'单个字符
#如果是id_info[-1]则是'a'单个字符

print(id_info * 3 )#copy
#outs:my name is Atuoamy name is Atuoamy name is Atuoa

print(id_info.split())#默认按照空格、制表符、换行符分裂
print(id_info.split('i')) #含参数即基于参数分裂字符串
#outs: ['my', 'name', 'is', 'Atuoa']
#outs:['my name ', 's Atuoa'] #list列表形式,这里暂且不讨论

add_info = ",whats your name?"
greet_you = id_info + '\t' +add_info #转义与+
print(greet_you)
#outs:my name is Atuoa ,whats your name?

tmp = ' '.join(add_info.split()) #join
print(id_info,tmp)
#outs:my name is Atuoa ,whats your name?
#join的调用其实有点变扭用的也比较少,usage:string.join(),括号中参数 是一个列表,这里暂且不讨论,后面有详细提及
  • 字符串前缀

    1. 字符串前加 u或者不加

    举例:u”字符串中有中文”
    含义
    1、前缀u表示该字符串是unicode编码
    2、Python2中用,用在含有中文字符的字符串前,防止因为编码问题,导致中文出现乱码。
    3、一般要在文件开关标明编码方式采用utf8。
    4、Python3中,所有字符串默认都是unicode字符串。

    1. 字符串前加 r

    举例:r”adc\n\r\tdkfjkd”
    含义
    1、前缀r表示该字符串是原始字符串,即\不是转义符,只是单纯的一个符号。
    2、常用于特殊的字符如换行符、正则表达式、文件路径。
    3、注意不能在原始字符串结尾输入反斜线,否则Python不知道这是一个字符还是换行符(字符串最后用\表示换行)

    1. 字符串前加 b

    含义
    1、前缀b表示该字符串是bytes类型。
    2、用在Python3中,Python3里默认的str是unicode类。Python2的str本身就是bytes类,所以可不用。
    3、常用在如网络编程中,服务器和浏览器只认bytes类型数据。如:send 函数的参数和 recv 函数的返回值都是 bytes 类型。
    4、在 Python3 中,bytes 和 str 的互相转换方式是
    str.encode(‘utf-8’)
    bytes.decode(‘utf-8’)

    1. 字符串前加 f
    1
    2
    3
    4
    5
    6
    7
    def testFStr():
    name = 'alex'
    age = 25

    print(f'my name is {name}, i am {age} years old')

    testFStr()

    含义

    1、Python3.6新加特性,前缀f用来格式化字符串。可以看出f前缀可以更方便的格式化字符串,比format()方法可读性高且使用方便。
    2、而且加上f前缀后,支持在大括号内,运行Python表达式。
    3、还可以用fr前缀来表示原生字符串。

更多:

string官方文档

数字(number)

运算符号 含义
+ 加法
- 减法
* 乘法
/ 除法
// 整除(也叫地板除法floor division)
% 求模(取余)
** 乘幂

简单的介绍三个数字函数:

divmod()接受两个参数,返回一个元组(tuple)第一个值为商,第二值为余数

1
divmod(9,5)

int() ,括号内可以接受整形或浮点型变量,但不能是字符串

str()函数可以将数值转换为字符串

1
2
3
4
greet = "hello"
name = 123
print(greet,str(name))
#outs:hello 123 #print中

py2中 整数/整数依旧是向下取整 ,类似于c++

py3中 会显示正常计算的结果

更多:

math官方文档

python内建的数学函数执行效率较低,占用内存较大,所以介绍的相对较少,一般py用于大数据处理时会用第三方的库numpy。

注释 (annotation)

  • 采用#发起的单行注释
  • 采用'''或者"""引起的多行注释

利用 \连接两行字符

可以使用反斜杠(\)来连接两行内容,将其放在第一行的末尾,py将第二行和第一行解释为1行

1
2
3
4
example = 'abc' + \
'defg'
print(example)
#out : abcdefg

py容器(列表,元组,字典,集合)

列表(list)

列表可以近似的理解成一个数组,下面是一个列表的例子

  1. 指定元素创建列表

    usage:列表名 = ['元素1','元素2','元素3','元素4'] (单引号+方括弧)

    输出print(列表名[0]) 即为 “元素1”

    tips:元素可以是任意的py对象,可以是变量,或者是新的列表和元组(姑且称之为嵌套,无统一叫法,叫套娃也行?)

  2. 利用list()方法创建一个空列表

    1
    2
    3
    another_empty_list = lsit()
    print(another_empty_list)
    #out:[] #表示打印了一个空数组 ,列表可以直接打印

    list()不仅只有这些功能,(始终记住py中表示字符串单双引号均可,习惯单引号)list函数参数接受一个字符串

    1
    2
    3
    4
    5
    6
    7
    8
    #将一个英文单词转化为列表
    list_cat = list('cat')
    print (lsit_cat) #outs:['c','a','t']

    #将一个元组转化为列表
    alphabet = ('a','b','c')
    print (list(alphabet))#outs:['a','b','c']

由于列表中包含各种元素灵活特性(见上一个tips)所以一些看起来很奇怪的套娃也是可以通过编译的

1
2
3
4
5
element = 'a'
a_tuple = ('hey','hello')
example = ["e1","e2",2,element,a_tuple]
print(example)
#outs: ['e1', 'e2', 2, 'a', ('hey','hello')]

当然为了不让自己逻辑混乱尽量少用套娃

列表的方法

  • 修改值 列表名[0] = '元素0',这样原列表中的“元素1”就被修改成了“元素0”

  • 添加元素 利用方法 append ()

    列表名.append('元素5'),这条代码会在列表末尾加一个“元素5”

    此方法参数可以填另一个列表甚至元组

  • 批量添加元素 利用方法extend()或者+=(推荐,类c语法)

    1
    2
    3
    4
    5
    family = ['mother','father']
    ext_family = ['me']
    family += ext_family
    print(family)
    #outs: ['mother', 'father', 'me']
  • 插入元素 利用方法 insert()

    列表名.insert(0,'元素0'),这条代码会在原本“元素1”的位置插入一个”元素0”,且此后的每一个元素右移一个位置

  • 删除元素

    del 列表名[0]这样就删除了原列表中的“元素1”,不可以继续使用他的值

    列表名.pop() pop会删除列表末尾的元素,概念来自于栈,弹出最后一个,此时可将弹出的元素存储在一个变量中,可以继续使用他的值

    列表名 .remove('元素0'),根据元素值进行删除,若存储在一个变量中,也可以继续使用他的值

  • 组织列表(排序)

    列表名.sort() 可以根据首字母顺序排序

    上述sort方法中括号内可以加入参数 reverse = True字母倒序排序

    sort对元素的顺序修改时永久的

    sorted()函数用于临时排序不影响列表中的原始排序

    也可以使用reverse = True 来实现字母倒序

  • 倒着打印列表

    利用方法reverse(),是永久性修改顺序

    顺便一提,切片的方法依旧可以在列表当中使用,比如逆序列表可以巧妙地使用list_name[::-1]

​ 利用函数len()可以快速得到列表的长度,ps:py计算列表元素数是从1开始算起,不用考虑0的计数

  • 获取元素在列表中的位置

    ​ 使用方法index()

    1
    2
    3
    4
    5
    test = ['a','b','c']
    test.index('a')
    #outs: 0
    test.index('b')
    #outs: 1
  • in判断元素是否在列表中

1
2
3
4
5
6
test = ['a','b','c']
print('a' in test)
#outs: True
print('atuoa' in test)
#outs: False
#返回值为逻辑真假
  • 使用方法count()统计元素在列表中出现次数

    usage:list_name.count('element')

  • 使用join()转换为字符串

1
2
3
test = ['a','b','c']
print(','.join(test))
#outs:a,b,c
遍历列表
1
2
3
magicians = [ 'alince' , 'david' , 'carolina']
for magician in magicians :
print(magician)

改段代码示例中用了for循环,magician是一个变量,magicians是一个列表,可以用变量来遍历整个列表

不要忘记冒号,表示下一行是循环的第一行

python要求强制缩进,注意缩进可能引发的问题


数值列表
  • 函数range生成数字
1
2
3
for value in range(1,6) #[1,6)
print(value)
#outs:1,2,3,4,5

输出数字1-5,6取不到

range 可以指定步长 例如range(2,11,2)

则是该函数从2至11步长为2

  • 使用list()函数来创建数字列表

    1
    2
    3
    numbers = list (range(1,6))
    print (numbers)
    #outs:[1,2,3,4,5]
  • 对数值列表的简单统计计算

    max(),min(),sum()三个内建函数

    usage:sum(list_name)

  • 列表解析

    1
    2
    3
    4
    # 列表名  表达式(range的) 变量      范围      
    squares = [value**2 for value in range (1,11)]
    print(squares)
    #outs:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

    可以减少代码行数

  • 将字符串列表转换为数值列表

map函数第一个参数接受数值转换的类型,第二个参数是待转的字符串;但是map函数的返回值是一段内存空间,不能直接打印还需要用list函数转换为列表,这样就变成数值函数了

关于数值列表与字符串列表的相互转换

1
2
3
4
5
6
7
8
9
10
11
12
13
#number_list convert string_list
number_list = [1,2,3]
str_list = []
for ele in number_list:
str_list.append(str(ele))
print(str_list)
#outs:['1', '2', '3']

#number_list convert string_list
str_list = ['4','5','6']
number_list = list(map(int,str_list))
print(number_list)
#outs:[4,5,6]
切片

作用 :输出部分列表

与range方法相同,切片的[0:3]表示也是0,1,2三个元素,不包括3,即[0,3)

切片可以缺省[:3]就是表示从列表的第一个元素开始

可以用负数作为索引,例如[-3:]就是指该列表的最后三个元素

  • 遍历切片

    仅将for循环中的列表换成切片即可实现例如

1
2
3
# 省略列表的定义 #该段程序省略了玩家名字,效果就是名字首字母大写输出
for player in players[:3]
print(player.title() )
  • 复制列表
  1. 使用.copy()方法
  2. list()转换函数
  3. 列表分片法copy_list = list_name[:]

值得一提的是,复制列表并不可以直接用列表名 = 列表名的形式,会导致两个变量名都指向一个列表的情况,一般使用缺省的切片来实现复制列表操作例如

1
2
3
4
5
test_list = ['a','b','c']
copy_list = test_list.copy() #.copy()方法实现
copy_lsit = list(test_lsit) #list转换函数
copy_list = test_list[:] #列表分片法实现

这样就可以实现复制列表的操作,若直接用列表名=列表名的形式 copy_list = test_list,就会导致两个列表变量指向同一个列表的情况,有点类似c系语言中两个指针指向同一个内存区域

元组(tuple)

与列表不同,元组无法改变元素的值,用小括弧“(”“)”引起的,先从建立一个元组开始

1
2
3
empty_tuple = ()
print(empty_tuple)
#outs: ()

建立一个非空元组

1
2
3
4
5
6
test = (1,3) #定义元组时可以去掉括号,但加上括号语法更清晰
print(test[0])
#outs:1
a,b = test #将元组分给多个变量,该过程称为元组解包
print(a,b)
#outs: 1 3

语法与列表基本相同,少了很多方法,与列表list()相对的方法,元组有tuple()作用是将其他类型转换为元组

1
2
3
4
family = ['monther','father','me']
tuple_family = tuple(family)
print(tuple_family)
#outs:('monther', 'father', 'me')

重要特性:

元组无法更改元素 ,但是可以更改整个元组变量,例如

1
2
3
4
5
6
test = (1,2)
for t in test:
print (t)
test = (3,4)
for t in test:
print(t)

使用中,元组使用的相对较少,以下是元组的一些优点;

  • 占用内存小
  • 值不会被意外篡改
  • 可以作为字典的键
  • 函数的参数是以元组的形式传递的
  • 命名元组(named tuple)可以作为对象替代(下文类中提到)

字典(dictionary)

创建一个字典

字典用于存储一个键值对应类型,按照惯例,从创建一个空字典开始

1
2
3
empty_dictionary = {}
print(empty_dictionary)
#outs:{}
1
2
3
4
alien_0 = {'color':'green','points':5}

print (alien_0['color'])
print (alien_0['points'])

字典“键-值”对应,每一组之用逗号隔开

更改字典的值alien_0['color']= 'yellow'

删键只需要键本身del alien_0 ['color']如此便会删除color的值

遍历字典

利用for循环来遍历字典操作,事先加了一点for循环,应该可以理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
user_0 = {
'username' : 'efermi', #key : value
'first' : 'enrico',
'last' : 'fermi',
}
for key,value in user_0.items():
print ("\nkey: " + key)
print ("value: " + value)
#outs:
'''key: username #多行注释,输出无三个单引
value: efermi

key: first
value: enrico

key: last
value: fermi'''

items()方法是将键和值取出的方法,同样的,仅需要值(values)可以用方法values(),返回值是列表(dict_keys()非完整列表)

添加或修改元素

与列表不同的是,字典没有那么多的方法用于添加和修改元素,而是提供一个更简洁的语法,例子如下

usage:dict_name ['key']='value'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
traffic = {'cars':'car',
'bikes':'bike',
'bikes':'pedestrian'
}
print(traffic)
#outs:{'cars': 'car', 'bikes': 'pedestrian'}
#py不允许一个字典中key重复,如果重复,就会像上面一样被后面出现的值替换
traffic['bikes'] = 'bike'
print(traffic)
#outs:{'cars': 'car', 'bikes': 'bike'}
#这样就正常啦,完成了一个修改值的操作
traffic['places'] = 'place'
print(traffic)
#outs:{'cars': 'car', 'bikes': 'bike', 'places': 'place'}
#添加键值对也可以用这种方式直接完成

使用update()合并两个字典

usage:old_dict_name.update(add_dict_name)

同样的,如果合并进来的字典中键与原字典中键重复,则新键覆盖旧键

使用del删除键值对

usage: del dict_name['del_key']

使用clear()删除所有元素

usage:dict_name.clear()变成一个空字典

使用in判断是否存在字典中

usage: 'search_key' in dict_name返回值为Ture/False

字典转列表(使用list())

因为在列表中提过list()的用法,这里再次提及一是为了回顾,二是字典转列表的操作往往可以和json的数据格式解析对应起来,而获取api返回的格式json正在成为主流,下面加粗文字也是踩过的一个坑。

仅需要键(keys)可以用方法keys(),实质是返回一个列表(dict_keys()非完整列表),可以用于遍历和查询,此方法返回的不是一个完整的列表(是一种迭代形式),如需转换成完整的列表,可以用list()方法,另外items(),values()也相同,如下(这里还有一点就是py2.7中返回的时一个完整的列表而不是迭代器,不过现在2.7停止维护基本使用的都是py3,这里当作了解下)

  • keys()获取所有键,返回一个列表(不完整)

  • value()获取所有值,返回一个列表(不完整)

  • items()获取所有键值对,返回一个列表,每一个键值对都以元组的形式存在

    1
    2
    3
    4
    5
    6
    7
    8
    traffic = {'cars':'car',
    'bikes':'bike',
    'bikes':'pedestrian'
    }
    print ( traffic.items())
    print(traffic.keys())
    #dict_items([('cars', 'car'), ('bikes', 'pedestrian')])
    #dict_keys(['cars', 'bikes'])

    这部分有点绕,上机写一下会清楚很多

usage:

1
2
3
4
5
6
7
signals = {'green':'go','yellow':'go fast','red':'stop'}
signals.keys()
#outs :dict_keys(['green','yellow','red'])
#call func "list()" to transfer an normal list
list( signals.keys() )
#outs ['green','yellow','red']
#this is a normal list

列表转字典(使用dict()

使用dict()可以将双值子序列的序列(可以是元组、列表)转换为字典,每个子序列的第一个元素做为key,第二元素作为value.(双值子序列即序列中每个元素符合“键-值对应”的序列)

usage:

1
2
3
lol = [['a','b'],['c','d'],['e','f']]
dict(lol)
#outs {'c':'d','a':'b','e':'f'}

通过对包含重复元素的列表调用set()函数可以让python找出去重的数据 (在集合中会详解)

  • 字典列表,列表当中套字典
1
2
3
4
5
6
7
8
alien_0 = {'clolor':'green','point':5}
alien_1 = {'color':'yellow','point':10}
alien_2 = {'color':'red','point':15}

aliens = [alien_0,alien_1,alien_2]

for alien in aliens:
print(alien) #用这种方法可以输出字典,列表当中套字典
  • 在字典中存储列表,字典当中套列表
  • 在字典中嵌套字典

使用=赋值或使用.copy()

与列表一样,使用等于会将原数据与新数据建立联系,修改其中一个,另一个也跟着改

如果想要避免“一损俱损”的情况,使用.copy()创建一个副本

usage: copy_dict = old_dict.copy()

以上是浅拷贝,一个修改会导致其他也修改,如果要数据互相不影响使用深度拷贝

1
2
import copy
new_one = copy.deepcopy()#括号中可以是列表或者字典等

集合(set)

集合的概念和离散数学的概念重合,不再赘述,值得强调的一点是,集合中的元素不能重复且无序的

使用set()创建集合

依旧是从一个空的集合开始

1
2
3
4
5
6
7
8
empty_set = set()
print(empty_set)
#outs: () #为什么集合不是花括号?
#仅仅是因为py中字典出现的比集合早罢了,占了集合的位置
#以下是非空集合
even_number ={0,2,4,6,8}
print(even_number)
#outs: {0,2,4,6,8}
  • set()将其他类型转换为集合

如前文所述,set()可以将列表转换为集合实现去重的作用(利用集合非重的特性)

  1. 字符串去重
1
2
3
a= 'letter'
print(set(a))
#outs: {'l', 't', 'r', 'e'}
  1. 列表元素去重
1
2
3
traffic= ['car','bike','plane','plane']
print(set(traffic))
#outs: {'bike', 'car', 'plane'}
  1. 元组元素去重
  2. 字典建立集合只有键(key)会被使用

使用in测试值是否存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#定义几种混合饮料,用字典表示,key是饮料名字,value是一个集合
drinks = {
'martini': {'vodka', 'vermouth'},
'black russian': {'vodka', 'kahlua'},
'white russian': {'cream', 'kahlua', 'vodka'},
'manhattan': {'rye', 'vermouth', 'bitters'},
'screwdriver': {'orange juice', 'vodka'}
}
#name和contents是字典中的key-vaule
for name, contents in drinks.items():
if 'vodka' in contents: #寻找有伏特加的饮料 (vodka-伏特加)
print(name) #for ,if语句要求强制缩进,具体会在代码结构中提及,这里理解就ok

'''
outs:
screwdriver
martini
black russian
white russian
'''
#需要伏特加,但不要苦艾酒,不加乳糖
for name, contents in drinks.items():
if 'vodka' in contents and not ('vermouth' in contents or 'cream' in contents):
print(name)
#这段直接搬的书,加了点注释,py解释性语言的特性应该不难理解,详细的语法会在后面提及
#outs:
# screwdriver
# black russian

运算符

  • 交集

使用&或者intersection()获取集合的交集

1
2
3
4
5
6
a = {1,2}
b = {2,3}
print (a & b)
#outs: {2}
print(a.intersection(b))
#outs:{2}
  • 并集

使用|或者union()获取集合的并集

  • 差集

使用-或者difference()获取集合的差集

不常见的集合运算:

  1. 使用^或者symmetric_difference()可以获得两个集合的异或集(仅在两个集合中出现一次)

  2. 使用 <= 或者 issubset() 可以判断一个集合是否是另一个集合的子集(第一个集合的所有 元素都出现在第二个集合中)

  3. <可以表示真子集

  4. 超集与子集正好相反(第二个集合的所有元素都出现在第一个集合中),使用 >= 或者 issuperset() 可以进行判断

  5. 使用 > 可以找到一个集合的真超集(第一个集合包含第二个集合的所有元素且还包 含其他元素)


py外壳(代码结构)

这块内容比较简单,均是常见的结构,比如for,while,if,else,break,continue等,使用时需要注意的是py代码要求的强制缩进 ,和其他一些语法规范(主要介绍和c类语言的区别)。有的时候会出现奇怪的报错提示:

unindent does not match any outer indentation level这就是忘记缩进了…也是个坑,之前有笑话说写py拿着游标卡尺量还是挺真实,pycharm的自动代码格式化功能挺好用的ctrl+alt+L

用户输入

使用函数input()

1
2
name = input ("please enter your name :")
print ("hello, "+ name + "!")

input 函数在运行过程中将输入解释为字符串而不是数字,若要数字要使用int()函数进行转换

int()来进行数值的输入,可以看成是str()的对应函数

  • 求模运算符 %,返回余数

在py2.7中应使用函数raw_input()来提示用户输入

if条件

lower()可以将函数大写变成小写但不会保存,可以用于忽略大小写的比较

!= 依旧表示逻辑非 and 表示逻辑与 or表示逻辑或
== 依旧表示条件判断

  • 可以利用关键字in来检查值是否已经包括在列表中
1
2
3
test = {'a','b','c'}
if 'a' in test: #需要加冒号
print("find a")
  • 同样的利用not in关键字来检查特定的值是否不含在列表中

if条件判断,代码执行块也要缩进

  • if语句

    1. 单if格式
    2. if-elif语句
    3. if-elif-else语句
    4. 多个elseif语句块及省略else语句
  • if语句块不需要用小括号括起来 ,且句末需要加上冒号

  • 不同于c类语言,5<x<10这样的语句在py中是可行的

while循环

和c系语言一样拥有break,continue等

与c系语言不同,py的while循环for循环也可以使用else语句,如果 while 循环正常结束(没有使用 break 跳出),程序将进入到可选的 else 段 ,概念与if-else不同,个人理解:循环通常是为了寻找某个元素,如果找到就break了,不需要进行else继续判断;反之循环没有触发break条件则需要else即续进行判断

for循环,使用迭代器(iterator)

1
2
3
4
5
6
7
8
9
10
11
12
#对c类语法熟悉可能会写出如下代码
numbers = [1,2,3,4,5,6]
tmp = 0
while(tmp<6):
print(numbers[tmp])
tmp+=1
#outs:1 2 3 4 5 6
#这代码并没有错,但是有更优解,简化代码
numbers = [1,2,3,4,5,6]
for number in numbers:
print(number)
#将代码改成这样,使其更有py风格,提高易读性

上例中的方法可以称之为迭代器,py中list,directionary,string,tuple,set均是可以迭代的对象。元组/列表在迭代的过程中产生一项,而字符串会产生一个字符,对一个字典进行迭代会返回字典的所有key(和函数keys()功能相同),若是对字典的value和item进行迭代可以用.value(),.items()方法,详见上文“字典转列表”小节

使用zip()进行并行迭代

并不是zip压缩的那个标准(

我找了半天也没找到zip这个名字怎么来的

1
2
3
4
5
6
7
8
9
10
11
a = ("John", "Charles", "Mike")
b = ("Jenny", "Christy", "Monica", "Vicky")

x = zip(a, b)

#这里我贴了一个w3cschool的示例代码
#use the tuple() function to display a readable version of the result:

print(tuple(x))
#outs:(('John', 'Jenny'), ('Charles', 'Christy'), ('Mike', 'Monica'))
#以长度短的为标准输出,此例中短的3个元素,就输出三个键值对。这里返回的也是一个迭代类型,实际应用中可以用dict()转换字典进行进一步处理

上例中使用了zip()函数,通俗的理解就是将两个分开东西(支持迭代的对象,元组,列表等等)凑成了一对,并且取短输出,扯了那么多zip还没讲到并行迭代,现在回归正题

1
2
3
4
5
6
7
8
9
a = ("John", "Charles", "Mike")
b = ("Jenny", "Christy", "Monica", "Vicky")

for f_name,l_name in zip(a,b):
print(f_name,l_name)
#outs:
#John Jenny
#Charles Christy
#Mike Monica

运用:两个列表和成一个字典

1
2
3
la = ['name', 'age']
lb = ['charles', 'unknown']
me = dict(zip(la,lb))

推导式(生成式)(comprehensions)

  • 列表推导式

usage:[expression for item in iterable if condition]

1
2
3
a_list = [number for number in range(1,6) if number % 2 == 1]
print(a_list)
#outs: [1, 3, 5]

第一个 number 变量为列表生成值,也就是说,把循环、判断的结果放在列表 a_list 中。第二个 number 为循环变量,在循环的时候执行if判断语句,只把奇数存入第一个number(列表生成值)

  • 字典推导式

usage:{key:value for key,value in iterable if condition}

1
2
3
4
my_dictionary = {'customer1': 7, 'customer2': 9, 'customer3': 11}
my_results = {key : value for key, value in my_dictionary.items() if value > 10}
print(my_results)
#outs: {'customer3': 11}

类似列表推导式

  • 集合推导式

usage:{expression for item in iterable if condition}

1
2
3
a_set = {number for number in range(1,6) if number % 2 == 1}
print(a_set)
#outs: {1, 3, 5}

函数

1
2
3
4
5
def func()
"""显示简单的问候语"""
print("hello!")

func()

形参和实参

  • 位置实参
1
2
3
4
5
def pet(animal_type ,pet_name):
print("\n I have a "+animal_type)
print("My"+animal_type+"'s name is "+pet_name.title())

pet ('hamster','harry')
  • 关键词实参
1
2
3
4
def pet(animal_type,pet_name):
print("\n I have a "+animal_type)
print("My"+animal_type+"'s name is "+pet_name.title())
pet(animal_type = 'hamster',pet_name='harry')#此时可以随意调换位置
  • 可以形参设定默认值,animal_type='dog'使用默认值时必须先列出没有默认值的形参,再列出有默认值的实参

函数返回值

1
2
3
4
5
def get_formatted_name(fitst_name,last_name):
full_name = first_name +' ' + last_name
return full_name.title()
musician = get_formatted_name('harry','smith')
print(musician)
  • 让实参变成可选的
1
2
3
4
5
6
7
8
9
10
11
12
def get_formatted_name (first_name,last_name,middle_name=''):#有默认值的实参放在最后
if middle_name:
full_name = first_name+' '+middle_name+' '+last_name
else:
full_name = first_name+' '+last_name
return full_name.title()
#没有中间名情况
musician = get_formatted_name('harry','smith')
print(musician)
#有中间名情况
musician = get_formatted_name('harry','hamster','smith')
print(musician)
  • 函数可以返回任何类型的值,包括字典,列表
  • 在函数中传递列表
1
2
3
4
5
6
7
8
9
10
11
def greet_users(names):
for name in names:
msg = "Hello,"+name.title()+"!"
print(msg)

usernames = ['hannah','ty','margot']
greet_users(usernames)
#outs:
# Hello,Hannah!
# Hello,Ty!
# Hello,Margot!

禁止函数修改列表,在函数中传入列表时用切片表示法[:]可以表示仅复制不改变原列表的值

传递任意数量的实参

1
2
3
4
5
6
7
8
def make_pizza(*toppings):#*用于建立一个空的元组toppings
print(toppings)

make_pizza('pepperoni')
make_pizza('mushrooms','green peppers','extra cheese')
#outs:
#('pepperoni',) #这里多一个逗号的原因不是编译器坏了,当元组元素为1时会多加一个逗号,而两个以上就可以省略
#('mushrooms', 'green peppers', 'extra cheese')

形参名*toppings创建了一个名为toppings的空元组,并将收到的值全部封装到找个元组中,以此实现任意数量的实参

使用任意数量的关键字实参

1
2
3
4
5
6
7
8
9
10
11
def build_profile (first,last,**user_info):#**用于建立一个空的字典user_info
profile = {} #空字典
profile['first_name'] = first
profile['last_name'] = last
for key,value in user_info.items():#item将key和value取出
profile[key] = value
return profile

user_profile = build_profile('albert','einstein',location='princeton',field='physics')

print(user_profile)

文档注释(文档字符串)

原文翻译中译名是文档字符串,我觉得文档注释更容易理解,就像github上一个项目的readme,在py中文档注释用来描述函数的功能,增加代码的可读性,可以用help(),或者func_name.__doc__

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def print_name(*name):
'it can print name' #这个就是文档注释
print(name) #同样可以用多行注释来写文档注释,有书说py注释没有多行注释,多行注释就是文档注释

print_name('harry', 'atuoa')
#outs:('harry', 'atuoa')

help(print_name) # help(函数名)来获取该函数的具体功能
#outs:Help on function print_name in module __main__:
#
#print_name(*name)
# it can print name

print(print_name.__doc__) #使用__doc__来直接获取文档注释
#outs: it can print name

上例中那个奇奇怪怪的__doc__其实是py的保留用法,本质是也是一个变量,不允许用户自己定义这种名字的变量,通常会除了上例中的用法,还有获取该函数名字的用法func_name.__name__

内部函数、闭包、匿名函数lambda()

  • 这部分内容有点绕,容易混淆,如果你们课程不要求,可以跳过

函数的“优先级”可以说是之前提到过的任何py数据结构都不能比拟的,可以将函数的返回值赋值给变量,作为参数被其他函数调用,从其他函数中返回值

内部函数

内部函数故名思意,就是在内部的函数,在什么内部的函数呢?函数。即在函数内部的函数,函数套娃(

1
2
3
4
5
6
7
8
def outer(a, b):
def inner(c, d):
return c + d
return inner(a, b)

result = outer(5,3)
print(result)
# outs: 8

内部函数和后面的闭包的区别就在于,内部函数获取数据是通过外部函数传参实现的。

闭包

定义如下:闭包是一个可以由另一个函数动态生成的函数,并且可以改变和存储函数外创建的变量的值

简单的说:

  1. 闭包首先得是一个内部函数
  2. 外部函数的返回值必须是内嵌函数
  3. 内嵌函数必须调用外部函数变量

简单理解就行,需要时再查资料 参考

匿名参数lanbda()

还记得那个非洲的英语老师教学生读google的视频吗?这部分的内容就从“咕噜咕噜”开始

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
African_eng_teacher = ['g', 'o', 'o', 'g', 'l', 'e', 'gulugulu']


def accent(word):
return word.title() + '!' #.title()的作用是首字母大写


def read_google(list_name, func): #将函数作为参数调入,read_google(列表,函数)
for i in list_name:
print(func(i))


read_google(African_eng_teacher, accent)
read_google(African_eng_teacher, lambda word : word.title()+'!') #lambda在这用于取代accent函数
'''outs:
G!
O!
O!
G!
L!
E!
Gulugulu!
'''
#两条语句的输出结果相同,均大声的念出了咕噜咕噜

装饰器

装饰器的作用就是在不改变已有源代码的情况下,修改已经存在的函数

装饰器的一般格式:

  1. *args和**kwargs(个人理解是arguments和keyword arguments的意思,一个元组一个字典)
  2. 闭包
  3. 作为参数的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
def sqaure_it(func):   #此装饰器的功能是平方运算
def new_function(*args,**kwargs):
result = func(*args,**kwargs)
return result*result
return new_function

@sqaure_it #装饰器声明,要在使用的函数之前添加装饰器的名字(未选一般格式3)
def add_number(a,b):
return a+b

print (add_number(3,5))
#outs : 64

另一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def info(func):                       #该装饰器实现了函数信息的打印
def new_f(*args, **kwargs):
print('function name is:', func.__name__)
print('add number is :', args)
print('keyword arguments is', kwargs)
result = func(*args, **kwargs)
print('sum is :', result)
return result

return new_f


@info
def add_number(a, b):
return a + b


add_number(3, 4)
'''
outs:
function name is: add_number
add number is : (3, 4)
keyword arguments is {}
sum is : 7

'''

命名空间和作用域

  • 局部变量和全局变量的区别,在函数中如果想要调用全局变量需要先声明global func_name再给全局变量重新赋值
  • py提供了两个获取命名空间的函数
    • locals()返回一个局部变量的字典
    • globals()返回一个全局变量的字典

使用try-expec处理异常

使用try-except代码块,依赖于try成功执行后的代码放在else代码块中

1
2
3
4
5
6
short_list = [1, 2, 3] 
position = 5
try:
short_list[position]
except:
print('Need a position between 0 and', len(short_list)-1, ' but got', position)

另一个例子

1
2
3
4
5
6
try:
do something
except FileNotFoundError: #文件不存在错误
pass #什么都不干,不提示错误
else:
do something

异常处理大同小异,需要时再查阅资料

正则表达式

https://segmentfault.com/a/1190000022242427

正则表达式的模式串patten可以分为两个部分

字符集 数量词

[]表示一个or关系的字符集,[abc]就是表示一个a或者b或者c

数量词是跟在字符集后,表示前面的字符集出现的次数比如{4,7}表示前面的字符串出现4~7次

  • py有一个自带表示一个字符串是另一个字符串字串的函数index()会返回查询子串在字符串中的位置,如果返回-1就是没找到
1
2
3
4
5
6
7
>>> a ="1234454666"
>>> a.index("1")
0
>>> a.index("66")
7
>>> l in a
False

但是正则表达式更加突出的是找到匹配模式的字符串

findall

匹配所有的符合规则串,返回一个list

1.查找一个匹配项

查找并返回一个匹配项的函数有3个:search、match、fullmatch,他们的区别分别是:

  1. search: 查找任意位置的匹配项
  2. match: 必须从字符串开头匹配
  3. fullmatch: 整个字符串与正则完全匹配

search(匹配一个)

从任意位置开始匹配,返回一个

1
2
3
4
5
6
7
8
>>> a="123"
>>> import re
>>> search =re.search("\d","1")
>>> search
<re.Match object; span=(0, 1), match='1'>
>>> search.group()
'1'

返回的是一个re模块的匹配对象

match(匹配一个)

1
>>> match = re.match('ll',"l23333ll111")

因为match必须从开头开始匹配,所以这个匹配不到内容

从字符串开头开始匹配字符串

fullmatch

完全匹配,需要完全匹配

贪婪匹配和非贪婪匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import re

a = 'java*&39android##@@python'

# 非贪婪

re_findall1 = re.findall('[a-z]{4,7}?', a)
print(re_findall1)

# 贪婪
re_findall2 = re.findall('[a-z]{4,7}', a)
print(re_findall2)


# 输出
['java', 'andr', 'pyth']
['java', 'android', 'python']

加了问号就是非贪婪了

2.查找多个匹配项

讲完查找一项,现在来看看查找多项吧,查找多项函数主要有:findall函数finditer函数

  1. findall: 从字符串任意位置查找,返回一个列表
  2. finditer:从字符串任意位置查找,返回一个迭代器

两个方法基本类似,只不过一个是返回列表,一个是返回迭代器。我们知道列表是一次性生成在内存中,而迭代器是需要使用时一点一点生成出来的,内存使用更优。

3.替换

替换主要有sub函数subn函数,他们功能类似!

先来看看sub函数的用法:

re.sub(pattern, repl, string, count=0, flags=0) 函数参数讲解:repl替换掉string中被pattern匹配的字符, count表示最大替换次数,flags表示正则表达式的常量。

值得注意的是:sub函数中的入参:repl替换内容既可以是字符串,也可以是一个函数哦! 如果repl为函数时,只能有一个入参:Match匹配对象。

4.切割

1
2
3
4
import re
>>> re.split("\.","www.pornhub.com")
['www', 'pornhub', 'com']
# 可以用于切割字符串并且返回一个列表

表达式全集

字符 描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。例如,“n”匹配字符“n”。“\n”匹配一个换行符。串行“\\”匹配“\”而“\(”则匹配“(”。
^ 匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配“\n”或“\r”之前的位置。
* 匹配前面的子表达式零次或多次。例如,zo能匹配“z”以及“zoo”。等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。
? 匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“does”或“does”中的“do”。?等价于{0,1}。
{n} n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。
{n,} n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。
{n,m} mn均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。
? 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo”,“o+?”将匹配单个“o”,而“o+”将匹配所有“o”。
. 匹配除“\*n”之外的任何单个字符。要匹配包括“\n*”在内的任何字符,请使用像“`(.
(pattern) 匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“\(”或“\)”。
(?:pattern) 匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符“`(
(?=pattern) 正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“`Windows(?=95
(?!pattern) 正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如“`Windows(?!95
(?<=pattern) 反向肯定预查,与正向肯定预查类拟,只是方向相反。例如,“`(?<=95
(?<!pattern) 反向否定预查,与正向否定预查类拟,只是方向相反。例如“`(?<!95
x|y 匹配x或y。例如,“`z
[xyz] 字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”。
[^xyz] 负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“p”。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。
[^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”。
\B 匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。
\cx 匹配由x指明的控制字符。例如,\cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的“c”字符。
\d 匹配一个数字字符。等价于[0-9]。
\D 匹配一个非数字字符。等价于[^0-9]。
\f 匹配一个换页符。等价于\x0c和\cL。
\n 匹配一个换行符。等价于\x0a和\cJ。
\r 匹配一个回车符。等价于\x0d和\cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于[^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于\x09和\cI。
\v 匹配一个垂直制表符。等价于\x0b和\cK。
\w 匹配包括下划线的任何单词字符。等价于“[A-Za-z0-9_]”。
\W 匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。
\xn 匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,“\x41”匹配“A”。“\x041”则等价于“\x04&1”。正则表达式中可以使用ASCII编码。.
*num* 匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,“(.)\1”匹配两个连续的相同字符。
*n* 标识一个八进制转义值或一个向后引用。如果*n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n*为一个八进制转义值。
*nm* 标识一个八进制转义值或一个向后引用。如果*nm之前至少有nm个获得子表达式,则nm为向后引用。如果*nm之前至少有n个获取,则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若nm均为八进制数字(0-7),则*nm将匹配八进制转义值nm*。
*nml* 如果n为八进制数字(0-3),且m和l均为八进制数字(0-7),则匹配八进制转义值nml。
\un 匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,\u00A9匹配版权符号(©)。

常用正则表达式

用户名 /^[a-z0-9_-]{3,16}$/
密码 /^[a-z0-9_-]{6,18}$/
十六进制值 /^#?([a-f0-9]{6}|[a-f0-9]{3})$/
电子邮箱 /^([a-z0-9_.-]+)@([\da-z.-]+).([a-z.]{2,6})$/ /^[a-z\d]+(.[a-z\d]+)*@(\da-z?)+(.{1,2}[a-z]+)+$/
URL /^(https?://)?([\da-z.-]+).([a-z.]{2,6})([/\w .-]*)*/?$/
IP 地址 /((2[0-4]\d|25[0-5]|[01]?\d\d?).){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)/ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
HTML 标签 /^<([a-z]+)([^<]+)(?:>(.)</\1>|\s+/>)$/
删除代码\注释 (?<!http:|\S)//.*$
Unicode编码中的汉字范围 /^[\u2E80-\u9FFF]+$/

py模块、包

导入模块

  • 导入整个模块

    1
    2
    3
    import moudle_name
    #调用
    moudle_name.function_name()
  • 导入特定的函数

    1
    2
    3
    from module_name import function_name
    #可以用逗号分隔函数名
    from module_name import function_0,function_1
  • 用as给函数指定别名

    1
    from module_name import function_name as fn
  • 用as给模块指定别名

    1
    import module_name as mn
  • 导入模块中所有函数

    使用*运算可以导入模块中的所有函数from module_name import *

  • 踩过坑的一点:例如我有一个文件正在编辑a.py,想从b的库里面导入名字为a的模块,那么在a.py的文件中不可以执行from b import a,原理也很简单,会引发歧义,报错的内容大概是"b" ImportError: cannot import name a

    (Python运行时,当前目录下不能有与引入的库文件相同的python文件,否则会在引入库文件时,找到相同的该文件)

导入包

假设当前编辑位于/desktop/test.py的程序,需要在/desktop下建立一个文件夹sources,/desktop/sources下包含你所有需要的模块,并且建立一个新的文件init.py,这样就完成了一个包的建立 ,

usage: from sources import module_name1,module_name2...

py标准库

py3标准库

[标准库使用指南](https://docs.python.org/3.3/tutorial/stdlib. html)

datetime

1
2
3
4
5
6
7
8
9
10

import datetime as dt
# 将yyyy-mm-dd h:m:s格式的时间转换成py的datetime类型
date1 = dt.datetime.strptime(dep_date, "%Y-%m-%d %H:%M:%S")
date2 = dt.datetime.strptime(arr_date, "%Y-%m-%d %H:%M:%S")
(date1-date2).seconds
(date1-date2).days

date1.strftime("%d/%m/%Y")
#重新转成字符串输出

类与对象

  • 首先便是OOP(Object Oriented Programming)的概念了,没啥好说的。简单提一句,如果对象就是名词,那么方法就是动词。类代表着独立事物的高度抽象,而对象是对类的实例化具象实现形式。一笔带过,以往的概念直接套用即可

从建立一个类开始

约定俗成的一个规定,类名开头第一个字母大写,用于区分,增加可读性

1
2
3
4
5
class Dog()
pass

#实例化
a_dog = Dog()
  • 方法__init__()

此方法在每次调用类的实例时自动运行(直接“望文生义”吧,initialization),name和age称之为dog类的属性,此方法类似c类语言的构造函数,self类似this指针(指向当前正在创建的对象本身),self在py的__init__()中不可缺省

1
2
3
4
5
6
7
8
9
10
11
class Dog():
def __init__(self,name,age):
self.name = name
self.age = age

def sit (self): #坐下!
print(self.name.title()+" is now sitting.")

def roll_over(self): #让狗狗打滚(爪巴?)
print(self.name.title()+" rolled over!")

实例化

1
my_dog = Dog('harry'  ,6)

调用方法

1
2
my_dog.sit()
my_dog.roll_over()

py中类的属性没有用属性修饰值private和public区分,但是私有(private)对象/函数可以用__name的形式命名,受保护(protected)的对象/函数可以用_name的形式命名,后面还会提及

修改特性值(3种方式)

  1. 直接修改对象的值对象名.特性名 = 值object.attribute = value
  2. 通过方法修改特性(attribute)(简而言之,在类中建立一个函数(称之为方法),在方法内用self.属性名来改变特性值)
  3. 在方法中递增特性值

在子类中添加新方法

举个例子吧,以汽车中特斯拉和奥迪为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Car():
def print_info(self):
print("it a car")

class Electric(Car):
def print_electric_info(self):
print("and it a electric car")

audi = Car()
tesla = Electric()

audi.print_info()
tesla.print_info()
tesla.print_electric_info()
'''
outs:
it a car
it a car
and it a electric car
'''

继承,override

​ 1.子类继承父类原有方法定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Father_class():
def __init__(self, family_name, gender):
self.family_name = family_name
self.gender = gender
def print_info(self):
print(self.family_name+' '+self.gender)

class Son_class(Father_class): #继承就是将父类 类名 写入子类括号中
def __init__(self, family_name,gender,age):
super().__init__(family_name,gender) #super()用于获取父类方法的定义(因为儿子和父亲姓氏和性别相同)
self.age = age
def print_info(self): #相同的函数名出现在子类中,就会重写(overrides)父类方法
print("family name is:"+self.family_name +",son age is:"+self.age)

father = Father_class('smith','male')
son = Son_class('smith','male','20')

son.print_info()
father.print_info()
#outs: family name is:smith,son age is:20
# smith male

  • super()是一个特殊的函数,帮助父类和子类联系起来
  • 重写父类方法,当子类和父类的方法名重复时,子类方法会覆盖父类方法
  1. 可以把类当作属性值赋值给另一个类中的属性,类似嵌套

使用属性对特性访问

刚刚再对修改属性进行讨论的时候提到过py并没有所谓的private和public属性,这里详细的来讨论一下吧

首先还是从c类语言开始,是否还记得当时写c类语言时私有类型是如何赋值和调用的?没错,我们需要在类中重新定义新的方法,比如使用display()/show()/getter()来调用私有类型输出,使用input()/get()/setter()来从外界获取数据赋值给私有类型。

在py中你也可以这么干,但是更具有py风格的是使用属性(property),尽量记住英文吧,毕竟attribute被翻译成特性,中文的属性和特性我觉得实在差别不大

讲了那么多废话,直接看一个例子吧

  • 使用setter/getter对隐藏的特性进行访问(trump同志借你的名字用下哈)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Duck():
def __init__(self, input_name):
self.hidden_name = input_name #这里的hidden_name相当于私有类型
def get_name(self):
print('inside the getter')
return self.hidden_name
def set_name(self, input_name):
print('inside the setter')
self.hidden_name = input_name
name = property(get_name, set_name)#这两个方法定义为了 name 属性
#property() 的第一个参数是 getter 方法,第二个参 数是 setter 方法

a_duck = Duck('duck')
print(a_duck.get_name()) #这里是显式调用等同于,隐式调用 print(a_duck.name)
# outs: inside the getter
# duck
a_duck.set_name('trump') #这里是显式调用等同于,a_duck.name = 'trump'
# outs: inside the getter
print(a_duck.get_name())
# outs: trump
  • 使用修饰符(decorator)

上面那个例子看着有点麻烦,来个简单的写法

该例子中定义两个不同的方法,它 们都叫 **name()**,但包含不同的修饰符:

  • @property,用于指示 getter 方法;

  • @name.setter,用于指示 setter 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Duck():
@property #简单的理解property就是输出“私有类”
def name(self):
print('inside the getter')
return self.hidden_name

@name.setter #方法名.setter可以理解为输入
def name(self, input_name):
print('inside the setter')
self.hidden_name = input_name

def __init__(self, input_name):
self.hidden_name = input_name


a_duck = Duck('duck')
print(a_duck.name)
a_duck.name = 'trump'
print(a_duck.name)
#你仍然可以像之前访问特性一样访问 name,但这里没有了显式的 get_name() 和 set_name() 方法
#outs:
'''
inside the getter
duck
inside the setter
inside the getter
trump
'''

在之前的例子中我们都用name属性指向类中存储的某一个特性(例子中式hidden_name),除此之外我们可以让属性指向一个计算结果值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#一个输入半径转换直径的Circle类
class Circle():
def __init__(self,radius):
self.radius = radius
@property
def diameter(self):
return 2*self.radius

c = Circle(5)
print(c.radius)
print(c.diameter)
c.radius = 7 #当半径改变时,直径会自动改变
print(c.diameter)
#outs:
# 5
# 10
# 14

因为我们没有对直径设置setter属性(@diameter.setter),那么无法从外部对直径进行修改,达到了保护数据的目的,只读属性

1
2
3
c.diameter = 9
#如果我给直径直接赋值,编译器就会报错
# AttributeError: can't set attribute

使用名称重整来保护私有属性

这个标题可能会引发一些误会,再次声明py并没有真正意义上的私有类型。

刚刚我们在鸭子类中加了一个隐藏的属性hidden_name,但是这种方法有一个弊端,就是当我知道这个类中有这个属性的时候我可以这样调用a_duck.hidden_name,为了禁止这种行为引进名称重整,将你需要命名的私有属性变量命名成__privatename,加两条下划线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#我只是把上面那个代码拔下来,将hidden_name全部替换为__name
class Duck():
@property
def name(self):
print('inside the getter')
return self.__name

@name.setter
def name(self, input_name):
print('inside the setter')
self.__name = input_name

def __init__(self, input_name):
self.__name = input_name

a_duck = Duck('trump')
print(a_duck.__name) #这样就会报错
#AttributeError: 'Duck' object has no attribute '__name'
#其实只是py将代码重整成了 a_duck._Duck__name 这种形式而已

好吧说了半天,这种保护特性的方式并不完美,但它确实能在一定程度上避免我们无意或有意地对特性进行直接访问

类的方法

​ 在类的定义中,以 self 作为第一个参数的方法都是实例方法(instance method)。它们在 创建自定义类时最常用。实例方法的首个参数是 self,当它被调用时,Py会把调用该 方法的对象作为 self 参数传入。
​ 与之相对,类方法(class method)会作用于整个类,对类作出的任何改变会对它的所有实 例对象产生影响。在类定义内部,用前缀修饰符 @classmethod 指定的方法都是类方法。与 实例方法类似,类方法的第一个参数是类本身。在 Py中,这个参数常被写作 cls,因为全称 class 是保留字,在这里我们无法使用。下面的例子中,我们为类 A 定义一个类方 法来记录一共有多少个类 A 的对象被创建:

  • @classmethod
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A():
count = 0

def __init__(self):
A.count += 1

def exclaim(self):
print("I'm an A!")

@classmethod
def kids(cls):
print("A has", cls.count, "little objects.")


easy_a = A()
breezy_a = A()
wheezy_a = A()
A.kids()
'''
outs:
A has 3 little objects.
'''
  • 静态方法(static method),用 @staticmethod 修饰, 它既不需要 self 参数也不需要 class 参数
1
2
3
4
5
6
7
class Greet():
@staticmethod
def greeting():
print('hello')

Greet.greeting()
#outs: hello

ok,静态方法不需要调用任何参数,甚至连对象都不需要,类名.方法名 可以直接调用,他的存在只是为了方便,不然这段代码会落单。

多态

还记得多态是什么吗?一起来回忆下吧。在oop中多态指的是一个实体具有多种形式,简单的按照字面意思理解,一个类具有多种形态,形态就体现在方法上,看段代码感受一下吧,虽然有点长,但其实很简单和清晰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Quote():
def __init__(self, person, words):
self.person = person
self.words = words
def who(self):
return self.person
def says(self):
return self.words + '.'

class QuestionQuote(Quote):

def says(self):
return self.words + '?'

class ExclamationQuote(Quote):

def says(self):
return self.words + '!'

hunter = Quote('Elmer Fudd', "I'm hunting wabbits")
print(hunter.who(), 'says:', hunter.says())
hunted1 = QuestionQuote('Bugs Bunny', "What's up, doc")
print(hunted1.who(), 'says:', hunted1.says())
hunted2 = ExclamationQuote('Daffy Duck', "It's rabbit season")
print(hunted2.who(), 'says:', hunted2.says())

'''outs:
Elmer Fudd says: I'm hunting wabbits.
Bugs Bunny says: What's up, doc?
Daffy Duck says: It's rabbit season!

'''

py的多态不同于其他的oop语言,它无论对象的种类是什么,只要包含 who() 和 says(),你便可以调用它。我们再来定义一个 BabblingBrook 类,它与我们之前的猎人猎物(Quote 类的后代)什么的没有任何关系

1
2
3
4
5
6
7
8
9
10
11
12
#这段代码接上一段,再次使用多态,在无关类中实现
class BabblingBrook():
def who(self):
return 'Brook'
def says(self):
return 'Babble'

brook = BabblingBrook()


print(brook.who()+" says "+brook.says())
#outs: Brook says Babble

魔术方法special method

Python 的特殊方法(special method),有时也被称作魔术方法(magic method),这是一个很有有趣的部分,先来看一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Word():
def __init__(self, text):
self.text = text

def __eq__(self, word2): # 魔术方法
return self.text.lower() == word2.text.lower() # lower是将字母变成小写


first = Word('ha')
second = Word('HA')
third = Word('eh')
if first == second:
print('True')
# outs: True
if not first == third:
print('False')
# outs: False

相信我不说也看得懂这段代码在干啥,没错正是比较单词是否相同(忽略大小写),唯一可能有所疑惑的便是__eq__,这便是魔术方法,常用如下,官方文档 | 参考

![magic method](C:\Users\83487\Pictures\programmer path\magic method.jpg)
![magic method2](C:\Users\83487\Pictures\programmer path\magic method2.jpg)

  • 这里我忽略一个组合(composition 或聚合aggregation)未提及,相对于类的父子继承的方式,是一种类似 类与类兄弟 关系的一种,不常用,如果需要再查资料

从外部类导入类模块

例如,外部文件有car.py其中包含两个class,Car和Electrical

在my_car文件中应该导入这两个类from car import Car ,Electrical

或者导入整个import Car

再用moudle_name.class_name的形式调用类

文件

文件

未提及不使用with关键字的用法,使用with关键字可以让py自动判断是否关闭

  • 读取文件
1
2
3
4
 #with关键字可让py自动判断何时关闭
with open ('file_name') as file_object:
contents = file_object.read()
print(contents)
  • 获取文件当前的脚本目录和工作目录
1
2
3
import os
os.path.dirname(os.path.abspath(__file__)) #get directory name
os.getcwd() #get current working directory
  • 写入文件
1
2
with open('file_name','w') as file_object:
file_object.write("i love programming")

附加到文件末尾用append,'a'替换'w'即可

  • 一个例子

获取当前文件的路径,并且添加一个pro.txt写入i love programming

1
2
3
4
5
6
import os
pwd = os.path.dirname(os.path.abspath(__file__))
os.chdir(pwd)
file_path = 'pro.txt'
with open(file_path,'w') as file_object:
contents = file_object.write("i love programming")

从这里开始基础部分算是结束了,后面的还都是笔记的形式没整理成教程,就看看前面的吧,

下文应用方面的比较多

w+ 可读写,文件不存在时创建文件

r+,可读写,文件不存在时报错

truncate(size)函数来删除 txt 文件内容,size是表示从第几个字节开始清除,如果是0时代表是删除全部内容(首先需要seek(0)不然可能会造成乱码)

b是以二进制的读入


用json存储数据

dumps将python内置的对象转化未json

loads将json数据读入作为python内置的对象

  • 对api返回的json对象r,r.json()将原json转化为一个py字典

  • 使用json.dump() , json.load()

    • json.dump()

json.dump()接受两个实参,一个是要存储的数据,一个是存储数据的对象,

而json.dumps()方法可接受只有一个实参,即存储的数据

1
indent = 4,sort_keys=True

如上两个参数,indent=4使代码缩进4bytes , sort_key升序排序(字母),同时试用与dump和dumps

1
2
3
4
5
6
7
import json
#directory save file & output
numbers = [1,2,3,4,6,5]

file_name = 'numbers.json'
with open('file_name','w') as f_obj:
json.dump(numbers,f_obj)

​ b. json.load()

1
2
3
4
5
6
7
import json
#string to directory
file_name = 'numbers.json'
with open('file_name') as f_obj:
numbers = json.load(f_obj)

print(numbers)

模块

requests模块

  1. request.get(url)

    假设r=requests.get(url)返回的对象r有如下属性

r.status_code http请求返回状态,200表示正常

r.text http相应为字符串形式,返回页面的内容

r.encoding 从http header 中猜测的相应内容编码方式

r.apparent_encoding 从内容中分析出的响应内容编码方式(备选编码方式)

r.content http响应内容的二进制形式

处理excel表格

使用xlrd

首先from xlrd import open_workbook导入py对excel导入支持

读取excel首先需要打开,可以使用example = openwork(file_name)

获取所有表格的名字(一个workbook有多个sheets) example.sheet_names()

通过索引和名字获取表格,比如一个excel中第一张sheet叫做“价格”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sheet1 = example.sheet_by_index(0) #通过索引获取表格,类似数组下标
sheet2 = example.sheet_by_name('价格')#通过名称获取表格
sheet1.ncols#列数
sheet1.nrows#行数
rows_value = sheet1.row_values(2)
#['微软', 'python工程师2', '2@2.com']
cols_value = sheet1.col_values(2)
#['对方邮箱', '1@1.com', '2@2.com', '3@3.com']
for i in range(sheet1.nrows):
print (sheet1.row_values(i))
''' 输出每一行,列表
['阿里巴巴', 'python工程师', '1@1.com']
['微软', 'python工程师2', '2@2.com']
['谷歌', 'python工程师3', '3@3.com']
'''
#使用单元格定位
cell_A1 = sheet1.cell(0,0).value
cell_A2 = sheet1.cell(0,1).value
使用pandas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
df = pd.read_excel('file_destiantion')
#df=pd.read_excel('lemon.xlsx',sheet_name='Sheet1')#可以通过sheet_name来指定读取的sheet
# df=pd.read_excel('lemon.xlsx',sheet_name=0)#可以通过表单索引来指定读取的表单
data = df.head()#前五行数据
#data=df.values#获取所有的数据,返回一个列表迭代器
print(format(data))
'''
a b c
1
2
3
1,2,3被称为是DataFrame的index属性
a,b,c被称为是columns属性
'''
nrows = df.index.size # 行数
ncols = df.columns.size # 列数
df.iloc[][] #按照单元格取
df.iloc[:,j].name #按照切片取,这里是第j列的名称 usage[row:column]

numpy

import numpy as np

以下笔记均在导入numpy的情况下使用

numpy数组

  • 从py列表创建数组

    np.array([1,2,3,4,5,6])

    numpy中的array方法还有dtype意为datatype指定数组的数据类型

![numpy data type](C:\Users\83487\Pictures\programmer path\numpy data type.jpg)

  • 利用numpy内建方法创建大规模数组
  1. 创建一个长度为10的数组,且赋予初值0

    np.zeros(10,dtype = int)

  2. 创建一个3*5的浮点数数组,初值为1

    np.ones( (3,5),dtype = float)

  3. 创建一个3*5的浮点数组,初值为3.14

    np.full((3,5),3.14)

  4. 创建一个3*5的浮点数组,从0-20,步长为2

    np.arange(0,20,2)

    out:[0,2,4,6,…20]

  5. 创建一个五个元素的数组,数值平均分配0-1中间

    np.linspace(0,1,5)

  6. 创建一个3*3取值在0-1之间的矩阵,由随机数组成的数组

    np.random.random((3,3))

  7. 创建一个正态分布,方差为1,3*3的随机数组

    np.random.normal(0,1,(3,3))

  8. 创建一个3*3,[0,10)之间的随机数组

    np.random.randint(0,10,(3,3))

  9. 创建一个3*3的单位矩阵

    np.eye(3)

  10. 创建一个3个整形数组构成的数组,未初始化,直接读取内存的值

    np.empty(3)


属性

每个数组均有nidm(数组的维度),shape(每个数组的大小),size(数组的总大小),dtype是数组的数据类型,itemsize每个数组元素字节大小,nbytes数组总字节大小

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
#省略下区间的写法(0,10)=> 10
x1 = np.random.randint(10,size = 6)#一维
x2 = np.random.randint(10,size = (3,4))#二维
x3 = np.random.randint(10,size = (3,4,5))#三维
x3.ndim #数组的维度 3
x3.shape #每个数组的大小 (3,4,5)
x3.size #数组的总大小 60
x3.dtype
x3.itemsize #每个数组元素字节大小 8bytes
x3.nbytes #数组总字节大小 480bytes

索引

  1. 若是数组名,则返回整个数组

  2. 第一个元素为0,可以使用负值,即为倒数第一个元素

  3. 在多维数组中可以用逗号分隔索引元素[行,列]

tips:若将浮点数的值赋值给整形的numpy对象,会自动截取整数部分,自动进行,无错误和警告

切分

x是一个数组则,数据的切分为x[start,stop,step]

值得注意的是,在一维数组中,x[4,7]这个切片表示的是原数组第5个元素(包括)到第七个元素(包括)

同样的负值在step中依旧可以使用,例如x[::-1]表示的是逆序输出原数组所有元素

  • 多维数组类似操作,不同维度之间用逗号分隔

  • 获取行列。例如:获取二维数组x2第一行,x2[0,:],或省略为x2[0]

    ​ 同理二维数组的x2第一列,x2[:,0]

  • 用上述的切分操作创建的是原数组的视图,即数据与原数组相关联,若改动某个元素的值,原数组中的该元素的值也被改变

  • 若想切分出来的新数组与原数组无关,可以用.copy()函数进行转换,即创建一个原数组子副本usage:x2.[:,0].copy()

变形与分裂

数组的变形

数组的变形可以用reshape() 函数和newaxis

![reshape](C:\Users\83487\Pictures\programmer path\reshape.jpg)

数组的拼接和分裂
拼接
1
2
3
4
x = np.array([1,2,3])
y = np.array([3,2,1])
np.concatenate([x,y])
#out: array([1,2,3,3,2,1])

concatenate也可以对二维数组和两个以上的数组对象进行拼接

1
2
3
4
grid = np.array([1,2,3],
[4,5,6])
np.concatenate([grid,grid])#默认沿着第一个轴进行拼接,y轴
#缺省axis = 1

输出结果np.array([1,2,3],

​ [4,5,6],

​ [1,2,3],

​ [4,5,6])

1
2
3
grid = np.array([1,2,3],
[4,5,6])
np.concatenate([grid,grid],axis = 0)#axis = 0,x轴拼接

输出结果np.array([1,2,3], [1,2,3],

​ [4,5,6], [4,5,6])

  • 或者使用np.vstack,np.hstack
1
2
3
4
grid = np.array([1,2,3],
[4,5,6])
np.vstack([grid,grid])#效果等于concatenate按y轴拼接
np.hstack([grid,grid])#效果等于concatenate按x轴拼接
分裂
  • np.split
1
2
3
4
x = [1,2,3,99,99,3,2,1]
x1,x2,x3 = np.split(x,[3,5])
print(x1,x2,x3)
#out : [1,2,3],[99,99],[3,2,1]

分裂点是3,5,分裂点之前的(不含分裂点)为一组

  • np.hsplit、np.vsplit

![vsplit hsplit](C:\Users\83487\Pictures\programmer path\vsplit hsplit.jpg)

numpy函数

  • 数组值求和

np.sum(),numpy的函数比py内置的sum函数速度更快,括号中值是numpy的对象

  • 最大最小值

numpy中有最大最小和求和的函数,用np_oject_name.min(),np_oject_name.max(), np_oject_name.sum()来得到

还有一个参数便是axis,axis 关键字指定的是数组将会被折叠的维 度,而不是将要返回的维度。因此指定 axis=0 意味着第一个轴将要被折叠——对于二维数 组,这意味着每一列的值都将被聚合

例如现在一个叫做M的numpy对象,M.min(axis=0)则意味着数据被摊开为只有x轴,并找到其中的min,

numpy支持的算术运算符,+,-,,/,//(地板除),*(指数),%(取余),

绝对值np.abs()

三角函数np.sin(),np.cos(),np.tan()

反三角函数np.arcsin(),np.arccos(),np.arctan()

指数和对数

np.exp(x) - e^x

np.exp2(x)-2^x

np.power(3,x)-3^x

np.log(x)- ln(x)

np.log2(x)-log2(x)

np.log10(x)-log10(x)

特殊版本

print("exp(x) - 1 =", np.expm1(x))

print("log(1 + x) =", np.log1p(x))

  • 更高级的版本科学计算的函数可以在scipy.special中找到

高级的通用函数特性

  1. 指定输出
1
2
3
4
5
6
7
8
9
10
11
x = np.arange(5)
y = np.empty(5)
np.multiply(x,10,out = y)
print(y)
#outs:[0. 10. 20. 30. 40.]

#another example
y = np.zeros(10)
np.power(2,x,out=y[::2]) #隔一个数字做乘方
print(y)
#[ 1. 0. 2. 0. 4. 0. 8. 0. 16. 0.]
  1. 聚合

对于np.add调用reduce方法会返回所有的元素的和

对于np.multiply函数调用reduce会返回数组中所有元素的乘积

如果要存储每次计算中间结果,可以用accumulate,同样可以对add和multiply调用,但是返回的是一个np数组对象,在原来的基础上最后加上一个元素和或积

  1. 外积

就像一个乘法表,

1
2
3
4
5
6
7
8
9
10
x = np.arange(1,6)
np.multiply.outer(x,x)
'''
outs:
[1,2,3,4,5]
[2,4,6,8,10]
[3,6,9,12,15]
[4,8,12,16,20]
[5,10,15,20,25]
'''

matplotlib

matplotlib 是一个绘图库,创建的图形可达到出版的质量要求。它可以创建常用的统计 图,包括条形图、箱线图、折线图、散点图和直方图。它还有一些扩展工具箱,比如 basemap 和 cartopy,用于制作地图,以及 mplot3d,用于进行 3D 绘图。 matplotlib 提供了对图形各个部分进行定制的功能。例如,它可以设置图形的形状和大 小、x 轴与 y 轴的范围和标度、x 轴与 y 轴的刻度线和标签、图例以及图形的标题。你可以 参考一下 matplotlib 初学者指南和 API,以获得 更多的关于定制图形的信息.

从一个

250 2172
500 4230
750 6344
1000 8404
1250 10448
1500 12541
1750 14587
2000 16727
2250 18835
2500 20840
2750 22925
3000 25001
3250 27093
3500 29182
3750 31227这样的文件中提取数据并且绘制散点图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import matplotlib.pyplot as plt
import matplotlib
import csv

# 设置中文字体
matplotlib.rcParams['axes.unicode_minus'] = False
matplotlib.rcParams['font.sans-serif'] = ['Microsoft YaHei']
matplotlib.rcParams['font.family']='sans-serif'

x = []
y = []

with open('D:\pycharm\gragh\/v3c.txt','r') as csvfile:
plots = csv.reader(csvfile, delimiter=' ')
for row in plots:
x.append(int(row[0]))
y.append(int(row[1]))

plt.scatter(x,y, label='散点', color='g', s=25, marker=".")
plt.ylim(0,1e8)
plt.xlabel('问题规模n')
plt.ylabel('执行次数(s)')
plt.title('v3散点图')
plt.legend()
plt.show()

生成exe发布

  • pyinstaller
1
pyinstaller -F helloworld.py

其中,-F 表示打包成单独的 .exe 文件,这时生成的 .exe 文件会比较大,而且运行速度回较慢。仅仅一个 helloworld 程序,生成的文件就 5MB 大。

另外,使用 -i 还可以指定可执行文件的图标; -w 表示去掉控制台窗口,给程序换图标的方法
输入命令中添加一个-i tubiao.ico(图标的相对路径)

python使用虚拟环境

python3 -m venv envir_name如果它不存在,这将创建 tutorial-env 目录,并在其中创建包含Python解释器,标准库和各种支持文件的副本的目录。

source 虚拟路径/bin/activate 激活虚拟环境

deactivate退出虚拟环境

conda

conda相当于virtualenv + pip环境,是一个包管理工具+虚拟环境的工具.不只支持python一个语言

  1. 首先在所在系统中安装Anaconda。可以打开命令行输入conda -V检验是否安装以及当前conda的版本。

  2. conda常用的命令

    1. conda list 查看安装了哪些包。
    2. conda env listconda info -e 查看当前存在哪些虚拟环境
    3. conda update conda 检查更新当前conda
  3. conda info --env查看有哪些虚拟环境

  4. 创建python虚拟环境。

    使用 conda create -n your_env_name python=X.X(2.7、3.6等)命令创建python版本为X.X、名字为your_env_name的虚拟环境。your_env_name文件可以在Anaconda安装目录envs文件下找到。

  5. 使用激活(或切换不同python版本)的虚拟环境。

conda activate env_name

退出环境

conda deactivate

打开命令行输入python –version可以检查当前python的版本。

使用如下命令即可 激活你的虚拟环境(即将python的版本改变)。

Linux: source activate your_env_name(虚拟环境名称)

Windows: activate your_env_name(虚拟环境名称)

这是再使用python –version可以检查当前python版本是否为想要的。

  1. 对虚拟环境中安装额外的

使用命令conda install -n your_env_name [package]即可安装package到your_env_name

  1. 关闭虚拟环境(即从当前环境退出返回使用PATH环境中的默认python版本)。

使用如下命令即可。

Linux: source deactivate

Windows: deactivate

  1. 删除虚拟环境。

使用命令conda remove -n your_env_name(虚拟环境名称) --all, 即可删除。

  1. 删除环境中的某个

使用命令conda remove --name your_env_name package_name 即可。

conda添加源

1
2
3
4
5
6
7
8
9
10
11
12
13
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
# 以上两条是Anaconda官方库的镜像

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
# 以上是Anaconda第三方库 Conda Forge的镜像

# for linux
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
# for legacy win-64
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/peterjc123/
以上两条是Pytorch的Anaconda第三方镜像
conda config --set show_channel_urls yes #刷新源

conda info可以查看是否添加成功

爬虫

bs4

1
2
3
from bs4 import BeautifulSoup 

soup = BeautifulSoup(web_response.content,"html.parser")

https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/

requests

1
2
3
4
5
6
7
import requests

web = requests.get('https://www.baidu.com') #向百度发起一次get请求,返回请求结果的实体类
print(web.status_code) #请求返回的状态码,200是OK,404是页面不存在,500是错误,更多自己百度搜索
print(type(web.content)) #页面内容的数据类型是bytes,因此需要解码
print(type(web.content.decode()))
print(web.content.decode()) #解码之后,得到的页面内容是结构化的字符串

selenium

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from selenium import webdriver
# 可以进行chrome相关包的自动下载和管理
from webdriver_manager.chrome import ChromeDriverManager



def element_screenshot(element):
'''
截取部分截图,根据dom元素的id获取
'''
pwd = os.path.dirname(os.path.abspath(__file__))
os.chdir(pwd)
# 截取全屏图片
# driver.set_window_size(1920,1080)
driver.save_screenshot("../images/full.png")
# 获取element的顶点坐标
x_Piont = element.location['x']
y_Piont = element.location['y']

# print(x_Piont + " " + y_Piont)
# 获取element的宽、高
element_width = x_Piont + element.size['width']
element_height = y_Piont + element.size['height']

picture = Image.open("../images/full.png")
# 此处的125是缩放比,windows桌面右键-显示设置中的缩放比数值,只有除以(100/125)坐标才可以显示正常
picture = picture.crop((x_Piont/(100/125.0), y_Piont/(100/125.0), element_width/(100/125.0), element_height/(100/125.0)))
picture.save("../images/Capture.png")


# 一个新的连接,如果找不到对应版本的驱动会自动安装 ,注意Chrome是大写字母开头
driver = webdriver.Chrome(executable_path=ChromeDriverManager().install())
driver.get("http://192.168.100.190//default2.aspx")
driver.maximize_window()
# 要截取的验证码元素
element = driver.find_element_by_id("icode")
# 调用element_screenshot()方法
element_screenshot(element)
  • xpath定位法

    和本文档同一目录下的pdf

转中文问题

1
2
3
# py3
from __future__ import unicode_literals
json.dumps(需要转成json对象,ensure_ascii=False)

在flask中使用log

1
2
3
4
5
6
7
handler = logging.FileHandler('flask.log', encoding='UTF-8')

handler.setLevel(logging.DEBUG) # 设置日志记录最低级别为DEBUG,低于DEBUG级别的日志记录会被忽略,不设置setLevel()则默认为NOTSET级别。
logging_format = logging.Formatter(
'%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s')
handler.setFormatter(logging_format)
flask_app.logger.addHandler(handler)

flask_app.logger.duebg()即可记录flask

flask_app为flask实例

生成requirement.txt

pip freezz > requiremets.txt

pipreqs ./

使用vscode导入相对路径

pycharm会自动添加项目根目录到工作路径,vscode 需要修改下配置文件,不然会no moudle error

在lau nch.json中添加

1
"env": {"PYTHONPATH":"${workspaceRoot}"}