常用的CentOS6.7中,默认自带的Python版本还是2.6.6,升级到2.7.11后,安装某些第三方的库提示ImportError: No module named zlib 百度了一下,按照前辈的方法果然解决了问题。特此记录下来!

bash部分

1
yum install zlib zlib-devel openssl

python部分

1
2
3
4
cd Python2.7.11
./configure --prefix=/usr/local/python27
make
make install

验证

1
2
3
>>> import zlib
>>>
>>>

没有结果就是最好的结果!

切片

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
In [3]: l = list(range(100))

#取前5个元素
In [4]: l[:5]
Out[4]: [0, 1, 2, 3, 4]

#取后5个元素
In [5]: l[-5:]
Out[5]: [95, 96, 97, 98, 99]

#取第11-20的元素
In [6]: l[11:20]
Out[6]: [11, 12, 13, 14, 15, 16, 17, 18, 19]

#取前10个元素,每2个取一个
In [7]: l[:10:2]
Out[7]: [0, 2, 4, 6, 8]

#取第1-10的元素,每2个取一个
In [8]: l[1:10:2]
Out[8]: [1, 3, 5, 7, 9]

#取全部的元素,每10个取一个
In [9]: l[::10]
Out[9]: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

#取得全部元素
In [10]: l[:]

#记住最后一个元素的索引是-1
In [11]: l[-1]
Out[11]: 99

list切片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
In [1]: l = ['apple', 'google', 'facebook', 'microsoft', 'linkin']

In [2]: l
Out[2]: ['apple', 'google', 'facebook', 'microsoft', 'linkin']

In [3]: l[0:3]
Out[3]: ['apple', 'google', 'facebook']

In [4]: l[:3]
Out[4]: ['apple', 'google', 'facebook']

In [5]: l[1:3]
Out[5]: ['google', 'facebook']

In [6]: l[-2:]
Out[6]: ['microsoft', 'linkin']

In [7]: l[-2:-1]
Out[7]: ['microsoft']

tuple切片

1
2
In [13]: (0, 1, 2, 3, 4, 5)[:3]
Out[13]: (0, 1, 2)

str切片

1
2
In [14]: 'apple'[:3]
Out[14]: 'app'

迭代

在Python中迭代是通过for ... in ...来实现的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
In [15]: d = {'apple':'pages', 'google':'docs', 'microsoft':'word'}

In [16]: for key in d:
....: print key
....:
google
apple
microsoft

In [17]: for value in d.values():
....: print value
....:
docs
pages
word

In [18]: for k, v in d.items():
....: print k,v
....:
google docs
apple pages
microsoft word

列表、元组、字典和字符串都是可迭代对象
判断一个对象是否是可迭代对象,通过collections模块的Iterable来判断

1
2
3
4
5
6
7
8
9
10
11
12
13
In [22]: from collections import Iterable

In [23]: isinstance('123', Iterable)
Out[23]: True

In [24]: isinstance([1, 2, 3], Iterable)
Out[24]: True

In [25]: isinstance((1, 2, 3), Iterable)
Out[25]: True

In [26]: isinstance({'a':1, 'b':2, 'c':3}, Iterable)
Out[26]: True

enumerate

Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身

1
2
3
4
5
6
In [27]: for i, value in enumerate(['A', 'B', 'C']):
....: print(i, value)
....:
(0, 'A')
(1, 'B')
(2, 'C')

列表生成式

列表生成式有自己的特殊语法
把要生成的元素放到最前面,后跟for循环,就可以创建一个list

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
n [29]: [i * i for i in range(1,10)]
Out[29]: [1, 4, 9, 16, 25, 36, 49, 64, 81]

#二层循环实现全排列
In [30]: [m + n for m in 'ABC' for n in 'XYZ']
Out[30]: ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

#列出根目录下的所有文件和文件夹
In [37]: [f for f in os.listdir('/')]
Out[37]:
['.autorelabel',
'lib',
'sbin',
'proc',
'dev',
'lib64',
'mnt',
'usr',
'etc',
'var',
'selinux',
'.autofsck',
'sys',
'srv',
'media',
'tmp',
'data',
'boot',
'lost+found',
'home',
'root',
'opt',
'bin']

#列表生成式使用两个变量来生成列表
In [38]: d
Out[38]: {'apple': 'pages', 'google': 'docs', 'microsoft': 'word'}

In [39]: [k + '-->' + v for k,v in d.items()]
Out[39]: ['google-->docs', 'apple-->pages', 'microsoft-->word']

#将列表中的元素全部转为小写或大写
In [42]: l = ['apple', 'google', 'facebook']

In [43]: [s.lower() for s in l]
Out[43]: ['apple', 'google', 'facebook']

In [44]: [s.upper() for s in l]
Out[44]: ['APPLE', 'GOOGLE', 'FACEBOOK']

In [45]: l.append(59)

In [46]: l
Out[46]: ['apple', 'google', 'facebook', 59]

In [47]: [s.upper() for s in l]
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-47-0e109a4f23f3> in <module>()
----> 1 [s.upper() for s in l]

AttributeError: 'int' object has no attribute 'upper'

#上面遇到列表中出现字符串和数字混合的情况,数字对象没有upper()或lower()方法
#这时需要使用判断来排除数字的情况

In [52]: l
Out[52]: ['apple', 'google', 'facebook', 59]

In [53]: [s.upper() for s in l if isinstance(s, str)]
Out[53]: ['APPLE', 'GOOGLE', 'FACEBOOK']

生成器(yield)

生成器返回一个可迭代的对象

生成器的关键字yield,与return的区别是

  • return 立即返回结果并结束函数

  • yield 返回结果并暂停函数,等待next()的下一次调用

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
In [1]: def my_fun():
...: sum = 1
...: while True:
...: sum = sum + 1
...: yield sum
...:

In [2]: m = my_fun()

In [3]: m.next()
Out[3]: 2

In [4]: m.next()
Out[4]: 3

In [5]: m.next()
Out[5]: 4

In [6]: m.next()
Out[6]: 5

In [7]: my_fun()
Out[7]: <generator object my_fun at 0x2767a00>

In [8]: my_fun().next()
Out[8]: 2

In [9]: my_fun().next()
Out[9]: 2

In [10]: my_fun().next()
Out[10]: 2

上面介绍的列表生成式也可以变成生成器生成式

只需把中括号换成小括号就变成了一个生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
In [11]: L = [x * x for x in range(10)]

In [12]: L
Out[12]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

In [13]: G = (x * x for x in range(10))

In [14]: G
Out[14]: <generator object <genexpr> at 0x2767aa0>

In [15]: G.next()
Out[15]: 0

In [16]: G.next()
Out[16]: 1

In [17]: G.next()
Out[17]: 4

生成器保存的是算法,在使用时计算结果,节省内存空间


迭代器

可以直接作用于for循环的数据类型有以下几种:

  • 集合数据类型。如list tuple dict set str

  • generator,包括生成器和带yield的generator function

这些可以直接作用于for循环的对象统称为可迭代对象Iterable

可以使用isinstance()判断一个对象是否是Iterable可迭代对象

1
2
3
4
In [20]: from collections import Iterable

In [21]: isinstance([],Iterable)
Out[21]: True

生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,最后抛出StopIteration异常,表示已经结束,无法返回下一个值

可以被next()函数调用并不断返回下一个值的对象称为迭代器Iterator

可以使用isinstance()判断一个对象是否是Iterator对象

1
2
3
4
5
6
7
In [24]: from collections import Iterator

In [25]: isinstance((x for x in range(10)), Iterator)
Out[25]: True

In [26]: isinstance([], Iterator)
Out[26]: False

Iterator 和 Iterable的区别

  • 生成器都是Iterator对象,但list dict等是Iterable,但不是Iterator

  • Iterator是迭代器,需要同时具备__iter__next两个方法,它们表示一个惰性计算的序列

  • Iterable是可迭代对象,列表元组等数据结构同样是可迭代对象,具备__iter__方法,但不具备next方法

使用for循环遍历可迭代对象时,for循环自动调用next()函数,并在接收到结束异常时退出循环


参考文章:http://www.liaoxuefeng.com/

定义函数

基础语法

1
2
3
def my_fun(arg):
print "run function"
return arg * arg

如果没有写return语句,函数执行之后会返回None

函数的返回值

可以有多个返回值,但是多个返回值默认是以元组的方式返回,相当于返回了一个元组

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> def my_fun3(arg1, arg2):
... x = arg1 + 59
... y = arg2 + 59
... return x,y
...
>>> r = my_fun3(12,78)
>>> type(r)
<type 'tuple'>
>>> print r
(71, 137)
>>> r, t = my_fun3(56, 89)
>>> print r,t
115 148

空函数

1
2
def my_fun2():
pass

调用函数

function_name()是调用函数的基本语法

  • function_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
>>> def my_fun4():
... print "hello"
... print "world"
...
>>> my_fun4()
hello
world
# my_fun4函数里面只有两行打印语句,没有定义返回值,所以返回值默认为空(None)
>>> s = my_fun4()
hello
world
>>> print s
None
>>> type(s)
<type 'NoneType'>
>>>
>>>
>>> def my_fun5():
... return "hello world"
...
# my_fun5函数里面定义了返回值
>>> ss = my_fun5()
>>> print ss
hello world
>>> type(ss)
<type 'str'>

函数的参数

默认参数

拿一个简单的幂运算举例
n=2即为默认参数,在调用该函数时,如果只指定了一个参数,那变量n将默认等于2

1
2
3
4
5
6
7
>>> def my_fun6(x, n=2):
... return x ** n
...
>>> my_fun6(3)
9
>>> my_fun6(3,3)
27

也可以将两个参数都设置有默认变量,这样该函数即使不传参,也能正常工作

1
2
3
4
5
6
7
8
9
>>> my_fun6()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: my_fun6() takes at least 1 argument (0 given)
>>> def my_fun7(x=3,n=2):
... return x ** n
...
>>> my_fun7()
9

使用默认参数的注意事项

  • 必选参数在前,默认参数在后,否则Python解释器会报错

  • 当函数需要多个参数的时候,将变化较大的参数放在前面,变化小的放在后面作为默认参数

  • 默认参数必须指向不可变对象(eg: int, string, float)

可变参数

可以折衷地使用列表或元组实现可变长参数
(以下交互终端使用了ipython)

1
2
3
4
5
6
7
8
9
10
11
In [1]: def cal(numbers):
...: sum = 0
...: for i in numbers:
...: sum = sum + i
...: return sum

In [2]: cal([1,2,3])
Out[2]: 6

In [3]: cal((1,2,3))
Out[3]: 6

可变参数的关键字为*星号。在设置函数的接收参数时,前面加上一个星号,则函数内部接收到的所有参数会自动转化为一个元组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
In [5]: def cal(*numbers):
...: sum = 0
...: for i in numbers:
...: sum = sum + i
...: return sum
...:

In [6]: cal(1,2,3)
Out[6]: 6

In [7]: cal()
Out[7]: 0

In [8]: cal(1,2,3,4,5,6)
Out[8]: 21
1
2
3
4
5
6
In [9]: def cal(*numbers):
...: return type(numbers)
...:

In [10]: cal()
Out[10]: tuple

关键字参数

可变长参数传入到函数内部会自动转换成一个元组;而关键字参数传入到函数内部会自动转换成一个字典
关键字参数的关键字是**两个星号

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
In [12]: def person(name, age, **otherkeyword):
....: print 'name: ', name, '\n', 'age: ', age, '\n', 'otherInfo: ', otherkeyword
....:

In [13]: person('ps',24)
name: ps
age: 24
otherInfo: {}

In [14]: person('ps',24,city='BJ')
name: ps
age: 24
otherInfo: {'city': 'BJ'}

In [15]: person('ps',24,city='BJ',job='Engineer')
name: ps
age: 24
otherInfo: {'city': 'BJ', 'job': 'Engineer'}

In [16]: dict_kw = {'city': 'BJ', 'job': 'Engineer'}

In [17]: dict_kw
Out[17]: {'city': 'BJ', 'job': 'Engineer'}

In [18]: person('ps',24,**dict_kw)
name: ps
age: 24
otherInfo: {'city': 'BJ', 'job': 'Engineer'}

参数组合

上面提到了四种参数(必选参数、默认参数、可变参数、关键字参数),这四种参数可以一起使用。
参数定义的顺序必须是:必须参数、默认参数、可变参数、关键字参数

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
In [21]: def func(a, b, c=0, *args, **kw):
....: print 'a:', a, '\n', 'b:', b, '\n', 'c:', c, '\n', 'tuple_args:', args, '\n', 'dict_kw:', kw
....:

In [22]: func(1,2)
a: 1
b: 2
c: 0
tuple_args: ()
dict_kw: {}

In [23]: func(1,2,c=3)
a: 1
b: 2
c: 3
tuple_args: ()
dict_kw: {}

In [24]: func(1,2,c=3,4,5)
File "<ipython-input-24-9272b7482bc9>", line 1
SyntaxError: non-keyword arg after keyword arg

In [25]: func(1,2,3,4,5)
a: 1
b: 2
c: 3
tuple_args: (4, 5)
dict_kw: {}

In [26]: func(1,2,3,4,5,x=59)
a: 1
b: 2
c: 3
tuple_args: (4, 5)
dict_kw: {'x': 59}

注意

  • *args是可变参数,接收一个tuple

  • **kw是关键字参数,接收一个dict

  • 在必选参数,默认参数,可变长参数和关键字参数混合使用时,默认参数在复制时不要指定参数名,如上例的c=3 否则会报错

常用内置函数

isinstance

isinstance函数判断对象类型

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
>>> class obj1:
... pass
...
>>> o = obj1()
>>> t = (1,2,3)
>>> l = [1,2,3]
>>> d = {'a':1,'b':2,'c':3}
>>> s = 'string'
>>> i = 6
>>> f = 5.9
>>>
>>> print isinstance(o, obj1)
True
>>> print isinstance(t, tuple)
True
>>> print isinstance(l, list)
True
>>> print isinstance(d, dict)
True
>>> print isinstance(s, str)
True
>>> print isinstance(i, int)
True
>>> print isinstance(f, float)
True

Python中解析YAML文件主要使用到两个方法,load()和dump()方法,使用方式类似于Python的pickle。熟悉在Python中解析YAML文件,对使用Python做saltstack自定义插件开发时会有很大的帮助

load

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@PolarSnow saltstack]# cat eg.yaml 
name: Tom Smith
age: 37
spouse:
name: Jane Smith
age: 25
children:
- name: Jimmy Smith
age: 15
- name1: Jenny Smith
age1: 12

[root@PolarSnow saltstack]# cat py_yaml.py
#!/usr/bin/env python
#coding=utf-8
import yaml

with open('eg.yaml', 'r') as loadfile:
print yaml.load(loadfile)

[root@PolarSnow saltstack]# python py_yaml.py
{'age': 37, 'spouse': {'age': 25, 'name': 'Jane Smith'}, 'name': 'Tom Smith', 'children': [{'age': 15, 'name': 'Jimmy Smith'}, {'age1': 12, 'name1': 'Jenny Smith'}]}

关键代码

1
2
3
4
5
#!/usr/bin/env python
#coding=utf-8
import yaml
with open('eg.yaml', 'r') as loadfile:
print yaml.load(loadfile)

dump

测试

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
[root@PolarSnow saltstack]# cat eg.yaml 
name: Tom Smith
age: 37
spouse:
name: Jane Smith
age: 25
children:
- name: Jimmy Smith
age: 15
- name1: Jenny Smith
age1: 12

[root@PolarSnow saltstack]# cat py_yaml.py
#!/usr/bin/env python
#coding=utf-8
import yaml
with open('eg.yaml', 'r') as loadfile:
y = yaml.load(loadfile)
print y
with open('eg1.yaml','w') as dumpfile:
dumpfile.write(yaml.dump(y))
print yaml.dump(y)

[root@PolarSnow saltstack]# python py_yaml.py
{'age': 37, 'spouse': {'age': 25, 'name': 'Jane Smith'}, 'name': 'Tom Smith', 'children': [{'age': 15, 'name': 'Jimmy Smith'}, {'age1': 12, 'name1': 'Jenny Smith'}]}
age: 37
children:
- {age: 15, name: Jimmy Smith}
- {age1: 12, name1: Jenny Smith}
name: Tom Smith
spouse: {age: 25, name: Jane Smith}

[root@PolarSnow saltstack]# cat eg1.yaml
age: 37
children:
- {age: 15, name: Jimmy Smith}
- {age1: 12, name1: Jenny Smith}
name: Tom Smith
spouse: {age: 25, name: Jane Smith}

关键代码

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python
#coding=utf-8
import yaml

#打开一个yaml文件将其解析,再将解析后的结构再转成yaml写入到新的文件
with open('eg.yaml', 'r') as loadfile:
y = yaml.load(loadfile)
print y

with open('eg1.yaml','w') as dumpfile:
dumpfile.write(yaml.dump(y))
print yaml.dump(y)

Python基础知识笔记


运行一个脚本后再进入交互终端 python -i

使用-i参数

1
2
3
4
5
$ echo "#!/usr/bin/env python
import sys" > test.py

$ python -i test.py
>>> sys.path

print的内容禁止转义 \

使用 r' '使单引号中的所有字符禁止转义

1
2
3
4
5
>>> print 'x\ny\tz'
x
y z
>>> print r'x\ny\tz'
x\ny\tz

打印多行 ‘’’…’’’

使用\n输入多行时可能不太好阅读,可以通过''' '''三引号的方式来输出多行

1
2
3
4
5
6
7
>>> print '''line one
... line two
... line three
... '''
line one
line two
line three

常量 PI

在Python中的常量也是一个变量,只不过为了显示这是个常量,约定俗成用大写表示常量
在Python中没有任何机制保证大写的变量不会被更改!

1
>>> PI = 3.1415926

字符串与数字间的转换(ASCII)

1
2
3
4
>>> ord('L')
76
>>> chr(76)
'L'

在Python中使用Unicode编码

1
2
3
4
5
6
7
8
>>> '中文'
'\xe4\xb8\xad\xe6\x96\x87'
>>> u'中文'
u'\u4e2d\u6587'
>>> print u'中文'
中文
>>> print u'\u4e2d\u6587'
中文

Unicode与禁止转义连用 print ur’…’

1
2
3
4
5
6
>>> print u'中\t文'
中 文
>>> print ur'中\t文'
中\t文
>>> ur'中\t文'
u'\u4e2d\\t\u6587'

Unicode与utf-8字符编码间的转换

Unicode 2 UTF-8

1
2
3
4
5
6
7
8
>>> u'ABC'
u'ABC'
>>> u'ABC'.encode('utf-8')
'ABC'
>>> u'中文'
u'\u4e2d\u6587'
>>> u'中文'.encode('utf-8')
'\xe4\xb8\xad\xe6\x96\x87'

UTF-8 2 Unicode

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> '\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
u'\u4e2d\u6587'
>>> print '\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
中文
>>> print u'\u4e2d\u6587'
中文
>>>
>>> 'ABC'.decode('utf-8')
u'ABC'
>>> print 'ABC'.decode('utf-8')
ABC
>>> print u'ABC'
ABC

Python文件中使用中文的声明 print u’…’

1
2
3
#!/usr/bin/env python
#coding=utf-8
print u'中文'

字符串格式化(占位符)

常见的占位符:

  • %d 整数
  • %f 浮点数
  • %s 字符串
1
2
3
4
>>> print 'Hi %s' % 'ps'
Hi ps
>>> print 'Hi %s, I have %d questions to ask you' % ('ps', 59)
Hi ps, I have 59 questions to ask you

对Unicode字符串进行占位时,字符编码需要前后保持一致

1
2
>>> print u'Hi %s, I have %d questions to ask you' % (u'ps', 59)
Hi ps, I have 59 questions to ask you

对占位符转义%%–>’%’

1
2
3
4
5
6
>>> print "update %d%" % 59
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: incomplete format
>>> print "update %d%%" % 59
update 59%

列表

1
2
3
>>> testlist = ['Apple', 'Microsoft', 'Samaung']
>>> testlist
['Apple', 'Microsoft', 'Samaung']

取值 list[index]

列表中最后一个元素的位置是len(testlist) - 1 or testlist[-1]

以此类推,倒数第二个元素是testlist[-2]

1
2
3
4
5
6
7
8
9
10
11
12
>>> testlist
['Apple', 'Microsoft', 'Samaung']
>>> len(testlist)
3
>>> len(testlist) - 1
2
>>> testlist[len(testlist) - 1]
'Samaung'
>>> testlist[-1]
'Samaung'
>>> testlist[-2]
'Microsoft'

追加 append(value)

1
2
3
4
5
>>> testlist
['Apple', 'Microsoft', 'Samaung']
>>> testlist.append('lastvalue')
>>> testlist
['Apple', 'Microsoft', 'Samaung', 'lastvalue']

插入 insert(index, value)

1
2
3
4
5
>>> testlist
['Apple', 'Microsoft', 'Samaung', 'lastvalue']
>>> testlist.insert(1, 'secondvalue')
>>> testlist
['Apple', 'secondvalue', 'Microsoft', 'Samaung', 'lastvalue']

删除末尾及指定位置的元素 pop(index)

1
2
3
4
5
6
7
8
9
10
>>> testlist
['Apple', 'secondvalue', 'Microsoft', 'Samaung', 'lastvalue']
>>> testlist.pop()
'lastvalue'
>>> testlist
['Apple', 'secondvalue', 'Microsoft', 'Samaung']
>>> testlist.pop(1)
'secondvalue'
>>> testlist
['Apple', 'Microsoft', 'Samaung']

替换元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#直接覆盖
>>> testlist
['Apple', 'Microsoft', 'Samaung']
>>> testlist[2] = 'Google'
>>> testlist
['Apple', 'Microsoft', 'Google']
``

## 二维数组

```python
>>> testlist = [['iPhone', 'iPad', 'iMac'], 'Microsoft', 'Google']
>>> testlist
[['iPhone', 'iPad', 'iMac'], 'Microsoft', 'Google']
>>> len(testlist)
3
>>> testlist[0][1]
'iPad'

元组

单个元素的元组

1
2
3
4
5
6
7
8
9
10
>>> testtuple = ('apple')
>>> testtuple
'apple'
>>> type(testtuple)
<type 'str'>
>>> testtuple = ('apple', )
>>> testtuple
('apple',)
>>> type(testtuple)
<type 'tuple'>

“可变元组”

一般情况下元组是不可变的数据结构,如果需要实现让元组可变,可以在元组中加入列表来实现

1
2
3
4
5
6
7
8
9
10
>>> testtuple = (['iPhone', 'iPad', 'iMac'], 'Microsoft', 'Google')
>>> testtuple
(['iPhone', 'iPad', 'iMac'], 'Microsoft', 'Google')
>>> testtuple[0].append('iPod')
>>> testtuple
(['iPhone', 'iPad', 'iMac', 'iPod'], 'Microsoft', 'Google')
>>> testtuple[0][2] = 'MBP'
>>> testtuple
(['iPhone', 'iPad', 'MBP', 'iPod'], 'Microsoft', 'Google')
#元组的指向并没有变,所以这个元组可以认为仍然没有变化,变的是元组中list的元素

if判断语句

基础语法

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> results = 100
>>> if results < 0 or results > 100:
... print "OMG!!!"
... elif 0 <= results < 60:
... print "Fail!!!"
... elif 60 <= results < 80:
... print "OK!!!"
... elif results >= 80 and results <=100:
... print "good!!!"
... else:
... print "Impossible!!!"
...
good!!!

简写

只要x是非零数值、非空字符串、非空list等,就判断为True,否则为False

1
2
3
4
5
6
7
8
9
>>> x = ''
>>> x
''
>>> if x:
... print 'not null'
... else:
... print 'null'
...
null

循环

for…in…

1
2
3
4
5
6
7
>>> testtuple = (['iPhone', 'iPad', 'iMac'], 'Microsoft', 'Google')
>>> for t in testtuple:
... print t
...
['iPhone', 'iPad', 'iMac']
Microsoft
Google

while

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> start = 0
>>> end = 9
>>> while True:
... print start
... start = start + 1
... if start > end:
... break
...
0
1
2
3
4
5
6
7
8
9

raw_input

num = raw_input('please input a num:')

字典

基础语法

1
2
3
>>> p = {'apple':'pages', 'microsoft':'word', 'google':'docs'}
>>> p['apple']
'pages'

检查元素是否包含在字典中

1
2
3
4
>>> p = {'apple':'pages', 'microsoft':'word', 'google':'docs'}
>>> p['apple']
'pages'
>>> 'apple' in p
1
2
3
4
5
#查找不到元素会返回None空
>>> p.get('google')
'docs'
>>> p.get('baidu')
>>>

删除一个key

1
2
3
4
>>> p.pop('google')
'docs'
>>> p
{'apple': 'pages', 'microsoft': 'word'}

in关键字

1
2
3
4
5
6
7
8
9
10
11
#判断一个元素是否包含在一个字典中
>>> p = {'apple':'pages', 'microsoft':'word', 'google':'docs'}
>>> p['apple']
'pages'
>>> 'apple' in p
True
#判断一个元素是否包含在一个列表中
>>> testlist
[['iPhone', 'iPad', 'iMac'], 'Microsoft', 'Google']
>>> 'Google' in testlist
True

集合

  • 可变集合(set)
  • 不可变集合(frozenset)

集合的基本使用

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
>>> s = set([1, 2, 3])
>>> s
set([1, 2, 3])
>>> type(s)
<type 'set'>

## 访问集合

集合是无序的,所以不能对集合创建索引或切片的操作,只能循环遍历或使用innot in来访问或判断集合元素

```python
>>> s = set([1, 2, 3, 4])
>>> s
set([1, 2, 3, 4])
>>> 2 in s
True
>>> 5 in s
False
>>> for i in s:
... print i
...
1
2
3
4

集合中的元素不能重复,集合会自动过滤掉重复的元素

1
2
3
4
5
6
>>> s.add(4)
>>> s
set([1, 2, 3, 4])
>>> s.add(4)
>>> s
set([1, 2, 3, 4])

删除集合中的元素

1
2
3
>>> s.remove(2)
>>> s
set([1, 3, 4])

交集与并集

1
2
3
4
5
6
>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s1 & s2
set([2, 3])
>>> s1 | s2
set([1, 2, 3, 4])

子集(真子集)超集(真超集)

子集包含集合本身,真子集不包含本身!如(1,2)的子集有:空集,(1),(2),(1,2).而真子集有:空集,(1),(2)没有(12)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#子集(<=)  真子集(<)
>>> set('shop') < set('bookshop')
True
>>> set('shop') <= set('bookshop')
True
>>> set('bookshop') < set('bookshop')
False
>>> set('bookshop') <= set('bookshop')
True
#超集(>=) 真超集(>)
>>> set('bookshop') > set('shop')
True
>>> set('bookshop') >= set('shop')
True
>>> set('bookshop') > set('bookshop')
False
>>> set('bookshop') >= set('bookshop')
True

异或

1
2
3
4
5
6
7
8
>>> s1
set([1, 2, 3])
>>> s2
set([2, 3, 4])
>>> s1 ^ s2
set([1, 4])
>>> s1.symmetric_difference(s2)
set([1, 4])

差补/相对补集

1
2
3
4
5
6
7
8
9
>>> s1
set([1, 2, 3])
>>> s2
set([2, 3, 4])
set([1, 4])
>>> s1 - s2
set([1])
>>> s2 -s1
set([4])

集合的应用: 去重

强制类型转换

字典

字典 2 字符串

1
2
3
4
5
>>> d = {'a':1, 'b':2}
>>> d
{'a': 1, 'b': 2}
>>> print type(str(d)), str(d)
<type 'str'> {'a': 1, 'b': 2}

字典 2 元组

1
2
3
4
5
6
7
>>> d = {'a':1, 'b':2}
>>> d
{'a': 1, 'b': 2}
>>> print tuple(d)
('a', 'b')
>>> print tuple(d.values())
(1, 2)

字典 2 列表

1
2
3
4
5
6
7
>>> d = {'a':1, 'b':2}
>>> d
{'a': 1, 'b': 2}
>>> print list(d)
['a', 'b']
>>> print list(d.values())
[1, 2]

元组

元组 2 字符串

1
2
3
4
5
>>> t = (1, 2, 3)
>>> t
(1, 2, 3)
>>> print type(str(t)), str(t)
<type 'str'> (1, 2, 3)

元组 2 列表

1
2
3
4
5
>>> t = (1, 2, 3)
>>> t
(1, 2, 3)
>>> print type(list(t)), list(t)
<type 'list'> [1, 2, 3]

元组 2 集合

1
2
3
4
5
>>> t = (1, 2, 3)
>>> t
(1, 2, 3)
>>> print type(set(t)), set(t)
<type 'set'> set([1, 2, 3])

元组不能转成字典

列表

列表 2 字符串

1
2
3
4
5
>>> l = [1, 2, 3]
>>> l
[1, 2, 3]
>>> print type(str(l)), str(l)
<type 'str'> [1, 2, 3]

列表 2 元组

1
2
3
4
5
>>> l = [1, 2, 3]
>>> l
[1, 2, 3]
>>> print type(tuple(l)), tuple(l)
<type 'tuple'> (1, 2, 3)

列表 2 集合

1
2
3
4
5
>>> l = [1, 2, 3]
>>> l
[1, 2, 3]
>>> print type(set(l)), set(l)
<type 'set'> set([1, 2, 3])

列表不能转成字典

字符串

字符串 2 列表

1
2
3
4
5
6
7
>>> s = "[[1,2], [3,4], [5,6], [7,8], [9,0]]"
>>> s
'[[1,2], [3,4], [5,6], [7,8], [9,0]]'
>>> print list(s)
['[', '[', '1', ',', '2', ']', ',', ' ', '[', '3', ',', '4', ']', ',', ' ', '[', '5', ',', '6', ']', ',', ' ', '[', '7', ',', '8', ']', ',', ' ', '[', '9', ',', '0', ']', ']']
>>> print type(eval(s)), eval(s)
<type 'list'> [[1, 2], [3, 4], [5, 6], [7, 8], [9, 0]]

字符串 2 字典

1
2
3
4
5
>>> s = "{1: 'a', 2: 'b'}"
>>> s
"{1: 'a', 2: 'b'}"
>>> print type(eval(s)), eval(s)
<type 'dict'> {1: 'a', 2: 'b'}

字符串 2 元组

1
2
3
>>> s = "([1,2], [3,4], [5,6], [7,8], (9,0))"
>>> print type(eval(s)), eval(s)
<type 'tuple'> ([1, 2], [3, 4], [5, 6], [7, 8], (9, 0))

字符串 2 集合

1
2
3
>>> s = "test"
>>> print type(set(s)), set(s)
<type 'set'> set(['s', 'e', 't'])

YAML的数据结构

YAML的设计者认为在配置文件中所要表达的数据内容有三种类型

  • Scalars(标量,如字符串和数字等)
  • Sequence (序列,类似于Python中列表的概念)
  • Mapping (类似于Python中字典的概念)

Sequence of Scalars

YAML(ball players)

1
2
3
- Mark McGwire
- Sammy Sosa
- Ken Griffey

Python(YAML)

1
['Mark McGwire', 'Sammy Sosa', 'Ken Griffey']

Mapping Scalars to Scalars

YAML(player statistics)

1
2
3
hr:  65    # Home runs
avg: 0.278 # Batting average
rbi: 147 # Runs Batted In

Pyhton(YAML)

1
{'hr':65, 'avg':0.278, 'rbi':147}

Mapping Scalars to Sequences

YAML(ball clubs in each league)

1
2
3
4
5
6
7
8
american:
- Boston Red Sox
- Detroit Tigers
- New York Yankees
national:
- New York Mets
- Chicago Cubs
- Atlanta Braves

Python(YAML)

1
{'american':['Boston Red Sox', 'Detroit Tigers', 'New York Yankees'], 'national':['New York Mets', 'Chicago Cubs', 'Atlanta Braves']}

Sequence of Mappings

YAML(players’ statistics)

1
2
3
4
5
6
7
8
-
name: Mark McGwire
hr: 65
avg: 0.278
-
name: Sammy Sosa
hr: 63
avg: 0.288

Python(YAML)

1
[{'name':'Mark McGwire', 'hr':65, 'avg':0.278}, {'name':'Sammy Sosa', 'hr':63, 'avg':0.288}]

Sequence of Sequences

YAML

1
2
3
- [name        , hr, avg  ]
- [Mark McGwire, 65, 0.278]
- [Sammy Sosa , 63, 0.288]

Python(YAML)

1
[['name', 'hr', 'avg'], ['Mark McGwire', 65, 0.278], ['Sammy Sosa', 63, 0.288]]

Mapping of Mappings

YAML

1
2
3
4
5
Mark McGwire: {hr: 65, avg: 0.278}
Sammy Sosa: {
hr: 63,
avg: 0.288
}

Python(YAML)

1
{'Mark McGwire':{'hr':65, 'avg':0.278}, 'Sammy Sosa':{'hr':63, 'avg':0.288}}

YAML中的注释

YAML

1
2
3
4
#ball players
- Mark McGwire
- Sammy Sosa
- Ken Griffey

YAML中的文档

在单一一个YAML文件中

  • 使用三个下划线___来分隔文档
  • 使用三个句号...表示结束(一般在通信信道中使用)

YAML(Two Documents in a Stream)

1
2
3
4
5
6
7
8
9
10
# Ranking of 1998 home runs
---
- Mark McGwire
- Sammy Sosa
- Ken Griffey

# Team ranking
---
- Chicago Cubs
- St Louis Cardinals

YAML

1
2
3
4
5
6
7
8
9
10
---
time: 20:03:20
player: Sammy Sosa
action: strike (miss)
...
---
time: 20:03:47
player: Sammy Sosa
action: grand slam
...

实例

YAML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
用YAML来描述一本书《Linux命令行与shell脚本编程大全》

# 《Linux命令行与shell脚本编程大全》描述
--- # begin of document
书名: 'Linux命令行与shell脚本编程大全'
出版社: '人民邮电出版社'
原作者: ['Richard Blum', 'Christine Bresnahan']
译者:
- 武海峰
- 朱巍
前二章节:
- 第一章: 初识Linux Shell
- 第二章: 走进Shell

#end of document

Python(YAML)

1
{'书名':'Linux命令行与shell脚本编程大全', '出版社':'人民邮电出版社', '原作者':['Richard Blum', 'Christine Bresnahan'], '译者':['武海峰', '朱巍'], '前二章节':{'第一章':'初识Linux Shell', '第二章':'走进Shell'}}

参考文档:

在使用salt进行软件管理的时候,有些节点报 No module named yum 的错误。经过排查,发现是因为升级了minion端Python版本后产生的问题

msater

1
2
3
4
5
6
$ salt 'vm3.salt.com' pkg.install httpd
vm3.salt.com:
ERROR: Traceback (most recent call last):
File "/usr/bin/repoquery", line 34, in <module>
import yum
ImportError: No module named yum

服务器自带的Python版本是2.6.6 由于其他业务的需求,Python的版本升级到了2.7.10,升级后首先yum命令处于不可用的状态,通过修改/usr/bin/yum文件的第一行#!/usr/bin/python#!/usr/bin/python2.6来修复yum命令的使用

由于系统默认的Python已经由2.6.6变更到了2.7.10

1
2
$ ls -l /usr/bin/python
lrwxrwxrwx 1 root root 34 Oct 9 02:16 /usr/bin/python -> /usr/local/python2.7/bin/python2.7

salt master在派发任务后,minion接收到任务并在本地使用默认的Python来执行,实际使用了升级后默认的Python2.7.10,导致Python报找不到yum模块的错误

在网上搜索了很多方案,全部是修改yum默认使用的Python版本来解决问题,貌似不能通过让yum来支持高版本的Python来解决问题。so,要解决salt minion本地调用yum不报错,就必须要保证其使用Python2.6.6来执行!解决方案和yum命令的修复方式相同:

1
2
3
4
5
6
7
8
9
$ head /usr/bin/repoquery
#!/usr/bin/python -tt
#... ...

$ vim /usr/bin/repoquery

$ head /usr/bin/repoquery
#!/usr/bin/python2.6 -tt
#... ...

/usr/bin/repoquery文件第一行的#!/usr/bin/python -tt更改为#!/usr/bin/python2.6 -tt即可

密钥对儿的认证

当初始化安装 minion 启动服务启动后

  1. minion端生成一个秘钥对,并产生一个ID值,minion服务会安装ID值命名的公钥发送给 master ,直到接受为止;
  2. master认证完毕后,会将minion 端发送来的,以ID值命名的公钥存放在 /etc/salt/pki/master/minions 目录中(无扩展名);
  3. master认证完毕后,会将自身的公钥发送给 minion,并存储为 /etc/salt/pki/minion/minion_master.pub

minion id的生成过程

minion 默认按照一定的顺序,试图找到一个不是localhost的值作为其ID

这里不需要知道salt是按照怎样的顺序取值的,只需要记住以下优先级即可

hostname < /etc/salt/minion_id < /etc/salt/minion文件中的id值


密钥对儿存放的位置

  • master 秘钥对默认存储在
1
2
/etc/salt/pki/master/master.pub 
/etc/salt/pki/master/master.pem
  • master 端认证的公钥存储在:
1
/etc/salt/pki/master/minions/
  • minion 秘钥对默认存储在
1
2
/etc/salt/pki/minion/minion.pub 
/etc/salt/pki/minion/minion.pem
  • minion 存放的master公钥
1
/etc/salt/pki/minion/minion_master.pub
  • minion_id 默认存储在
1
/etc/salt/minion_id

在实际使用过程中,minion端可能会遇到各种原因导致的密钥对儿不匹配的情况,造成在master端显示在denied keys列表中无法通过认证。

  • [master]先在master端删除该id
  • [minion]再删除minion端的key文件
  • [minion]最后重启服务
1
2
3
4
5
6
7
8
rm -fr /etc/salt/pki/minion/minion_master.pub
#通过上面的介绍可以得知,以上这个文件是在master端认证通过之后,发放到minion端的公钥
#造成出现这个文件情况是因为早期连接了一个其他的master,更换master导致原公钥无法匹配
#删除与旧master认证的公钥文件
rm -fr /etc/salt/pki/minion/minion.pem #删除minion的私钥文件
rm -fr /etc/salt/pki/minion/minion.pub #删除minion的公钥文件
service salt-minion restart #重启服务 会自动重新生成新的密钥对儿
#此时master端查看keys时,新的主机已经出现在Unaccepted Keys的列表中了

参考文章 salt key 认证过程

saltstack安装及配置

首先安装epel源

1
2
rpm -ivh http://mirrors.kernel.org/fedora-epel/6/x86_64/epel-release-6-8.noarch.rpm
yum makecache

master

安装

1
yum install salt-master -y

配置

master端安装好后一般不需要任何设置,启动服务器即可

1
2
service salt-master start
chkconfig salt-master on

minion

安装

1
yum install salt-minion

配置

minion端至少需要配置两项,id和master需要指定。

  • id: 这台主机的唯一标识! 就像mac地址一样!
  • master: 指定salt master的IP地址或域名!

注意:注意冒号后面一定要有一个空格。

1
2
3
$ vim /etc/salt/minion
id: node1.salt.com
master: master.salt.com

master与minion的认证

master

1
2
3
4
5
6
salt-key -L #查看所有主机
#没有接受的key会显示在Unaccepted Keys下
salt-key -A #接受所有主机
salt-key -D #删除所有主机
salt-key -a node1.salt.com #接受指定的主机
salt-key -d node1.salt.com #删除指定的主机

一般情况下,master不会在配置文件中开启自动授权


测试连通性

master

1
2
3
$ salt '*' test.ping
node1.salt.com:
True

在salt master端执行salt ‘*’ test.ping时,某一节点出现如下报错:
Minion did not return. [No response]

登陆到这一节点查看minion的日志,发现如下的问题

1
2
3
4
5
6
7
8
$ tail -f /var/log/salt/minion
The master may need to be updated if it is a version of Salt lower than 2015.5.3, or
If you are confident that you are connecting to a valid Salt Master, then remove the master public key and restart the Salt Minion.
The master public key can be found at:
/etc/salt/pki/minion/minion_master.pub
2015-11-23 23:30:02,645 [salt.crypt ][ERROR ][3530] The Salt Master has cached the public key for this node, this salt minion will wait for 10 seconds before attempting to re-authenticate
2015-11-23 23:30:05,108 [salt.crypt ][ERROR ][3586] The Salt Master has cached the public key for this node, this salt minion will wait for 10 seconds before attempting to re-authenticate
2015-11-23 23:30:15,136 [salt.crypt ][ERROR ][3586] The Salt Master has cached the public key for this node, this salt minion will wait for 10 seconds before attempting to re-authenticate

大概的意思就是,minion端拿到的key与master端的不符,验证无法通过。
解决方法是删除minion端的key,再重新与master进行连接和认证。

minion

1
2
3
4
5
6
7
8
9
10
11
12
$ cat pki/minion/minion_master.pub 
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtzq0AjuyQsVEgsx692GN
... ...
7fbuudp4yu5vcYcqksKIFcm0J3E+OR+rx/NUIHt0ZL8HLxcSn4Si/S6dVp/vE7Oc
swIDAQAB
-----END PUBLIC KEY-----
[root@localhost salt]# rm -fr pki/minion/minion_master.pub

[root@localhost salt]# service salt-minion restart
Stopping salt-minion daemon: [ OK ]
Starting salt-minion daemon: [ OK ]

master

1
salt-key -A

minion

1
2
3
4
5
6
7
$ cat pki/minion/minion_master.pub 
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy46TJvK9BUqjvaYzmt5Q
... ...
ADw0hU6B/A1kRBeUbb6Fy+HljiSjD3O+mhoK7RE8rCnvJCHfuZSX/qMtLEyoh0vN
tQIDAQAB
-----END PUBLIC KEY-----

至此,master与minion端的通信正常。