python基础

Python是个好脚本啊! 处理&分析数据好使.

简单的复习下Python基础, 也为了方便自己日后复习方便!

注意事项

1
2
3
4
0. 统一缩进
1. 大小写是敏感的
2. 单行注释用#, 多好注释用'''或者 """
3. 字符串或语句多行 \

小工具

1
2
3
4
命令行中查看一个类型所有的信息(变量, 方法等等)
dir(dict)
help(dict)
help(dict.keys)

数据类型

常用的数据类型:
Number String List Tuple Sets Dictionary

1
2
3
python中的变量在使用前都要声明, 变量赋值以后才会进行赋值.
1.标准数据类型
Number--int, float, bool(True/False), complex


1
2
3
4
5
6
7
8
2.  String --a = "hello"
title()首字母大写 a.title()
upper()全部大写 a.upper()
lower()全部小写 a.lower()
dir(a)查看所有的方法*******通用的
+ 进行字符串的拼接
str(name) 转化为字符串
len(name)

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
3.  List (一种有序的集合, 可随时添加或删除其中的某个元素)的十种操作方法
list = [1, 2, 3, "hello"]
list1 = [12, 34]
1. append()---list.append(123)-->[1, 2, 3, "hello"] list.append(list1)-->[1, 2, 3, "hello",[12, 34]]
2. expend() ---list.expend(list1)-->[1, 2, 3, "hello", 12, 34]
3. insert() ---list.insert(0, 0) -->[0, 1, 2, 3, "hello"]
4. pop()----list.pop()-->[1, 2, 3] list.pop(2)-->[1, 2, "hello"] 默认删除最后一个, 也可以指定下标
5. remove()---list.remove("hello")-->[1, 2, 3] 如果有多个元素一样, 默认删除第一个.
6. count() ---统计某个元素的数量 list.count("hello") -->1
7. len(list) --> 4 统计列表中的个数
8. index() --list.index("hello")-->3
9. reverse() --反转
10.sort() --原排序 list.sort()
11.sorted(list) --返回一个新的排序好的列表, 元列表不变. list1 = sorted(list)

str = "hello"
print(str[0:-1]) 输出第一个到倒数第二个字符
print(str[2:5]) 输出第三个到第五个字符
print(str+"world")

List使用最多[]
里面的元素可以不相同,可以嵌套, 和字符串一样可以被索引和截取。
与字符串不同的是 List里面的元素是可以被修改的。
List还有很多内置的方法。

列表的切片操作: (字符串也是可以使用的.)
list = ['michael', 'sarah', 'tracy', 'bob', 'jack']
1.取前三个元素
第一种方法:
list[0:3]
第二种方式:
for i in range(n):
r.append(list[i])
2. 取最后一个元素 list[-1] --> 'jack'
3. 取倒数最后两个元素 list[-2:] --> ['bob','jack']
4. range(100) [1:99]的列表
5. 取前十个元素 list[:10] 后十个-->list[-10:]
l = range(100)
6. 取前十个, 隔两个取2是步长 l[:10:2] --> [0, 2, 4, 6, 8]
7. 每隔5个取一个 l[::5] -->[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]

字符串切片:也就是截取.
name = 'hello'
name[:4:2] -->'hl'

列表推导式
names = ['bob', 'tom', 'alice', 'jerry', 'rose', 'jack']
1. 取出名字字母个数大于三的名字
for name in names :
if len(name) > 3 :
print name
输出结果:
alice
jerry
rose
jack

使用推导式, 取什么就把什么放前面.
[name.upper() for name in names if len(name)>3]
输出结果: ['ALICE', 'JERRY', 'ROSE', 'JACK']

[name for name in names if len(name)>3]
输出结果: ['alice', 'jerry', 'rose', 'jack']

[(x,y) for x in range(6) if x%2==0 for y in range(6) if y%2 == 1]
输出结果: [(0, 1), (0, 3), (0, 5), (2, 1), (2, 3), (2, 5), (4, 1), (4, 3), (4, 5)]

[row[2] for row in M]
输出结果: [3, 6, 9]

[row[M.index(row)] for row in M]
输出结果: [1, 5, 9]

1
2
3
4
4.  Tuple类似列表, 不同之处在于元祖中的元素不能被修改。元祖写在小括号里()
注意下 零个和一个元素的写法
tup1 = ()
tup2 = (21,)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
5.  Sets 无序集合
创建集合用{} 或者set()。 注意创建空集合不能用{},因为{}表示创建一个空字典, 应该用set()
a = set('abcdefg')
b = set('bcdefghij')
if('a' in a) :
print('a在集合中')
else :
print('b不在集合中')

集合是可以进行运算的
print(a - b) #a与b的差集
print(a | b) #a与b的并集
print(a & b) #a与b的交集
print(a ^ b)# a与b中同时不存在的元素

1
2
3
4
6.  Dictionary中的元素是通过key来取得。key要唯一。
dic1 = {1:"hello", 2:"world"}
dic2 = dict([("hello", 1), ("world", 2)])
字典中也有很多内置函数 keys() values()

1
2
3
4
7.  在python中,序列类型包括字符串(普通字符串和unicode字符串)、列表和元组,
所谓序列,即成员有序排列,可通过下标访问。
假设序列有n个元素,访问单个元素时,下标从0开始,到n-1结束,
如果是逆序访问,下标从-1开始,到-n结束,切片操作支持多个元素的访问。

再次温习

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
list的crud
1. append
2. insert
3. pop
4. classmates[0] = 'abcd'
5. __contains__()
6. index
7. len(classmates)

tuple:不可变
1. 只有一个元素时, t = (123,)


if 3 > 5:
print('a')
elif 5 > 3:
print('b')
else:
print('c')

range(5)
range(1, 5)
range(1, 5, 2)

for i in range(10):
print(i)


dict:
d = {'a':123, 'b':'hello'}
1. d.get('a', 'not found')
2. d.keys()
3. d.values()
4. d['aa'] = 'world'
5. d.pop('a')

set:
s = {1, 2,3 ,6}
s1 | s2 并集
s1 & s2 交集
s1 - s2 差集
1. s.add(5)
2. s.remove(2)

可变和不可变对象:
list就是可变对象, 而str就是不可变
简单来说, 就是看修改元素是否直接在源对象上修改, 还是又重新生成了新的一个对象. (即修改的对象的内容, 还是对象的指针).

set, dict, str, list, tuple都是Iterable
可以检验:
from collections import Iterable

isinstance([], Iterable)
isinstance((1, ), Iterable)
isinstance({}, Iterable)
isinstance('abc', Iterable)
isinstance({1, 3,4}, Iterable)

map和reduce
1. map()函数接受两个参数, 第一个参数是函数(这里接收一个参数), 第二个参数是一个Iterable,
实现的效果就是 将第二个参数Iterable这个对象中的每一个值取出来作为第一个参数,
然后第一个函数必须要接收这个参数, 并且要有返回值.
虽然这样也可以用for循环来实现, 但是用map只是一行代码的事, 就可以解决, 何乐而不为呢?

>>> def f(a):
... return a, 'hello'
...
>>> map(f, range(10))
[(0, 'hello'), (1, 'hello'), (2, 'hello'), (3, 'hello'), (4, 'hello'), (5, 'hello'), (6, 'hello'), (7, 'hello'), (8, 'hello'), (9, 'hello')]

2. reduce()函数接受两个参数. 第一个参数是函数(这里接收两个参数), 第二个参数也是一个Iterable对象.
第二个参数是Iterable对象, 第一次传递两个参数给函数的时候, 是拿Iterable对象中的前两个,
然后通过函数将计算的结果返回出来, 然后再讲结果和Iterable中的下一个值 一并作为参数传递给函数.

即为. reduce把结果继续和序列的下一个元素做累计.
def ha(a, b):
... print a+b
... return a+b
...
>>> reduce(ha, ['a', 'b','c'])
ab
abc
'abc'

函数定义

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
dict空间换取时间
range()
list-append, insert, pop, pop(2), list[2]可变
tuple 不可变
dict['username'] = 'daejong'


def functionName:
return 'daejong', 22

数可以返回多个值, tuple类

字符串拼接 必须同为字符串

输入不同类型的数据时, 也可以 print 'hello',18 会自带空格

函数的有默认参数值的参数, 要放在没有默认值的参数后面


def peson(username, age, **other):
print 'username',username, 'age', age, 'other',other

person('daejong', 22, city='shanghai')

打印: username daejong age 22 other {'city':'shanghai'}


def vals(username, *list) :
print 'username', username, "lsit", list

vals('daejong', *[1,2,3,’123'])
打印:username daejong hello ([1,2,3, '123']) 这里将list转成了tuple


认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!

要注意定义可变参数和关键字参数的语法:

*args是可变参数,args接收的是一个tuple;list转tuple不可变


以及调用函数时如何传入可变参数和关键字参数的语法:

可变参数既可以直接传入: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的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。

命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。

定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*,否则定义的将是位置参数。
**kw是关键字参数,kw接收的是一个dict。

切片
list1 = [1,2,3,4,5,6]
list2 = list1[:] 值拷贝
list1[1:3] 从下标为1拷贝3-1个元素.
list1[:-2] 从头开始到倒数第二个元素
list1[::2] 从头开始每隔2个
list1[:4:2] 取前四个元素, 每隔2个进行打印.

函数传入参数的的时候.
def hello(name, *list1, **dict1):
可变参数:
这里list1是在函数调用的时候,将传入的可变list转为不可变的tuple, 可以接受0或者多个list

键字参数, 也可以同时0个或者多个参数, key=value
1.会在函数内部进行组装成dict
2. 或者直接传入 **dict1


def hello(name, *list, **kw):
print name
print list
print kw

hello(daejong’, *[1,2,4], **{‘age’:18})

hello(daejong’, *[1,2,3], city=shanghai’)

文件操作

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
这种用法会帮助我们自动关闭文件..
with open('Users/daejong/Desktop/test.txt', 'r') as f:
list1 = f.readlines()

输出:
['#import "stdio.h"\n',
'\n', 'int main() {\n',
'\tprintf("yourname is %s",
"daejong");\n',
'\treturn 0;\n',
'}\n']

去掉结尾的空格
for i in range(len(list1)):
list1[i] = list[i].strip()

输出:
['#import "stdio.h"', '', 'int main() {', 'printf("yourname is %s", "daejong");', 'return 0;', '}']

操纵文件
import os #一定要导入该模块
os.name()

os.path.abspath() 输出当前的绝对路径/Users/daejong/Desktop
os.path.split('/Users/daejong/Desktop/test.txt')
输出('/Users/daejong/Desktop', 'test.txt')这是一个tuple

os.path.splitext('/Users/daejong/Desktop/test.text')
输出('/Users/daejong/Desktop/test', '.txt')

os.rename('text.txt', 'demo.txt')

过滤文件
1.列出当前目录下所有文件
os.listdir('filename') 列出filename目录下所有的文件-->>> listdir('.')当前目录
os.getcwd() 得到当前目录
os.chdir(name) 改变当前目录
os.path.isdir(name) 判断是不是一个目录
os.path..isfile(name) 判断是不是一个文件
os.path.getsize(name) 得到文件的大小

[x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1] == '.txt']
输出
['demo.txt', 'git\xe5\xad\xa6\xe4\xb9\xa0.txt', 'python.txt', 'python\xe4\xb8\xad\xe7\x9a\x84\xe6\xad\xa3\xe5\x88\x99.txt', '\xe7\xbd\x91\xe6\x98\x93\xe6\x96\xb0\xe9\x97\xbb\xe6\x95\xb0\xe6\x8d\xaeAPI.txt']
对输出进行解码
'git\xe5\xad\xa6\xe4\xb9\xa0.txt'
list3[1].decode('utf-8') ->>git学习.txt

读取一个文件夹下所有txt文件放到一个list
>>> for x in os.listdir('.'):
... if os.path.isfile(x) and os.path.splitext(x)[1] == '.txt':
... string = os.path.abspath(x)
... with open(string, 'r') as f:
... mylist.append(f.readlines())
...

查看具体的信息
>>> for i in range(len(mylist[1])):
... print mylist[1][i].decode('utf-8')



>>> for i in range(len(mylist)):
... for j in range(len(mylist[i])):
... print mylist[i][j].decode('utf-8')
...

最后再介绍点正则表达式

虽说用的不多, (分析数据时可以用其他模块), 还是介绍下吧, 知道个意思!

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
39
40
41
42
常见的正则:
1.字符
. 匹配任意的字符(除\n)
\ 转义字符
[...]任意字符 如[0-9](等同于[\d]),[a-z],[A-Z]

2.预定义字符 可写在[...]中
\d 匹配数字[0-9]
\D 匹配非数字[^\d]
\w 单词字符[a-zA-Z0-9] 区分于上面的.字符
\W 非单词字符

3.数量词
* 匹配前一个字符0次或者无限次
+ 匹配前一个字符1次或者无限次
? 匹配前一个字符0次或者1
{m} 匹配前一个字符m次
{m, n} 匹配前一个字符m-n次

4.边界匹配
多行模式下:
^匹配开头
$匹配结尾
单行模式下:
\A匹配字符串开头
\Z匹配字符串结尾

5.逻辑和分组(只会显示分组里面的内容) 比如: re.findall(r"(\d)abc\1", '1abc1 2abc2 3abc2') => ['1', '2']
| 代表左右表达式任意匹配一个,总是会先匹配左边的,一旦成功则跳过右边的匹配,如果|没有被包括在分组中,则它的范围是整个正则表达式.
(...)被括起来的表达式将作为分组, 从表达式的左边开始遇到一个分组的左括号'(', 编号加1, 另外表达式作为一个整体,后面可以直接接数量词,
还有表达式中的|仅在该分组内有效 (abc){2} -> abcabc a(123|456)c -> a123c

re.findall(r'(\d)(\d)ab\1\2', '12ab12')
[('1', '2')]

\<number>引用编号为number的分组匹配到的字符串, (\d)ab\1 -> 1ab1 2ab2
补充:(...)被括起来的表达式将作为分组,从表达式的左边开始遇到一个分组的左括号'(',编号加1, 这个分组除了有这个编号还可以额外的指定一个别名:
(?P<name>..) 如 (?P<id>abc){2} ->abcabc
使用:引用别名为name的分组匹配到的字符串:
(?P<id>\d)abc(?P=id)
re.findall(r'(?P<id>\d)abc(?P=id)', '1abc1 2abc2')
['1', '2']

题外话

深拷贝 浅拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
浅拷贝:
1. 拷贝指向对象的指针, 意思就是拷贝出来的目标对象的指针和源对象的指针指向是同一块内存空间
2. 这是一种简单的拷贝. 即让几个对象公用一块内存. 然而当这块内存销毁的时候, 可以会重复销毁几次, 内存就会崩掉.
深拷贝:
1. 拷贝指针指向的具体内容, 拷贝结束之后, 内存中的值时完全一样的, 但是拷贝出来的目标对象和源对象的内存地址是不一样的,
这两个对象之间互不影响.


两者之间的原理 : 如果现在有一个A对象,拷贝之后得到一份新的对象A_Copy,
如果时浅拷贝,那么A对象和A_Copy对象指向的就是同一个内存的资源,
它拷贝的只是一个指针而已,对象的内容并没有拷贝.也就是说对象的资源还是只有一份.
如果这个时候我们对A_copy对象进行修改操作,那么A对象的内容同样会被修改.
然而如果是深拷贝,拷贝的不仅仅是指针,还有内容,拷贝的对象B_Copy会自助分配内存,
两个对象的指针指向的是不同的内存空间,因为A对象和B_Copy对象的内存地址是不一样的,
所以,如果我们对B_Copy进行修改操作的话是不会影响到A对象,它们之间是互不干涉的

总之,
1. 浅拷贝就类似你和你的影子的关系, 你挂了, 你的影子也挂了.
2. 深拷贝则就是 你挂了, 但是你的克隆人还活着.

以前写的东西也没整理的习惯, 这次先整理一部分, 内容可能有点乱, 还望谅解!

期待大牛带我飞😯😯😯😯😯😯