python知识小结(2)

来源:互联网 发布:mysql truncate函数 编辑:程序博客网 时间:2024/06/03 17:08

StringIO和BytesIO

StringIO

很多时候,数据读写不一定是文件,也可以在内存中读写。

StringIO顾名思义就是在内存中读写str。

要把str写入StringIO,我们需要先创建一个StringIO,然后,像文件一样写入即可:

>>> from io import StringIO>>> f = StringIO()>>> f.write('hello')5   # 返回的是写入的字符串的长度>>> f.write(' ')1>>> f.write('world!')6>>> print(f.getvalue())hello world!getvalue()方法用于获得写入后的str。要读取StringIO,可以用一个str初始化StringIO,然后,像读文件一样读取:>>> from io import StringIO>>> f = StringIO('Hello!\nHi!\nGoodbye!')>>> while True:...     s = f.readline()   # 按照行的形式 从内存中读取数据...     if s == '':...         break...     print(s.strip())...Hello!Hi!Goodbye!

BytesIO

BytesIO

StringIO操作的只能是str,如果要操作二进制数据,就需要使用BytesIO。

BytesIO实现了在内存中读写bytes,我们创建一个BytesIO,然后写入一些bytes:

>>> from io import BytesIO>>> f = BytesIO()>>> f.write('中文'.encode('utf-8'))6>>> print(f.getvalue())b'\xe4\xb8\xad\xe6\x96\x87'请注意,写入的不是str,而是经过UTF-8编码的bytes。和StringIO类似,可以用一个bytes初始化BytesIO,然后,像读文件一样读取:>>> from io import BytesIO>>> f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')>>> f.read()b'\xe4\xb8\xad\xe6\x96\x87'

通过 os 来获取环境变量中的值
os.environ.get(key, default) 从环境变量中获取到需要的值, 如果没有这个值, 就返回 设定的默认的值

使用 os.path 来操作文件的目录

os.path.abspath() 获取项目下的绝对的路径

os.path.split(文件的名称) 返回的结果是一个 列表 列表中的 元素是 文件的名称 和 文件的后缀名称

第一个使用的是 os.path.split()os.path.split(os.path.join(os.path.abspath(''), "1111.txt"))返回的内容: ('D:\\test\\练习', '1111.txt')第二个使用的是 os.path.splitext()   返回的是文件的名称和后缀os.path.splitext(os.path.join(os.path.abspath(''), "1111.txt"))返回的内容: ('D:\\test\\练习\\1111', '.txt')这些合并、拆分路径的函数并不要求目录和文件要真实存在,它们只对字符串进行操作。# 对文件重命名:>>> os.rename('test.txt', 'test.py')# 删掉文件:>>> os.remove('test.py')

copyfile() 函数的使用

幸运的是shutil模块提供了copyfile()的函数,你还可以在shutil模块中找到很多实用函数,它们可以看做是os模块的补充

一行代码搞定当前目录下的所有的文件夹

os.list.dir()  # 获取到当前目录下面的所有的文件和文件夹>>> [x for x in os.listdir('.') if os.path.isdir(x)]['.lein', '.local', '.m2', '.npm', '.ssh', '.Trash', '.vim', 'Applications', 'Desktop', ...]列出当前文件下面所有的采用的是以指定文件后缀结尾的文件>>> [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']['apis.py', 'config.py', 'models.py', 'pymonitor.py', 'test_db.py', 'urls.py', 'wsgiapp.py']

序列化的操作

pickle

pickle 序列化后的操作 只能使用Python 语言进行使用

>>> import pickle>>> d = dict(name='Bob', age=20, score=88)>>> pickle.dumps(d)b'\x80\x03}q\x00(X\x03\x00\x00\x00ageq\x01K\x14X\x05\x00\x00\x00scoreq\x02KXX\x04\x00\x00\x00nameq\x03X\x03\x00\x00\x00Bobq\x04u.'pickle.dumps()方法把任意对象序列化成一个bytes,然后,就可以把这个bytes写入文件。或者用另一个方法pickle.dump()直接把对象序列化后写入一个file-like Object:和json的 功能是一样的 但是就是 json 是通用的 但是 pickle  只能Python 语言 才能进行使用Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。

json 序列化的 进阶操作 使用json 序列化一个对象

使用 json 序列化一个类的对象

import jsonclass Student(object):    def __init__(self, name, age, score):        self.name = name        self.age = age        self.score = scores = Student('Bob', 20, 88)print(json.dumps(s))这样直接的进行序列化的时候 是会出现错误的Traceback (most recent call last):  ...TypeError: <__main__.Student object at 0x10603cc50> is not JSON serializablejson中的 可选参数default 可以传入一个函数 来先把累对象 转换成一个 字典可选参数default就是把任意一个对象变成一个可序列为JSON的对象,我们只需要为Student专门写一个转换函数,再把函数传进去即可:def student2dict(std):    return {        'name': std.name,        'age': std.age,        'score': std.score    }这样,Student实例首先被student2dict()函数转换成dict,然后再被顺利序列化为JSON:>>> print(json.dumps(s, default=student2dict)){"age": 20, "name": "Bob", "score": 88}不过,下次如果遇到一个Teacher类的实例,照样无法序列化为JSON。我们可以偷个懒,把任意class的实例变为dictprint(json.dumps(s, default=lambda obj: obj.__dict__))因为通常class的实例都有一个__dict__属性,它就是一个dict,用来存储实例变量。也有少数例外,比如定义了__slots__class同样的道理,如果我们要把JSON反序列化为一个Student对象实例,loads()方法首先转换出一个dict对象,然后,我们传入的object_hook函数负责把dict转换为Student实例:def dict2student(d):    return Student(d['name'], d['age'], d['score'])运行结果如下:>>> json_str = '{"age": 20, "score": 88, "name": "Bob"}'>>> print(json.loads(json_str, object_hook=dict2student))<__main__.Student object at 0x10cd3c190>打印出的是反序列化的Student实例对象。使用json 序列化一个日期的的对象  明天记得完成

dict_ 可以把类中的对象的属性转换成一个字典的形式

class Student():    def __init__(self, name, age, gender):        self.name = name        self.age = age        self.gender = genderdemo = Student("xixi", 20, 1).__dict__print(type(demo))print(demo)输出结果:    <class 'dict'>    {'name': 'xixi', 'age': 20, 'gender': 1}

使用 subprocess 来创建子进程

一、subprocess以及常用的封装函数

运行python的时候,我们都是在创建并运行一个进程。像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序。在Python中,我们通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。

subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所以我们可以根据需要来从中选取一个使用。另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。

subprocess.call()

父进程等待子进程完成
返回退出信息(returncode,相当于Linux exit code)

subprocess.check_call()

父进程等待子进程完成
返回0
检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属性,可用try…except…来检查

多线程下 使用 lock 的

当多个程序同时修改一个数据的时候 就需要用到锁的概念,

使用 lock = threading.lock() 创建一个锁的对象
获取锁的对象采用的是 lock.acquire() 释放锁 采用的是 lock.release()

常用模块

  1. datetime 模块
  2. 2.
获取当前的时间>> from datetime import datetime>>> datetime.now()datetime.datetime(2017, 10, 12, 16, 36, 45, 179103)>>> now = datetime.now()>>> print(now)2017-10-12 16:36:59.643930>>> type(now)<class 'datetime.datetime'>设定指定的时间>>> time = datetime(2017, 10, 12, 16, 40)>>> print(time)2017-10-12 16:40:00
  1. datetime转换为timestamp
    3.
>>> now.timestamp()1507797419.64393把timestamp 转换会 datetime的方法now = datetime.fromtimestamp(t)要把timestamp转换为datetime,使用datetime提供的fromtimestamp()方法:>>> from datetime import datetime>>> t = 1429417200.0>>> print(datetime.fromtimestamp(t))2015-04-19 12:20:00注意到timestamp是一个浮点数,它没有时区的概念,而datetime是有时区的。上述转换是在timestamp和本地时间做转换。本地时间是指当前操作系统设定的时区。例如北京时区是东8区,则本地时间:2015-04-19 12:20:00实际上就是UTC+8:00时区的时间:2015-04-19 12:20:00 UTC+8:00而此刻的格林威治标准时间与北京时间差了8小时,也就是UTC+0:00时区的时间应该是:2015-04-19 04:20:00 UTC+0:00timestamp也可以直接被转换到UTC标准时区的时间:>>> from datetime import datetime>>> t = 1429417200.0>>> print(datetime.fromtimestamp(t)) # 本地时间2015-04-19 12:20:00>>> print(datetime.utcfromtimestamp(t)) # UTC时间2015-04-19 04:20:00

字符串和 时间的转换

str转换为datetime

很多时候,用户输入的日期和时间是字符串,要处理日期和时间,首先必须把str转换为datetime。转换方法是通过datetime.strptime()实现,需要一个日期和时间的格式化字符串:

datetime.strptime(string, "%Y-%m-%d-%H")  >>> from datetime import datetime>>> cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')>>> print(cday)2015-06-01 18:19:59

字符串’%Y-%m-%d %H:%M:%S’规定了日期和时间部分的格式

把datetime.now() 转换成str 字符串的方法

>>> now.strftime("%Y-%m-%d %H:%M:%S")'2017-10-12 16:36:59'

datetime 的加减操作

对日期和时间进行加减实际上就是把datetime往后或往前计算,得到新的datetime。加减可以直接用+和-运算符,不过需要导入timedelta这个类:

>>> from datetime import datetime, timedelta>>> now = datetime.now()>>> nowdatetime.datetime(2015, 5, 18, 16, 57, 3, 540997)>>> now + timedelta(hours=10)datetime.datetime(2015, 5, 19, 2, 57, 3, 540997)>>> now - timedelta(days=1)datetime.datetime(2015, 5, 17, 16, 57, 3, 540997)>>> now + timedelta(days=2, hours=12)datetime.datetime(2015, 5, 21, 4, 57, 3, 540997)

小结

datetime表示的时间需要时区信息才能确定一个特定的时间,否则只能视为本地时间。

如果要存储datetime,最佳方法是将其转换为timestamp再存储,因为timestamp的值与时区完全无关。

collections的使用

  1. 使用namedtuple创建一个指定属性的元组
>>> from collections import namedtuple>>> point = namedtuple("point", ['x', 'y'])>>> p = point(1, 2)>>> p.x1>>> p.y2>>> ppoint(x=1, y=2)同时满足这两种的实例>>> isinstance(p, point)True>>> isinstance(p, tuple)Truenamedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素。这样一来,我们用namedtuple可以很方便地定义一种数据类型,它具备tuple的不变性,又可以根据属性来引用,使用十分方便。可以验证创建的Point对象是tuple的一种子类:
  1. 使用deque 来构建 双向的列表 list
    使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。

deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:

>>> q = deque(['a', 'b', 'c'])>>> qdeque(['a', 'b', 'c'])>>> q.append('d')>>> qdeque(['a', 'b', 'c', 'd'])>>> q.append(1)>>> qdeque(['a', 'b', 'c', 'd', 1])>>> q.appendleft(2)>>> qdeque([2, 'a', 'b', 'c', 'd', 1])从左右边删除  但是里面不能带参数  list中的pop 是可以携带参数的 代表的是要删除那个索引下的元素>>> q.pop()1>>> q.popleft()2
  1. defaultdict
    可以作为字典来使用, 当获取到的key 不存在的时候 返回一个默认的值 给 字典中的键统一的设定

defaultdict类的初始化函数接受一个类型作为参数,当所访问的键不存在的时候,可以实例化一个值作为

>>> dd1 = defaultdict(list)>>> dd1["key"][]>>> dd1["key1"] = 2>>> dd1["key1"]2

defaultdict类除了接受类型名称作为初始化函数的参数之外,还可以使用任何不带参数的可调用函数,到时该函数的返回结果作为默认值

>>> dd = defaultdict(lambda:' ')>>> dd["key"]''

注意默认值是调用函数返回的,而函数在创建defaultdict对象时传入。

除了在Key不存在时返回默认值,defaultdict的其他行为跟dict是完全一样的。

在参数中使用 * 或者 ** 是为了让这个指定的变量 进行解包操作

  1. Orderdict 实现一个有序的字典的方式
>>> from collections import OrderedDict>>> d = dict([('a', 1), ('b', 2), ('c', 3)])>>> d # dict的Key是无序的{'a': 1, 'c': 3, 'b': 2}>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])>>> od # OrderedDict的Key是有序的OrderedDict([('a', 1), ('b', 2), ('c', 3)])注意,OrderedDict的Key会按照插入的顺序排列,不是Key本身排序:其他的操作和 普通的字典是没有什么区别的
  1. counter 计数器的使用

使用counter 可以完成 统计一个列表中出现重复的次数
from collections import Counter
c = Counter(sequence) 传入的是一个序列对象 可迭代的对象
c.most_common(n) 传入的参数是一个 整型, 是要获取到 前几个数据

源码中的一些简单实例:

 '''Dict subclass for counting hashable items.  Sometimes called a bag    or multiset.  Elements are stored as dictionary keys and their counts    are stored as dictionary values.    >>> c = Counter('abcdeabcdabcaba')  # count elements from a string    >>> c.most_common(3)                # three most common elements    [('a', 5), ('b', 4), ('c', 3)]    >>> sorted(c)                       # list all unique elements    ['a', 'b', 'c', 'd', 'e']    >>> ''.join(sorted(c.elements()))   # list elements with repetitions    'aaaaabbbbcccdde'    >>> sum(c.values())                 # total of all counts    15    >>> c['a']                          # count of letter 'a'    5    >>> for elem in 'shazam':           # update counts from an iterable    ...     c[elem] += 1                # by adding 1 to each element's count    >>> c['a']                          # now there are seven 'a'    7    >>> del c['b']                      # remove all 'b'    >>> c['b']                          # now there are zero 'b'    0    >>> d = Counter('simsalabim')       # make another counter    >>> c.update(d)                     # add in the second counter    >>> c['a']                          # now there are nine 'a'    9    >>> c.clear()                       # empty the counter    >>> c    Counter()    Note:  If a count is set to zero or reduced to zero, it will remain    in the counter until the entry is deleted or the counter is cleared:    >>> c = Counter('aaabbc')    >>> c['b'] -= 2                     # reduce the count of 'b' by two    >>> c.most_common()                 # 'b' is still in, but its count is zero    [('a', 3), ('c', 1), ('b', 0)]

struct 模块的使用

Python提供了一个struct模块来解决bytes和其他二进制数据类型的转换。

struct的pack函数把任意数据类型变成bytes:

hashlib 加密的使用

在python的时候 需要把 加密的数据转换成字节的形式 才能都进行加密

如果是 英文的 可以直接使用 b”nihao ’ 把字符串转换成 byte 类型的

如果是中文的 需要经过编码来进行解决 ‘你好’.encode(‘utf-8’)

import hashlibmd5 = hashlib.md5()md5.update('how to use md5 in python hashlib?'.encode('utf-8'))print(md5.hexdigest())

如果要加密的字节很长还可以, 分段进行加密操作, 例如:

import hashlibmd5 = hashlib.md5()md5.update('how to use md5 in '.encode('utf-8'))md5.update('python hashlib?'.encode('utf-8'))print(md5.hexdigest())MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。

sha1的使用
使用方法 和md5 是一样的 但是生成的是一个 40为的16进制的字符串来表示的

import hashlibsha1 = hashlib.sha1()sha1.update('how to use sha1 in '.encode('utf-8'))sha1.update('python hashlib?'.encode('utf-8'))print(sha1.hexdigest())

因为 md5 可能会被反推出来 , 存在一定的安全的隐患, 推荐的是使用 加密和 加盐的操作 来进行处理
就是在 进行加密的时候 加入一个字符串, 只要这个字符串不被外泄, 别人就很难破解你的密码

import hashlibmd5 = hashlib.md5()md5.update('how to use md5 in '.encode('utf-8'))md5.update('python hashlib?'.encode('utf-8'))print(md5.hexdigest())md5 = hashlib.md5()>>> def main(string):...     md5.update((string + "hehe").encode("utf-8"))...     print(md5.hexdigest())

itertools 模块的使用

Python的内建模块itertools提供了非常有用的用于操作迭代对象的函数。
1. 无限次的重复

>>> import itertools>>> natuals = itertools.count(1)>>> for n in natuals:...     print(n)...123...因为count()会创建一个无限的迭代器,所以上述代码会打印出自然数序列
  1. 无限次的重复
    cycle()会把传入的一个序列无限重复下去:请注意 这里是一个序列
>>> import itertools>>> cs = itertools.cycle('ABC') # 注意字符串也是序列的一种>>> for c in cs:...     print(c)...'A''B''C''A''B''C'...
  1. repeat()负责把一个元素无限重复下去,不过如果提供第二个参数就可以限定重复次数:
>>> ns = itertools.repeat('A', 3)>>> for n in ns:...     print(n)...AAA

无限序列只有在for迭代时才会无限地迭代下去,如果只是创建了一个迭代对象,它不会事先把无限个元素生成出来,事实上也不可能在内存中创建无限多个元素。

无限序列虽然可以无限迭代下去,但是通常我们会通过takewhile()等函数根据条件判断来截取出一个有限的序列:

>>> natuals = itertools.count(1)>>> ns = itertools.takewhile(lambda x:x<=10, natuals)>>> list(ns)[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

chain()

chain()可以把一组迭代对象串联起来,形成一个更大的迭代器:

>>> for c in itertools.chain('ABC', 'XYZ'):...     print(c)# 迭代效果:'A' 'B' 'C' 'X' 'Y' 'Z'

groupby()

groupby()把迭代器中相邻的重复元素挑出来放在一起:>>> for key, group in itertools.groupby('AAABBBCCAAA'):...     print(key, list(group))...A ['A', 'A', 'A']B ['B', 'B', 'B']C ['C', 'C']A ['A', 'A', 'A']

实际上挑选规则是通过函数完成的,只要作用于函数的两个元素返回的值相等,这两个元素就被认为是在一组的,而函数返回值作为组的key。如果我们要忽略大小写分组,就可以让元素’A’和’a’都返回相同的key:

>>> for key, group in itertools.groupby('AaaBBbcCAAa', lambda c: c.upper()):...     print(key, list(group))...A ['A', 'a', 'a']B ['B', 'B', 'b']C ['c', 'C']A ['A', 'A', 'a']
原创粉丝点击