python-05-02-模块

  • 目录
  • 相关概念
  • 模块os
  • 模块sys
  • 模块time
  • 模块random
  • 模块pickle
  • 模块json
  • 模块logging
  • 模块paramiko
  • 模块configparser
  • 模块MySQLdb
  • 模块hashlib
  • 模块uuid
  • 模块md5
  • 模块

相关概念

  • 过程编程 , 函数式编程, 模块化编程是一个意思,区别于面向对象编程
  • 面向对象编程好处:(特性: 封装,继承,多态)

python程序可以分解成模块,语句,表达式和 对象

  • 程序由模块构成
  • 模块包含语句
  • 语句包含表达式
  • 表达式建立并处理对象
    表达式是”某事“, 语句是“做某事”即指令
    语句的特性:它们改变了事物,例如,赋值语句改变了变量,print改变了屏幕输出。

模块导入的使用

1
2
3
4
5
6
>>> import platform
>>> print(platform.uname())
uname_result(system='Linux', node='ubuntu', release='4.2.0-35-generic', version='#40~14.04.1-Ubuntu SMP Fri Mar 18 16:37:35 UTC 2016', machine='x86_64', processor='x86_64')
>>> import platform
>>> dir(platform)
['DEV_NULL', '_UNIXCONFDIR', '__builtins__' 此处略... ]

模块导入区别

import 导入会形成以模块名同名的名称空间,如果有个方法叫uname(),那么我们调用是print(platform.uname())加上platform名称空间前缀不会冲突

1
2
3
4
5
6
>>> import random     # 独立名称空间
>>> random.choice([3,5,6,7,8,9])
7
>>> from random import choice # 没有独立名称空间,当前有choice方法会覆盖,这就是区别
>>> choice([3,5,6,7,8,9])
6

from-import是导入指定模块的某些方法和属性,会导入在当前名称空间里,如果当前名称空间也有choice方法,那么会覆盖choice方法。
import和from-import是可执行语句,独立可执行片断,可以嵌套在if测试中,或出现在def中,这样在我们满足条件再导入模块。

己知模块查找此模块在系统中的路径,用法module_name.__file__

1
2
3
>>> import random
>>> random.__file__
'/usr/lib/python3.4/random.py'

反射
有一种说法叫反射
1 以字符串的形式导入模块
2 以字符串的形式调用函数

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
root@apt:~# cat /usr/local/lib/python2.7/dist-packages/pkg/mysql.py
#!/usr/bin/python2.7
def count():
return 3306
root@apt:~#
In [1]: var = 'pkg.mysql'
In [2]: mode = __import__(var)
In [3]: mode.mysql.count()
Out[3]: 3306
In [4]: func = 'count'
In [5]: Func = getattr(mode.mysql, func)
In [6]: Func()
Out[6]: 3306

模块os

More info 详情

模块sys

利用sys模块模拟#滚动条

1
2
3
4
5
6
7
8
import sys,time

In [111]: for i in range(50):
.....: sys.stdout.write("\033[32;1m#\033[0m")
.....: sys.stdout.flush()
.....: time.sleep(0.05)
.....:
##################################################

time模块

random模块

博客参考

几个有用的方法

1
2
3
4
import  random
print(random.randint(1,10)) # 取1-9
print(random.randrange(1,20,2)) # 步长为2,意味着取奇数
print(random.sample([1,2,3,4,5,6,7,8],3)) # 取一个3个元素的列表[3, 6, 1]

生成随机码(一)

1
2
3
4
5
6
7
8
9
checkcode = ''
for i in range(4):
current=random.randrange(0,4)
if current != i:
tmp = chr(random.randint(65,90))
else:
tmp = random.randint(0,9)
checkcode += str(tmp)
print(checkcode)

生成随机码(二)

1
2
3
4
import string
# print(string.ascii_uppercase + string.ascii_lowercase+string.digits)
source = string.ascii_uppercase + string.ascii_lowercase+string.digits
print("".join(random.sample(source,4)))

pickle模块

pickle只是python支持,那么可以序列化python内所有数据类型

在程序运行的过程中,所有的变量都是在内存中,过程中可能改变变量,程序结束,内存变量回收。此时如果没有把修改过的变量存到磁盘上,下次程序运行又是最初的变量,怎么解决这个问题,序列化就派上用场了。

序列化: 把内存中的变量变成可存储可传输的过程称为序列化,pickling
反序列化:把变量从序列化对象重新读入内存称为反序列化,unpickling

pickle.dump() 序列化入文件
pickle.dumps() 序列化为字符串,可赋值
pickle.load() 从文件加载
pickle.loads() 从字符串加载

1
2
3
4
5
6
7
8
9
10
11
In [27]: import pickle
In [29]: my_list
Out[29]: [0, 2, 4, 6, 8, 10]

In [30]: pickle_file = open('/root/my_list.pkl', 'wb') # 打开一个文件
In [31]: pickle.dump(my_list, pickle_file) # 序列化入这个文件
In [32]: pickle_file.close()

In [33]: pickle_file = open('/root/my_list.pkl', 'rb') # 打开文件
In [34]: pickle.load(pickle_file) # 从一个文件加载回来
Out[34]: [0, 2, 4, 6, 8, 10]
1
2
3
4
5
6
7
8
9
10
11
12
13
In [36]: import pickle
In [37]: list1 = ['wxq', 11, 22,'good']

In [38]: dumpsed = pickle.dumps(list1)
In [39]: type(dumpsed)
Out[39]: builtins.bytes

In [40]: loadsed = pickle.loads(dumpsed)
In [41]: loadsed
Out[41]: ['wxq', 11, 22, 'good']

In [42]: type(loadsed)
Out[42]: builtins.list

json模块

json是各语言通用的序列化数据交换格式,只支持序列化数据类型:str int float set dict list tuple

JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输,并且可以直接在Web页面中读取,这也是为什么json这么通用的原因。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import json
# d={"user":"wxq"}
#
# json_s=(json.dumps(d)) # 这里d是什么不管,json.dumps后是把d 序列化为符合json标准(只支持双引号)的字符串
# json.loads(json_s) # json_s必须符合json双引号标准才能反序列化
#
# json.loads("{'user':'wxq'}") # 这里虽然是字符串,但里面是单引号,不符合json标准,会报错的

json_s=json.dumps({'user':'wxq'})
# 可以看到这里传入的不是标准的(双引号),但json_dumps后成为字符串{"user": "wxq"},是符合json标准(只支持双引号)的字符串。

in javascript
JSON.stringfy() # 序列化
JSON.parse() # 反序列化

logging模块

python的logging模块提供了标准的日志接口,我们来看一下简单用法

1
2
3
4
5
6
7
8
9
10
11
12
root@apt:/tmp# cat log.py 
#!/usr/bin/env python3

import logging
#日志级别: DEGUG INFO WARNING ERROR CRITICAL
#数字表示分别为 10 20 30 40 50

logging.warning("warning message")
logging.error("error message")
root@apt:/tmp# python3 log.py
WARNING:root:warning message
ERROR:root:error message

上面的日志是直接输出,怎么才能让应用程序日志写入文件呢? 也很简单
定义一个log.py的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
root@apt:/tmp# cat log.py 
#!/usr/bin/env python3

import logging
#日志级别: DEGUG INFO WARNING ERROR CRITICAL
#数字表示分别为 10 20 30 40 50

log_file = 'example.log'
logging.basicConfig(filename=log_file,level=logging.INFO)
logging.debug('program debug message ...')
logging.info('info message')
logging.warning("warning message")
logging.error("error message")

运行一下log.py文件

1
2
3
4
5
root@apt:/tmp# python3 log.py
root@apt:/tmp# cat example.log
INFO:root:info message
WARNING:root:warning message
ERROR:root:error message

我们注意到logging.debug信息并没有写入,为什么呢?因为level=logging.INFO定义要写入日志的日志级别,只有达到定义的日志级别才会记录。

但是发现记录的日志太丑了,怎么样才能让打印的日志人性化呢,就需要格式化输出。

格式 说明
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2017-02-01 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s 用户输出的消息

如果想同时把log打印在屏幕和文件日志里,或者有日志切割的需求,可能要复杂些

  • logger提供了应用程序可以直接使用的接口;
  • handler将(logger创建的)日志记录发什么方式输出,是屏幕还是文件,或二都都要;
  • filter提供了细度过滤来决定哪些日志不要输出,如密码敏感信息;
  • formatter决定日志记录的最终输出格式。

logger工作原理图
logger工作原理图

屏幕和文件都输出

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
import logging

#create logger
logger = logging.getLogger('TEST-LOG')
logger.setLevel(logging.DEBUG)

# create console handler and set level to debug
sh = logging.StreamHandler()
sh.setLevel(logging.DEBUG)

# create file handler and set level to warning
fh = logging.FileHandler("access.log")
fh.setLevel(logging.WARNING)
# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# add formatter to sh and fh
sh.setFormatter(formatter)
fh.setFormatter(formatter)

# add ch and fh to logger
logger.addHandler(sh)
logger.addHandler(fh)

# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

日志切割
handlers.RotatingFileHandler:按文件大小切割
handlers.TimedRotatingFileHandler: 按时间切割

示例1:

1
大小切割略

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import logging
from logging import handler
logger = logging.getLogger(__name__)

log_file = "timelog.log"
#fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3)
fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3)

formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)

logger.warning("test1")
logger.warning("test12")
logger.warning("test13")
logger.warning("test14")

模块paramiko

1
2
3
4
5
6
7
8
9
`pycrypto-2.6.1.tar.gz`# 下载安装
apt-get install python-dev
python setup.py build
python setup.py install
import Crypto
`paramiko-1.10.1.tar.gz` 下载安装
python setup.py build
python setup.py install
import paramiko

模块configparser

生成如下example.ini 文件,该如何做呢

1
2
3
4
5
6
7
8
9
10
11
12
13
root@ubuntu:~# cat example.ini
[DEFAULT]
compression = yes
serveraliveinterval = 45
compressionlevel = 9
forwardx11 = yes

[bitbucket.org]
user = wxq

[topsecret.server.com]
host port = 5000
forwardx11 = no

编写如下脚本执行 python3 create_example.py即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root@ubuntu:~# cat create_example.py 
#!/usr/bin/env python3
#
import configparser

config = configparser.ConfigParser()
config["DEFAULT"] = {'ServerAliveInterval': '45',
'Compression': 'yes',
'CompressionLevel': '9'}

config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'wxq'
config['topsecret.server.com'] = {}
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = '5000' # mutates the parser
topsecret['Forwardx11'] = 'no' # same here
config['DEFAULT']['Forwardx11'] = 'yes'
with open('example.ini', 'w') as configfile:
config.write(configfile)

那么有了example.ini 这样的文件,如何读取呢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
>>> import configparser   # 导入模块
>>> config = configparser.ConfigParser() # 类实例化
>>> config.sections() # 调用类中一个方法
[]
>>> config.read('example.ini') # 文件读入
['example.ini']
>>> config.sections() # 除了[DEFAULT]还有哪些区块,列表呈现
['bitbucket.org', 'topsecret.server.com']
>>> 'bitbucket.org' in config
True
>>> config['bitbucket.org']['user'] # 指定区块指定字典键对应值
'wxq'
>>> config['DEFAULT']['compression']
'yes'
>>> for i in config['bitbucket.org']: # 指定区块打印键
... print(i) # 注意:包括[DEFAULT]区块的键也在这里呈现
...
user
compression
serveraliveinterval
compressionlevel
forwardx11

1
2
3
4
5
6
7
8
9
>>> d1 = config['bitbucket.org']  # 指定区块读出其实是一个字典
>>> for k,v in d1.items():
... print("%s = %s" % (k,v))
...
user = wxq
compression = yes
serveraliveinterval = 45
compressionlevel = 9
forwardx11 = yes
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
root@ubuntu:~# cat wxq.txt   # 有这么一个文件
[section1]
k1 = v1
k2: v2

[section2]
k1 = v111
>>> import configparser
>>> config = configparser.ConfigParser()
>>> config.read('/root/wxq.txt') # 读入这样的文件
['/root/wxq.txt']
>>> config.sections() # 查看这个文件的区块
['section1', 'section2']
>>> config.items('section1') # 查看指定区块的键值对
[('k1', 'v1'), ('k2', 'v2')]

>>> config.options('section1') # 只显示指定区块的键
['k1', 'k2']
>>> config.has_section('section3') # 判断某区块是否存在返回True/False
False
>>> config.add_section('section3') # 添加一个区块
>>> config.has_section('section3') # 有了这个区块
True
>>> config.set('section3', 'k1', 'v1') # 添加一行配置,也就是设置一个区块的键值对
>>> config.write(open('wxq', 'w'))
1
2
3
4
5
6
7
8
9
10
root@ubuntu:~# cat wxq   # 按照上面的写入会生成了一个新文件
[section1]
k1 = v1
k2 = v2

[section2]
k1 = v111

[section3]
k1 = v1
1
2
3
4
5
6
>>> config.remove_option('section3', 'k1')  # 删除某键值对
True
>>> config.write(open('wxq.txt', 'w'))
>>> config.remove_section('section3') # 删除某区块
True
>>> config.write(open('wxq.txt', 'w'))

模块MySQLdb

python连接数据库操作

  • 建立数据库连接
  • 创建游标cursor(用于发送sql语句,获取sql结果,解析返回结果)
  • 关闭游标cursor curname.close()
  • 关闭数据库连接 conname.close()

模块安装
apt-get install python-mysqldb
查看模块
help(‘modules’)
加载数据库模块
import MySQLdb as mysql

创建连接,会生成一个con.cursor()的类
con = mysql.connect(host=’127.0.0.1’,user=’root’,passwd=’dbpass’)

游标类实例化
cur = con.cursor()

cur.execute 传入一个参数执行sql语句
cur.executemany 传入多个参数执行sql语句

cur.fetchall 查询执行后的结果返回所有
cur.fetchmany查询执行后的结果返回多个
cur.fetchone 查询执行后的结果返回一个
游标回滚
help(cur.scroll)
scroll(self, value, mode=’relative’)

cur.scroll(0,mode=’absolute’)

hashlib模块

用于加密相关操作,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法

1
2
3
4
5
6
7
8
9
import hashlib
str = hashlib.sha1(b'admin123') # python3中必须bytes格式
str.hexdigest()
'f865b53623b121fd34ee5426c792e5c33af8c227'

str = hashlib.md5(b'admin123')

str.hexdigest()
'0192023a7bbd73250516f069df18b500'

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
import hashlib

m = hashlib.md5()
m.update(b"Hello")
m.update(b"It's me")
print(m.digest())
m.update(b"It's been a long time since last time we ...")

print(m.digest()) #2进制格式hash
print(len(m.hexdigest())) #16进制格式hash
'''
def digest(self, *args, **kwargs): # real signature unknown
""" Return the digest value as a string of binary data. """
pass

def hexdigest(self, *args, **kwargs): # real signature unknown
""" Return the digest value as a string of hexadecimal digits. """
pass

'''
import hashlib

# ######## md5 ########
hash = hashlib.md5()
hash.update(b'admin')
print(hash.hexdigest())

# ######## sha1 ########
hash = hashlib.sha1()
hash.update(b'admin')
print(hash.hexdigest())

# ######## sha256 ########
hash = hashlib.sha256()
hash.update(b'admin')
print(hash.hexdigest())

# ######## sha384 ########
hash = hashlib.sha384()
hash.update(b'admin')
print(hash.hexdigest())

# ######## sha512 ########
hash = hashlib.sha512()
hash.update(b'admin')
print(hash.hexdigest())

python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 再进行处理然后再加密

1
2
3
4
import hmac
h = hmac.new(b'wxq')
h.update(b'hi')
print(h.hexdigest())

来个实用例子:
注意:bytes只接收ascii的值,字符串为unicode,需转为ascii样的值,比如utf-8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
root@wxq:~# cat md5.py 
#!/usr/bin/env python3
import hashlib
import time

def create_md5():
m = hashlib.md5()
m.update(bytes(str(time.time()),encoding='utf-8'))
return m.hexdigest()

res = create_md5()
print(res)

root@wxq:~# python3 md5.py
ebd8a4dd680e2e29b1a44b27b2bdd2f7
root@wxq:~# python3 md5.py
4e178ffe5eaa58584434d3b519708638

更多关于md5,sha1,sha256等介绍的文章.看这里

模块uuid

直接来个例子:

1
2
3
4
5
6
7
8
9
10
root@wxq:~# cat create_uuid.py 
#!/usr/bin/env python3
import uuid
def create_uuid():
return (str(uuid.uuid1()))

res = create_uuid()
print(res)
root@wxq:~# python3 create_uuid.py
2cad772c-fe7d-11e6-b3db-3a71234db8d2

模块md5

1
2
3
4
5
6
7
8
9
10
11
12
13
#password=form.cleaned_data['password']
from utils import md5
form.cleaned_data['password']=md5(form.cleaned_data['password'])
app01/utils/md.py
import hashlib
def md5(text):
m = hashlib.md5()
m.update(text.encode('utf-8')) # python3接收bytes格式,encode后就是bytes
return m.hexdigest()

if __name__ == '__main__':
text='123'
return md5(text)

update可以执行多次,效果一样

1
2
3
m.update(b"hello ")
m.update(b"world")
等同于m.update(b"hello world")

模块

模块

模块