Python3中的json模块使用详解


Posted in Python onMay 05, 2018

1. 概述

JSON (JavaScript Object Notation)是一种使用广泛的轻量数据格式. Python标准库中的json模块提供了JSON数据的处理功能.

Python中一种非常常用的基本数据结构就是字典(Dictionary). 它的典型结构如下:

d = {
'a': 123,
'b': {
'x': ['A', 'B', 'C']
}
}

而JSON的结构如下:

{
"a": 123,
"b": {
"x": ["A", "B", "C"]
}
}

可以看到, Dictionary和JSON非常接近, 而Python中的json库提供的主要功能, 也是两者之间的转换.

2. 读取JSON

json.loads方法可以将包含了一个JSON数据的str, bytes或者bytearray对象, 转化为一个Python Dictionary. 它的完型接口签名如下:

json.loads(s, *, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)

2.1 最简单的例子

json.loads最基本的使用方式就是将一个包含JSON数据的str传递给这个方法:

>>> json.loads('{"a": 123}')
{'a': 123}

注意

在Python中, str值可以放在一对单引号中, 也可以放在一对双引号中:

>>> 'ABC' == "ABC"
True

所以, 在定义Dictionary的str类型的键和值的时候, 使用单引号或者双引号都是合法和等价的:

>>> {"a": 'ABC'} == {'a': "ABC"}
True

但是, 在JSON中, 字符串数据只能放在双引号中, 因而json.loads方法处理的字符串的JSON内容中, 字符串必须使用双引号. 否则就会发生解码错误:

>>> json.loads("{'a': 123}")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 354, in loads
return _default_decoder.decode(s)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/decoder.py", line 339, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/decoder.py", line 355, in raw_decode
obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

如果被处理的Python字符串是包含在双引号中的, 那么JSON中的双引号就需要转义:

>>> json.loads("{\"a\": 123}")
{'a': 123}

2.2 bytes和bytearray数据

对于内容是JSON数据的bytes和bytearray, json.loads方法也可以处理:

>>> json.loads('{"a": 123}'.encode('UTF-8'))
{'a': 123}
>>> json.loads(bytearray('{"a": 123}', 'UTF-8'))
{'a': 123}

2.3 编码格式

json.loads的第二个参数是encoding没有实际作用.

由于Python 3中str类型总是使用UTF-8编码, 所以s参数为str类型时, json.loads方法自动使用UTF-8编码. 并且, str不能以BOM字节开头.

当s参数为bytes或者bytearray时, json.loads方法会自动判断为UTF-8, UTF-16还是UTF-32编码. 默认也是将其按照UTF-8编码转化为str对象进行后续处理.

2.4 数据类型转换

JSON可以表示四种主类型数据

  • 1.字符串 string
  • 2.数字 number
  • 3.布尔类 boolean
  • 4.空值 null

以及两结数据结构

  • 1.对象 object
  • 2.数组 array

默认实现中, JSON和Python之间的数据转换对应关系如下表:

JSON Python
object dict
array list
string str
number (int) int
number (real) float
true True
false False
null None

实际转换情况如下例:

>>> json.loads("""
... {
... "obj": {
... "str": "ABC",
... "int": 123,
... "float": -321.89,
... "bool_true": true,
... "bool_false": false,
... "null": null,
... "array": [1, 2, 3]
... }
... }""")
{'obj': {'str': 'ABC', 'int': 123, 'float': -321.89, 'bool_true': True, 'bool_false': False, 'null': None, 'array': [1, 2, 3]}}

对于JSON中数字number类型的数据, 有以下几点需要注意:

1.JSON中的实数real number类型的精度不能超过Python中的float类型的精度范围, 否则就有精度损失. 如下例:

>>> json.loads('3.141592653589793238462643383279')
3.141592653589793

2.JSON标准不包括非数字NaN, 正无穷Infinity和负无穷-Infinity, 但是json.loads方法默认会将JSON字符串中的NaN, Infinity, -Infinity转化为Python中的float('nan'), float('inf')和float('-inf'). 注意, 这里JSON中的NaN, Infinity, -Infinity必须大小写正确并且拼写完整. 如下例

>>> json.loads('{"inf": Infinity, "nan": NaN, "ninf": -Infinity}')
{'inf': inf, 'nan': nan, 'ninf': -inf}

2.5 自定义JSON对象转换类型

json.loads默认将JSON中的对象数据转化为Dictionary类型, object_hook参数可以用来改变构造出的对象.

object_hook接受一个函数, 这个函数的输入参数为JSON中对象数据转化出的Dictionary对象, 其返回值则为自定义的对象. 如下例所示:

>>> class MyJSONObj:
... def __init__(self, x):
... self.x = x
...
>>> def my_json_obj_hook(data):
... print('obj_hook data: %s' % data)
... return MyJSONObj(data['x'])
...
>>> result = json.loads('{"x": 123}', object_hook=my_json_obj_hook)
obj_hook data: {'x': 123}
>>> type(result)
<class '__main__.MyJSONObj'>
>>> result.x
123

当JSON中的对象有嵌套时, json.loads方法会按照深度优先的方式遍历对象树, 将各层的对象数据传递给object_hook. 叶节点的JSON对象构造出的Python对象, 会作为父节点的一个值, 传递给父节点的object_hook方法. 如下例:

>>> class MyJSONObj:
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
>>> def my_json_obj_hook(data):
... print('obj_hook data: %s' % data)
... return MyJSONObj(**data)
...
>>> result = json.loads('{"x": {"x": 11, "y": 12}, "y": {"x": 21, "y":22}}', object_hook=my_json_obj_hook)
obj_hook data: {'x': 11, 'y': 12}
obj_hook data: {'x': 21, 'y': 22}
obj_hook data: {'x': <__main__.MyJSONObj object at 0x10417ef28>, 'y': <__main__.MyJSONObj object at 0x10417ed68>}

除了object_hook参数以外, 还有一个object_pairs_hook参数. 这个参数同样可以用来改变json.loads方法构造出的Python对象的类型. 这个参数和object_hook的不同, 在于传入的方法所接收到的输入数据不是一个Dictionary, 而是一个包含tuple的list. 每个tuple都有两个元素, 第一个元素是JSON数据中的键, 第二个元素是这个键对应的值. 如JSON对象

{
"a": 123,
"b": "ABC"
}

对应的输入数据是

[
('a': 123),
('b', 'ABC')
]

当调用json.loads方法时, 同时指定object_hook和object_pairs_hook, object_pairs_hook会覆盖object_hook参数.

2.6 自定义JSON数字转换类型

默认实现中, JSON中的实数被转换为Python的float类型, 整数被转换为int或者long类型. 类似object_hook, 我们可以通过parse_float和parse_int参数指定自定义的转换逻辑. 这两个方法的输入参数为表示JSON实数或者整数的字符串. 下例中, 我们将实数转换为numpy.float64, 将整数转换为numpy.int64:

>>> def my_parse_float(f):
... print('%s(%s)' % (type(f), f))
... return numpy.float64(f)
...
>>> def my_parse_int(i):
... print('%s(%s)' % (type(i), i))
... return numpy.int64(i)
...
>>> result = json.loads('{"i": 123, "f": 321.45}', parse_float=my_parse_float, parse_int=my_parse_int)
<type 'str'>(123)
<type 'str'>(321.45)
>>> type(result['i'])
<type 'numpy.int64'>
>>> type(result['f'])
<type 'numpy.float64'>

2.6.1 自定义NaN, Infinity和-Infinity转换类型

由于标准JSON数据不支持NaN, Infinity和-Infinity, 所以parse_float并不会接收到这几个值. 当需要自定义这几个值转换的对象的时候, 就需要使用另外一个接口parse_constant. 比如下例中, 将这几个值同样转换为numpy.float64类型:

>>> def my_parse_constant(data):
... print('%s(%s)' % (type(data), data))
... return numpy.float64(data)
...
>>> result = json.loads('{"inf": Infinity, "nan": NaN, "ninf": -Infinity}', parse_constant=my_parse_constant)
<type 'str'>(Infinity)
<type 'str'>(NaN)
<type 'str'>(-Infinity)
>>> result['inf']
inf
>>> type(result['inf'])
<type 'numpy.float64'>

2.7 非对象顶级值

根据JSON规范, 一个JSON数据中, 可以只包含一个值, 而不是一个完整的对象. 这个值可以是一个字符串, 一个数字, 布尔值, 空值, 或者一个数组. 除了这三种JSON规范中给出的类型, 还可以是NaN, Infinity或者-Infinity:

>>> json.loads('"hello"')
'hello'
>>> json.loads('123')
123
>>> json.loads('123.34')
123.34
>>> json.loads('true')
True
>>> json.loads('false')
False
>>> print(json.loads('null'))
None
>>> json.loads('[1, 2, 3]')
[1, 2, 3]

2.8 重复键名

在同一层级JSON对象中, 不应当出现重复的键名, 不过JSON规范中没有给出这种情况的处理标准. 在json.loads中, 当JSON数据中有重复键名, 则后面的键值会覆盖前面的:

>>> json.loads('{"a": 123, "b": "ABC", "a": 321}')
{'a': 321, 'b': 'ABC'}

2.9 处理JSON数据文件

当JSON数据是保存在一个文件中的时候, json.load方法可以用来从这个文件中读取数据, 并转换为Python对象. json.load方法的第一个参数就是指向JSON数据文件的文件类型对象.

比如/tmp/data.json文件的内含如下:

{
"a": 123,
"b": "ABC"
}

可以使用下例中的代码来读取并转化文件中的JSON数据:

>>> with open('/tmp/data.json') as jf:
... json.load(jf)
...
{u'a': 123, u'b': u'ABC'}

除了文件类型的对象, 只要是实现了read方法的类文件对象, 都可以作为fp参数, 比如下例中的io.StringIO:

>>> sio = io.StringIO('{"a": 123}')
>>> json.load(sio)
{'a': 123}

json.load方法的其他参数的意义和使用方法和上文中的json.loads相同, 这里不再赘述.

3 生成JSON

json.dumps方法可以将Python对象转换为一个表示JONS数据的字符串. 它的完整接口签名如下:

json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

它的第一个参数obj即为要转换的数据对象.

>>> json.dumps({'a': 123, 'b': 'ABC'})
'{"a": 123, "b": "ABC"}'

3.1 编码格式

json.dumps的ensure_ascii参数用来控制生成的JSON字符串的编码. 其默认值为True, 此时, 所有的非ASCII码字条都会转义. 如果不希望自动进行转义, 则会保持原有编码, 限UTF-8. 如下例所示:

>>> json.dumps({'数字': 123, '字符': '一二三'})
'{"\\u6570\\u5b57": 123, "\\u5b57\\u7b26": "\\u4e00\\u4e8c\\u4e09"}'
>>> json.dumps({'数字': 123, '字符': '一二三'}, ensure_ascii=False)
'{"数字": 123, "字符": "一二三"}'

3.2 数据类型转换

在默认实现中, json.dumps可以处理的Python对象, 及其所有的属性值, 类型必须为dict, list, tuple, str, float或者int. 这些类型与JSON的数据转换关系如下表:

Python JSON
dict object
list, tuple array
str string
int, float, int-&float-derived emuns number
True true
False false
None null

实际转换情况如下示例:

>>> json.dumps(
... {
... 'str': 'ABC',
... 'int': 123,
... 'float': 321.45,
... 'bool_true': True,
... 'bool_false': False,
... 'none': None,
... 'list': [1, 2, 3],
... 'tuple': [12, 34]
... }
... )
'{"str": "ABC", "int": 123, "float": 321.45, "bool_true": true, "bool_flase": false, "none": null, "list": [1, 2, 3], "tuple": [12, 34]}'

虽然JSON标准规范不支持NaN, Infinity和-Infinity, 但是json.dumps的默认实现会将float('nan'), float('inf')和float('-inf')转换为常量NaN, Infinity, 和-Infinity. 如下例所示:

>>> json.dumps(
... {
... 'nan': float('nan'),
... 'inf': float('inf'),
... '-inf': float('-inf')
... }
... )
'{"nan": NaN, "inf": Infinity, "-inf": -Infinity}'

由于这些常量可能会导致生成的JSON字符串不能被其他的JSON实现处理, 为了防止这种情况出现, 可以将json.dumps的allow_nan参数设置为True. 此时, 当处理的Python对象中出现这些值时, json.dumps方法会抛出异常.

3.3 循环引用

json.dumps方法会检查Python对象中是否有循环引用, 如果发现了循环引用, 就会抛出异常. 如下例所示:

>>> circular_obj = {}
>>> circular_obj['self'] = circular_obj
>>> circular_obj
{'self': {...}}
>>> json.dumps(circular_obj)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
ValueError: Circular reference detected

如果不希望json.dumps方法检查循环引用, 可以将参数check_circular设置为False. 但如果此时Python对象中有循环引用, 有可能发生递归嵌套过深的错误或者其他错误, 这么做是比较危险的. 如下例所示:

>>> json.dumps(circular_obj, check_circular=False)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 238, in dumps
**kw).encode(obj)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
RecursionError: maximum recursion depth exceeded while encoding a JSON object

3.4 JSON字符串输出格式

json.dumps方法的indent参数可以用来控制JSON字符串的换行和缩进效果.

indent参数默认值为None. 此时, JSON字符串不会有换行和缩进效果. 如下示:

>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}))
{"a": 123, "b": {"x": 321, "y": "ABC"}}

当indent为0或者负数时, JSON字符会包含换行:

>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent=-1))
{
"a": 123,
"b": {
"x": 321,
"y": "ABC"
}
}
>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent=0))
{
"a": 123,
"b": {
"x": 321,
"y": "ABC"
}
}

而当indent为正整数时, 除了换行, JSON还会以指定数量的空格为单位在对象层次间进行缩进:

>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent=2))
{
"a": 123,
"b": {
"x": 321,
"y": "ABC"
}
}

indent还可以是str, 此时, JSON会以str内容为单位进行缩进, 比如制表符\t:

>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent='\t'))
{
"a": 123,
"b": {
"x": 321,
"y": "ABC"
}
}

json.dumps的另外一个参数separators可以用来设置输出的分隔符. 这个参数的值应当是一个有两个元素的tuple. 其第一个值为成员间的分隔符, 第二个值为键值之间的分隔符. 其默认值也会随上文中的indent参数影响. 当indent为None时, separators的默认值为(', ', ': '), 即分隔符后都有一个空格. 当indent不为None时, 其默认值则为(',', ':'), 即只有键值间分隔符后会有一个空格, 而元素间分隔符则不带空格, 因为此时会有换行.

separators参数的一种可能的使用场景是希望移除所有的非必要格式字符, 以此来减小JSON字符串的大小. 此时可以将separator设置为(',', ';'), 并不设置indent参数, 或者将其显式设置为None:

>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent=None, separators=(',', ':')))
{"a":123,"b":{"x":321,"y":"ABC"}}

3.5 转换自定义Python对象

json.dumps的默认实现只能转换Dictionary类型的对象. 如果想要转换自定义对象, 需要使用default参数. 这个参数接收一个函数, 这个函数的参数是一个要转换的Python对象, 返回值是能够表示这个Python对象的Dictionary对象. default函数会从对象引用树的顶层开始, 逐层遍历整个对象引用树. 因此, 不用自己实现对象树的遍历逻辑, 只需要处理当前层次的对象. 如下例所示:

>>> class MyClass:
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
>>> def my_default(o):
... if isinstance(o, MyClass):
... print('%s.y: %s' % (type(o), o.y))
... return {'x': o.x, 'y': o.y}
... print(o)
... return o
...
>>> obj = MyClass(x=MyClass(x=1, y=2), y=11)
>>> json.dumps(obj, default=my_default)
<class '__main__.MyClass'>.y: 11
<class '__main__.MyClass'>.y: 2
'{"x": {"x": 1, "y": 2}, "y": 11}'

3.6 非字符串类型键名

在Python中, 只是可哈希(hashable)的对象和数据都可以做为Dictionary对象的键, 而JSON规范中则只能使用字符串做为键名. 所以在json.dumps的实现中, 对这个规则进行了检查, 不过键名允许的范围有所扩大, str, int, float, bool和None类型的数据都可以做为键名. 不过当键名非str的情况时, 键名会转换为对应的str值. 如下例:

>>> json.dumps(
... {
... 'str': 'str',
... 123: 123,
... 321.54: 321.54,
... True: True,
... False: False,
... None: None
... }
... )
'{"str": "str", "123": 123, "321.54": 321.54, "true": true, "false": false, "null": null}'

而当出现其他类型的键名时, 默认出抛出异常:

>>> json.dumps({(1,2): 123})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
TypeError: keys must be a string

json.dumps的skipkeys参数可以改变这个行为. 当将skipkeys设置为True时, 遇到非法的键名类型, 不会抛出异常, 而是跳过这个键名:

>>> json.dumps({(1,2): 123}, skipkeys=True)
'{}'

3.7 生成JSON文件

当需要将生成的JSON数据保存到文件时, 可以使用json.dump方法. 这个方法比json.dumps多了一个参数fp, 这个参数就是用来保存JSON数据的文件对象. 比如, 下例中的代码

>>> with open('/tmp/data.json', mode='a') as jf:
... json.dump({'a': 123}, jf)
...

就会将JSON数据写入到/tmp/data.json文件里. 代码执行完后, 文件内容为

{"a": 123} 
json.dump方法也可以接受其他类文件对象:
>>> sio = io.StringIO()
>>> json.dump({'a': 123}, sio)
>>> sio.getvalue()
'{"a": 123}'

json.dump的其他参数和json.dumps的用法相同, 这里不再赘述.

4 JSON解码和编码类实现

json.loads, json.load, json.dumps和json.dump这四个方法是通过json.JSONDecoder和json.JSONEncoder这两个类来完成各自的任务的. 所以也可以直接使用这两个类来完成前文描述的功能:

>>> json.JSONDecoder().decode('{"a": 123}')
{'a': 123}
>>> json.JSONEncoder().encode({'a': 123})
'{"a": 123}'

json.loads, json.load, json.dumps和json.dump这个四个方法的参数主要都是传递给了json.JSONDecoder和json.JSONEncoder的构造方法, 所以使用这些方法可以满足绝大部分需求. 当需要自定义json.JSONDecoder和json.JSONEncoder子类的时候, 只需要将子类传递给cls参数. 同时, 这些方法都有**kw参数. 当自定义实现类的构造函数需要标准参数列表之外的新参数时, 这个参数就会将新参数传递给实现类的构造方法.

5 相关资源

  1. JSON
  2. The JavaScript Object Notation (JSON) Data Interchange Format - RFC 4627
  3. json — JSON encoder and decoder

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python使用cookie库操保存cookie详解
Mar 03 Python
Python的字典和列表的使用中一些需要注意的地方
Apr 24 Python
python中numpy基础学习及进行数组和矢量计算
Feb 12 Python
Python实现合并两个列表的方法分析
May 28 Python
Python面向对象程序设计OOP入门教程【类,实例,继承,重载等】
Jan 05 Python
python 限制函数执行时间,自己实现timeout的实例
Jan 12 Python
python实现批量视频分帧、保存视频帧
May 31 Python
解决keras GAN训练是loss不发生变化,accuracy一直为0.5的问题
Jul 02 Python
python--shutil移动文件到另一个路径的操作
Jul 13 Python
python使用XPath解析数据爬取起点小说网数据
Apr 22 Python
Python+Appium实现自动抢微信红包
May 21 Python
宝塔更新Python及Flask项目的部署
Apr 11 Python
Python 编码规范(Google Python Style Guide)
May 05 #Python
python 编码规范整理
May 05 #Python
PYTHON基础-时间日期处理小结
May 05 #Python
python 日期操作类代码
May 05 #Python
Python批量发送post请求的实现代码
May 05 #Python
PyQt5 pyqt多线程操作入门
May 05 #Python
详解pyqt5 动画在QThread线程中无法运行问题
May 05 #Python
You might like
DedeCMS 核心类TypeLink.class.php摘要笔记
2010/04/07 PHP
php删除左端与右端空格的方法
2014/11/29 PHP
才发现的超链接js导致网页中GIF动画停止的解决方法
2007/11/02 Javascript
javascript dom追加内容实现示例
2013/09/21 Javascript
JS实现时间格式化的方式汇总
2013/10/16 Javascript
JavaScript中的Web worker多线程API研究
2014/12/06 Javascript
JavaScript模块规范之AMD规范和CMD规范
2015/10/27 Javascript
利用Javascript实现简单的转盘抽奖
2017/02/13 Javascript
vue省市区三联动下拉选择组件的实现
2017/04/28 Javascript
详解vue-router传参的两种方式
2018/09/10 Javascript
实现elementUI表单的全局验证的方法步骤
2019/04/29 Javascript
js模拟实现百度搜索
2020/06/28 Javascript
JavaScript 异步时序问题
2020/11/20 Javascript
python使用PyV8执行javascript代码示例分享
2013/12/04 Python
python安装oracle扩展及数据库连接方法
2017/02/21 Python
pygame游戏之旅 计算游戏中躲过的障碍数量
2018/11/20 Python
pybind11和numpy进行交互的方法
2019/07/04 Python
python Django 创建应用过程图示详解
2019/07/29 Python
django基于存储在前端的token用户认证解析
2019/08/06 Python
flask框架url与重定向操作实例详解
2020/01/25 Python
解决Jupyter无法导入已安装的 module问题
2020/04/17 Python
Python ORM框架Peewee用法详解
2020/04/29 Python
Spring @Enable模块驱动原理及使用实例
2020/06/23 Python
爱尔兰最大的体育零售商:Life Style Sports
2019/06/12 全球购物
JSP&Servlet技术面试题
2015/05/21 面试题
初三化学教学反思
2014/01/23 职场文书
打造完美自荐信
2014/01/24 职场文书
文字自荐书范文
2014/02/10 职场文书
祖国在我心中演讲稿500字
2014/05/04 职场文书
运动会口号大全
2014/06/07 职场文书
个人对照检查材料思想汇报
2014/09/26 职场文书
2015年党员自评材料
2014/12/17 职场文书
先进人物事迹材料
2014/12/29 职场文书
仓管员岗位职责
2015/02/03 职场文书
施工员岗位职责
2015/02/10 职场文书
关于分班的感言
2015/08/04 职场文书