模块补充
configparser(提供配置文件的读写解析操作)
configparser的方法
sections() #获取配置文件的所有section(返回列表) items(section) #获取指定section下所有的键值对(返回一个列表,一个键值对是一个元祖) options(section) #获取指定节点下所有的键(返回列表) get(section,option) #获取指定节点下的指定option的值,返回字符串 getint(section, option) #获取指定节点下的指定option的值,返回整形 getfloat(sction, option) #获取指定节点下的指定option的值,返回浮点形 getboolean(section, option) #获取指定节点下的指定option的值,返回布尔形 write(file_obj) #保存配置文件的更改操作
检查,删除,添加节点 has_section(section) #检查有没有指定的section,返回true或false add_section(section) #添加一个指定的section remove_section(section) #删除一个指定的section 检查,删除,设置指定section内的option has_option(section, option) #检查指定section中是否有指定的option,返回布尔 remove_option(section, option) #删除指定section中的指定option键值对 set(section, option_key, option_value) #在指定section下设置一个option键值对
操作实例:
在配置文件中添加删除section
1 1. 在配置文件末尾追加一个section 2 创建一个实例 3 config = configparser.ConfigParser() 4 将文件内容读取到内存 5 config.read('my.cnf', encoding='utf-8') 6 添加一个section 7 config.add_section('gouyc') 8 保存更改到文件中 9 with open('my.cnf', 'w') as f: 10 config.write(f) 11 12 2. 删除配置文件中的一个section 13 ret = config.remove_section('gouyc') 14 with open('my.cnf', 'w') as f: 15 config.write(f) 16 17 3. 检查有没有指定的section,返回布尔 18 ret = config.has_section('gouyc') 19 print(ret)
在配置文件中操作section中的option(添加,删除,检查option)
1 1. 检查指定section中是否有指定的option 2 import configparser 3 4 创建一个config的对象 5 config = configparser.ConfigParser() 6 读取配置文件 7 config.read('my.cnf', encoding='utf-8') 8 检查mysqld的section中是否有server-id的option 9 ret = config.has_option('mysqld', 'server-id') 10 print(ret) 11 12 2. 在指定section中添加一个option 13 import configparser 14 15 config = configparser.ConfigParser() 16 config.read('my.cnf', encoding='utf-8') 17 在mysqld中的section中添加一个serverid的option,值是1 18 config.set('mysqld', 'serverid', '1') 19 打开文件 20 with open('my.cnf', 'w') as f: 21 将更改写入文件。 22 config.write(f) 23 24 3.在指定section中删除一个option 25 config.remove_option('mysqld', 'serverid') 26 with open('my.cnf', 'w') as f: 27 config.write(f)
注意:添加option时,如果指定的option已经存在,那么将修改option对应的值。
XML模块(提供对xml文件的操作)
什么是xml?
XML(eXtensible Markup Language)指可扩展标记语言,被设计用来传输和存储数据,已经日趋成为当前许多新生技术的核心,在不同的领域都有着不同的应用。它是web发展到一定阶段的必然产物,既具有SGML的核心特征,又有着HTML的简单特性,还具有明确和结构良好等许多新的特性。
python解析XML常见的有三种方法:一是xml.dom.*模块,它是W3C DOM API的实现,若需要处理DOM API则该模块很适合,注意xml.dom包里面有许多模块,须区分它们间的不同;二是xml.sax.*模块,它是SAX API的实现,这个模块牺牲了便捷性来换取速度和内存占用,SAX是一个基于事件的API,这就意味着它可以“在空中”处理庞大数量的的文档,不用完全加载进内存;三是xml.etree.ElementTree模块(简称 ET),它提供了轻量级的Python式的API,相对于DOM来说ET 快了很多,而且有很多令人愉悦的API可以使用,相对于SAX来说ET的ET.iterparse也提供了 “在空中” 的处理方式,没有必要加载整个文档到内存,ET的性能的平均值和SAX差不多,但是API的效率更高一点而且使用起来很方便。
简单来说,xml是实现不同语言或程序之间进行数据交换的协议。
python中操作xml的模块是ElementTree
1、解析xml文件
1 from xml.etree import ElementTree as ET 2 3 解析xml文件 4 xmlfile = ET.parse('xo.xml') 5 获取xml的根节点(获取到的是一个element对象) 6 root = xmlfile.getroot() 7 8 获取跟节点的名字 9 root.tag 10 11 获取节点的属性(返回一个字典) 12 root.attrib 13 14 获取节点的内容(有内容返回内容,无内容返回空 ) 15 root.text
2、操作xml文件
class Element: """An XML element. This class is the reference implementation of the Element interface. An element's length is its number of subelements. That means if you want to check if an element is truly empty, you should check BOTH its length AND its text attribute. The element tag, attribute names, and attribute values can be either bytes or strings. *tag* is the element name. *attrib* is an optional dictionary containing element attributes. *extra* are additional element attributes given as keyword arguments. Example form: <tag attrib>text<child/>...</tag>tail """ 当前节点的标签名 tag = None """The element's name.""" 当前节点的属性 attrib = None """Dictionary of the element's attributes.""" 当前节点的内容 text = None """ Text before first subelement. This is either a string or the value None. Note that if there is no text, this attribute may be either None or the empty string, depending on the parser. """ tail = None """ Text after this element's end tag, but before the next sibling element's start tag. This is either a string or the value None. Note that if there was no text, this attribute may be either None or an empty string, depending on the parser. """ def __init__(self, tag, attrib={}, **extra): if not isinstance(attrib, dict): raise TypeError("attrib must be dict, not %s" % ( attrib.__class__.__name__,)) attrib = attrib.copy() attrib.update(extra) self.tag = tag self.attrib = attrib self._children = [] def __repr__(self): return "<%s %r at %#x>" % (self.__class__.__name__, self.tag, id(self)) def makeelement(self, tag, attrib): 创建一个新节点 """Create a new element with the same type. *tag* is a string containing the element name. *attrib* is a dictionary containing the element attributes. Do not call this method, use the SubElement factory function instead. """ return self.__class__(tag, attrib) def copy(self): """Return copy of current element. This creates a shallow copy. Subelements will be shared with the original tree. """ elem = self.makeelement(self.tag, self.attrib) elem.text = self.text elem.tail = self.tail elem[:] = self return elem def __len__(self): return len(self._children) def __bool__(self): warnings.warn( "The behavior of this method will change in future versions. " "Use specific 'len(elem)' or 'elem is not None' test instead.", FutureWarning, stacklevel=2 ) return len(self._children) != 0 # emulate old behaviour, for now def __getitem__(self, index): return self._children[index] def __setitem__(self, index, element): # if isinstance(index, slice): # for elt in element: # assert iselement(elt) # else: # assert iselement(element) self._children[index] = element def __delitem__(self, index): del self._children[index] def append(self, subelement): 为当前节点追加一个子节点 """Add *subelement* to the end of this element. The new element will appear in document order after the last existing subelement (or directly after the text, if it's the first subelement), but before the end tag for this element. """ self._assert_is_element(subelement) self._children.append(subelement) def extend(self, elements): 为当前节点扩展 n 个子节点 """Append subelements from a sequence. *elements* is a sequence with zero or more elements. """ for element in elements: self._assert_is_element(element) self._children.extend(elements) def insert(self, index, subelement): 在当前节点的子节点中插入某个节点,即:为当前节点创建子节点,然后插入指定位置 """Insert *subelement* at position *index*.""" self._assert_is_element(subelement) self._children.insert(index, subelement) def _assert_is_element(self, e): # Need to refer to the actual Python implementation, not the # shadowing C implementation. if not isinstance(e, _Element_Py): raise TypeError('expected an Element, not %s' % type(e).__name__) def remove(self, subelement): 在当前节点在子节点中删除某个节点 """Remove matching subelement. Unlike the find methods, this method compares elements based on identity, NOT ON tag value or contents. To remove subelements by other means, the easiest way is to use a list comprehension to select what elements to keep, and then use slice assignment to update the parent element. ValueError is raised if a matching element could not be found. """ # assert iselement(element) self._children.remove(subelement) def getchildren(self): 获取所有的子节点(废弃) """(Deprecated) Return all subelements. Elements are returned in document order. """ warnings.warn( "This method will be removed in future versions. " "Use 'list(elem)' or iteration over elem instead.", DeprecationWarning, stacklevel=2 ) return self._children def find(self, path, namespaces=None): 获取第一个寻找到的子节点 """Find first matching element by tag name or path. *path* is a string having either an element tag or an XPath, *namespaces* is an optional mapping from namespace prefix to full name. Return the first matching element, or None if no element was found. """ return ElementPath.find(self, path, namespaces) def findtext(self, path, default=None, namespaces=None): 获取第一个寻找到的子节点的内容 """Find text for first matching element by tag name or path. *path* is a string having either an element tag or an XPath, *default* is the value to return if the element was not found, *namespaces* is an optional mapping from namespace prefix to full name. Return text content of first matching element, or default value if none was found. Note that if an element is found having no text content, the empty string is returned. """ return ElementPath.findtext(self, path, default, namespaces) def findall(self, path, namespaces=None): 获取所有的子节点 """Find all matching subelements by tag name or path. *path* is a string having either an element tag or an XPath, *namespaces* is an optional mapping from namespace prefix to full name. Returns list containing all matching elements in document order. """ return ElementPath.findall(self, path, namespaces) def iterfind(self, path, namespaces=None): 获取所有指定的节点,并创建一个迭代器(可以被for循环) """Find all matching subelements by tag name or path. *path* is a string having either an element tag or an XPath, *namespaces* is an optional mapping from namespace prefix to full name. Return an iterable yielding all matching elements in document order. """ return ElementPath.iterfind(self, path, namespaces) def clear(self): 清空节点 """Reset element. This function removes all subelements, clears all attributes, and sets the text and tail attributes to None. """ self.attrib.clear() self._children = [] self.text = self.tail = None def get(self, key, default=None): 获取当前节点的属性值 """Get element attribute. Equivalent to attrib.get, but some implementations may handle this a bit more efficiently. *key* is what attribute to look for, and *default* is what to return if the attribute was not found. Returns a string containing the attribute value, or the default if attribute was not found. """ return self.attrib.get(key, default) def set(self, key, value): 为当前节点设置属性值 """Set element attribute. Equivalent to attrib[key] = value, but some implementations may handle this a bit more efficiently. *key* is what attribute to set, and *value* is the attribute value to set it to. """ self.attrib[key] = value def keys(self): 获取当前节点的所有属性的 key """Get list of attribute names. Names are returned in an arbitrary order, just like an ordinary Python dict. Equivalent to attrib.keys() """ return self.attrib.keys() def items(self): 获取当前节点的所有属性值,每个属性都是一个键值对 """Get element attributes as a sequence. The attributes are returned in arbitrary order. Equivalent to attrib.items(). Return a list of (name, value) tuples. """ return self.attrib.items() def iter(self, tag=None): 在当前节点的子孙中根据节点名称寻找所有指定的节点,并返回一个迭代器(可以被for循环)。 """Create tree iterator. The iterator loops over the element and all subelements in document order, returning all elements with a matching tag. If the tree structure is modified during iteration, new or removed elements may or may not be included. To get a stable set, use the list() function on the iterator, and loop over the resulting list. *tag* is what tags to look for (default is to return all elements) Return an iterator containing all the matching elements. """ if tag == "*": tag = None if tag is None or self.tag == tag: yield self for e in self._children: yield from e.iter(tag) # compatibility def getiterator(self, tag=None): # Change for a DeprecationWarning in 1.4 warnings.warn( "This method will be removed in future versions. " "Use 'elem.iter()' or 'list(elem.iter())' instead.", PendingDeprecationWarning, stacklevel=2 ) return list(self.iter(tag)) def itertext(self): 在当前节点的子孙中根据节点名称寻找所有指定的节点的内容,并返回一个迭代器(可以被for循环)。 """Create text iterator. The iterator loops over the element and all subelements in document order, returning all inner text. """ tag = self.tag if not isinstance(tag, str) and tag is not None: return if self.text: yield self.text for e in self: yield from e.itertext() if e.tail: yield e.tail
注意:由于 每个节点 都具有以上的方法,并且在上一步骤中解析时均得到了root(xml文件的根节点),所以 可以利用以上方法进行操作xml文件。
遍历xml文件的所有内容
1 方式一,根据xml文件获取element 2 from xml.etree import ElementTree as ET 3 4 xmlfile = ET.parse('xo.xml') 5 root = xmlfile.getroot() 6 for item in root: 7 print(item.tag, item.attrib) 8 for line in item: 9 print(line.tag, line.attrib, line.text) 10 11 方式二,打开文件,获取xml文件内容 12 str_xml = open('xo.xml', 'r').read() 13 14 root = ET.XML(str_xml)
遍历xml文件中指定的节点
1 root表示根节点,iter方法指定节点 2 for item in root.iter('country'): 3 print(item.tag, item.attrib)
修改节点内容
1 from xml.etree import ElementTree as ET 2 3 ############ 解析方式二 ############ 4 5 # 直接解析xml文件 6 tree = ET.parse("xo.xml") 7 8 # 获取xml文件的根节点 9 root = tree.getroot() 10 11 ############ 操作 ############ 12 13 # 顶层标签 14 print(root.tag) 15 16 # 循环所有的year节点 17 for node in root.iter('year'): 18 # 将year节点中的内容自增一 19 new_year = int(node.text) + 1 20 node.text = str(new_year) 21 22 # 设置属性 23 node.set('name', 'alex') 24 node.set('age', '18') 25 # 删除属性 26 del node.attrib['name'] 27 28 29 ############ 保存文件 ############ 30 tree.write("newnew.xml", encoding='utf-8')
1 from xml.etree import ElementTree as ET 2 3 ############ 解析方式一 ############ 4 5 # 打开文件,读取XML内容 6 str_xml = open('xo.xml', 'r').read() 7 8 # 将字符串解析成xml特殊对象,root代指xml文件的根节点 9 root = ET.XML(str_xml) 10 11 ############ 操作 ############ 12 13 # 顶层标签 14 print(root.tag) 15 16 # 循环所有的year节点 17 for node in root.iter('year'): 18 # 将year节点中的内容自增一 19 new_year = int(node.text) + 1 20 node.text = str(new_year) 21 22 # 设置属性 23 node.set('name', 'alex') 24 node.set('age', '18') 25 # 删除属性 26 del node.attrib['name'] 27 28 29 ############ 保存文件 ############ 30 tree = ET.ElementTree(root) 31 tree.write("newnew.xml", encoding='utf-8') 32 33 解析字符串方式,修改,保存
删除节点
1 from xml.etree import ElementTree as ET 2 3 ############ 解析字符串方式打开 ############ 4 5 # 打开文件,读取XML内容 6 str_xml = open('xo.xml', 'r').read() 7 8 # 将字符串解析成xml特殊对象,root代指xml文件的根节点 9 root = ET.XML(str_xml) 10 11 ############ 操作 ############ 12 13 # 顶层标签 14 print(root.tag) 15 16 # 遍历data下的所有country节点 17 for country in root.findall('country'): 18 # 获取每一个country节点下rank节点的内容 19 rank = int(country.find('rank').text) 20 21 if rank > 50: 22 # 删除指定country节点 23 root.remove(country) 24 25 ############ 保存文件 ############ 26 tree = ET.ElementTree(root) 27 tree.write("newnew.xml", encoding='utf-8')
1 from xml.etree import ElementTree as ET 2 3 ############ 解析文件方式 ############ 4 5 # 直接解析xml文件 6 tree = ET.parse("xo.xml") 7 8 # 获取xml文件的根节点 9 root = tree.getroot() 10 11 ############ 操作 ############ 12 13 # 顶层标签 14 print(root.tag) 15 16 # 遍历data下的所有country节点 17 for country in root.findall('country'): 18 # 获取每一个country节点下rank节点的内容 19 rank = int(country.find('rank').text) 20 21 if rank > 50: 22 # 删除指定country节点 23 root.remove(country) 24 25 ############ 保存文件 ############ 26 tree.write("newnew.xml", encoding='utf-8')
创建节点
1 from xml.etree import ElementTree as ET 2 3 4 # 创建根节点 5 root = ET.Element("famliy") 6 7 8 # 创建节点大儿子 9 son1 = ET.Element('son', {'name': '儿1'}) 10 # 创建小儿子 11 son2 = ET.Element('son', {"name": '儿2'}) 12 13 # 在大儿子中创建两个孙子 14 grandson1 = ET.Element('grandson', {'name': '儿11'}) 15 grandson2 = ET.Element('grandson', {'name': '儿12'}) 16 son1.append(grandson1) 17 son1.append(grandson2) 18 19 20 # 把儿子添加到根节点中 21 root.append(son1) 22 root.append(son1) 23 24 tree = ET.ElementTree(root) 25 tree.write('oooo.xml',encoding='utf-8', short_empty_elements=False)
1 from xml.etree import ElementTree as ET 2 3 # 创建根节点 4 root = ET.Element("famliy") 5 6 7 # 创建大儿子 8 # son1 = ET.Element('son', {'name': '儿1'}) 9 son1 = root.makeelement('son', {'name': '儿1'}) 10 # 创建小儿子 11 # son2 = ET.Element('son', {"name": '儿2'}) 12 son2 = root.makeelement('son', {"name": '儿2'}) 13 14 # 在大儿子中创建两个孙子 15 # grandson1 = ET.Element('grandson', {'name': '儿11'}) 16 grandson1 = son1.makeelement('grandson', {'name': '儿11'}) 17 # grandson2 = ET.Element('grandson', {'name': '儿12'}) 18 grandson2 = son1.makeelement('grandson', {'name': '儿12'}) 19 20 son1.append(grandson1) 21 son1.append(grandson2) 22 23 24 # 把儿子添加到根节点中 25 root.append(son1) 26 root.append(son1) 27 28 tree = ET.ElementTree(root) 29 tree.write('oooo.xml',encoding='utf-8', short_empty_elements=False)
1 from xml.etree import ElementTree as ET 2 3 4 # 创建根节点 5 root = ET.Element("famliy") 6 7 8 # 创建节点大儿子 9 son1 = ET.SubElement(root, "son", attrib={'name': '儿1'}) 10 # 创建小儿子 11 son2 = ET.SubElement(root, "son", attrib={"name": "儿2"}) 12 13 # 在大儿子中创建一个孙子 14 grandson1 = ET.SubElement(son1, "age", attrib={'name': '儿11'}) 15 grandson1.text = '孙子' 16 17 18 et = ET.ElementTree(root) #生成文档对象 19 et.write("test.xml", encoding="utf-8", xml_declaration=True, short_empty_elements=False)
注意:由于原生保存的XML时默认无缩进,如果想要设置缩进的话, 需要修改保存方式:
1 from xml.etree import ElementTree as ET 2 from xml.dom import minidom 3 4 5 def prettify(elem): 6 """将节点转换成字符串,并添加缩进。 7 """ 8 rough_string = ET.tostring(elem, 'utf-8') 9 reparsed = minidom.parseString(rough_string) 10 return reparsed.toprettyxml(indent=" ") 11 12 # 创建根节点 13 root = ET.Element("famliy") 14 15 16 # 创建大儿子 17 # son1 = ET.Element('son', {'name': '儿1'}) 18 son1 = root.makeelement('son', {'name': '儿1'}) 19 # 创建小儿子 20 # son2 = ET.Element('son', {"name": '儿2'}) 21 son2 = root.makeelement('son', {"name": '儿2'}) 22 23 # 在大儿子中创建两个孙子 24 # grandson1 = ET.Element('grandson', {'name': '儿11'}) 25 grandson1 = son1.makeelement('grandson', {'name': '儿11'}) 26 # grandson2 = ET.Element('grandson', {'name': '儿12'}) 27 grandson2 = son1.makeelement('grandson', {'name': '儿12'}) 28 29 son1.append(grandson1) 30 son1.append(grandson2) 31 32 33 # 把儿子添加到根节点中 34 root.append(son1) 35 root.append(son1) 36 37 38 raw_str = prettify(root) 39 40 f = open("xxxoo.xml",'w',encoding='utf-8') 41 f.write(raw_str) 42 f.close()
subprocess(执行系统命令)
可以执行shell命令的相关模块和函数有:
- os.system
- os.spawn*
- os.popen* 废弃
- popen2.* 废弃
- commands.* 废弃,3.x中被移除
注意:以上执行shell命令的相关的模块和函数的功能均在 subprocess 模块中实现,并提供了更丰富的功能。
subprocess.call(执行命令,返回状态码)
1 ret = subprocess.call(["ls", "-l"], shell=False) 2 ret = subprocess.call("ls -l", shell=True)
subproc.esscheck_call(执行命令,如果执行状态码是 0 ,则返回0,否则抛异常)
1 subprocess.check_output(["echo", "Hello World!"]) 2 subprocess.check_output("exit 1", shell=True)
subprocess.popen(用来执行复杂的系统命令)
参数:
- args:shell命令,可以是字符串或者序列类型(如:list,元组)
- bufsize:指定缓冲。0 无缓冲,1 行缓冲,其他 缓冲区大小,负值 系统缓冲
- stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
- preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
- close_sfs:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会继承父进程的输入、输出、错误管道。
所以不能将close_fds设置为True同时重定向子进程的标准输入、输出与错误(stdin, stdout, stderr)。 - shell:同上
- cwd:用于设置子进程的当前目录
- env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
- universal_newlines:不同系统的换行符不同,True -> 同意使用
- startupinfo与createionflags只在windows下有效
将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等
1 import subprocess 2 ret1 = subprocess.Popen(["mkdir","t1"]) 3 ret2 = subprocess.Popen("mkdir t2", shell=True)
终端输入的命令分为两种:
- 输入即可得到输出,如:ifconfig
- 输入进行某环境,依赖再输入,如:python
1 import subprocess 2 3 obj = subprocess.Popen("mkdir t3", shell=True, cwd='/home/dev',)
1 import subprocess 2 3 obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) 4 obj.stdin.write("print(1) ") 5 obj.stdin.write("print(2)") 6 obj.stdin.close() 7 8 cmd_out = obj.stdout.read() 9 obj.stdout.close() 10 cmd_error = obj.stderr.read() 11 obj.stderr.close() 12 13 print(cmd_out) 14 print(cmd_error)
1 import subprocess 2 3 obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) 4 obj.stdin.write("print(1) ") 5 obj.stdin.write("print(2)") 6 7 out_error_list = obj.communicate() 8 print(out_error_list)
1 import subprocess 2 3 obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) 4 out_error_list = obj.communicate('print("hello")') 5 print(out_error_list)
shutile(文件操作,复制(文件内容,权限,状态信息)递归拷贝文件。压缩文件,打包文件处理)
shutil.copyfileobj(fsrc, fdst[, length])
将文件内容拷贝到另一个文件中
1 import shutil 2 3 shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))
shutil.copyfile(src, dst)
拷贝文件
1 shutil.copyfile('nginx.conf', 'nginx2.conf')
shutil.copymode(src, dst)
仅拷贝权限。内容、组、用户均不变
1 shutil.copymode('f1.log', 'f2.log')
shutil.copystat(src, dst)
仅拷贝状态的信息,包括:mode bits, atime, mtime, flags
1 shutil.copystat('f1.log', 'f2.log')
shutil.copy(src, dst)
拷贝文件和权限
1 import shutil 2 3 shutil.copy('nginx.conf', 'nginx2.conf')
shutil.copy2(src, dst)
拷贝文件和状态信息
1 import shutil 2 3 shutil.copy2('nginx.conf', 'nginx2.conf')
shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件夹
1 import shutil 2 3 递归拷贝文件,可以忽略某些文件 4 shutil.copytree('log', 'log2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
1 import shutil 2 3 递归的拷贝文件,同时拷贝软链接文件 4 shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
shutil.rmtree(path[, ignore_errors[, onerror]])
递归的去删除文件
1 import shutil 2 3 shutil.rmtree('log')
shutil.move(src, dst)
递归的去移动文件,它类似mv命令,其实就是重命名。
1 import shutil 2 3 shutil.move('folder1', 'folder3')
shutil.make_archive(base_name, format,...)
创建压缩包并返回文件路径,例如:zip、tar
创建压缩包并返回文件路径,例如:zip、tar
- base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
如:www =>保存至当前路径
如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/ - format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
- root_dir: 要压缩的文件夹路径(默认当前目录)
- owner: 用户,默认当前用户
- group: 组,默认当前组
- logger: 用于记录日志,通常是logging.Logger对象
1 #将 /usr/local/nginx/bin 下的文件打包放置当前程序目录 2 import shutil 3 ret = shutil.make_archive("wwwwwwwwww", 'gztar', root_dir='/usr/local/nginx/bin') 4 5 6 #将 /usr/local/nginx/bin 下的文件打包放置 /data/back目录 7 import shutil 8 ret = shutil.make_archive("/data/back/wwwwwwwwww", 'gztar', root_dir='/usr/local/nginx/bin')
shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:
zipyas
1 import zipfile 2 3 # 压缩 4 z = zipfile.ZipFile('laxi.zip', 'w') 5 z.write('a.log') 6 z.write('data.data') 7 z.close() 8 9 # 解压 10 z = zipfile.ZipFile('laxi.zip', 'r') 11 z.extractall() 12 z.close()
tar解压缩
1 import tarfile 2 3 # 压缩 4 tar = tarfile.open('your.tar','w') 5 tar.add('/usr/local/bin/nginx', arcname='nginx') 6 tar.add('/usr/local/nginx/conf/nginx.conf', arcname='nginx.conf') 7 tar.close() 8 9 # 解压 10 tar = tarfile.open('your.tar','r') 11 tar.extractall() # 可设置解压地址 12 tar.close()
面向对象编程(oop)
面向过程编程:将程序的实现着重于过程上,一步一步的堆代码。经常在程序的书写过程中,同样的代码,要写很多次。不利于程序的阅读和排错
面向函数变成:将程序的实现分解成一个一个的小功能,将这些功能写成函数,在需要的时候,直接调用。不需要在重新写同样的功能。
面向对象编程:在函数的基础上,把同样的函数功能封装到类中。
面向对象的两个重要概念:
类和对象
类和对象的关系:
- 在创建一个对象时,会有一个类对象指针,表明这个对象是由哪个类创建的,当执行对象方法时,通过类对象指针到指定的类中去寻找方法并调用。
- 对象是类中的一个实例化的对象,比如动物是一个类,而猫,狗,猪都是动物类中的一个对象。
- 类是一个泛指,我们将具有同样功能,外观,行为的某些事物称为类,而这些具有同样功能,外观行为的某一个个体称之为类中的一个对象。
什么场景适合面向对象?
- 如果函数有共同的参数时,就可以变成适用面向对象的方式,将参数值一次性的封装到对象中,以后去对象中取即可。
比如数据库操作的场景
函数式编程实现过程:
- 写4个函数,增加数据,删除数据,更改数据,查询数据
- 根据业务逻辑在需要相应操作的时候,调用操作函数
1 def fetch(host, username, password, sql): 2 pass 3 4 def create(host, username, password, sql): 5 pass 6 7 def remove(host, username, password, sql): 8 pass 9 10 def modify(host, username, password, sql): 11 pass 12 13 14 fetch('123.com', 'root', 123456, 'select * from a') 15 create('123.com', 'root', 123456, 'create database a') 16 remove('123.com', 'root', 123456, 'delete a from user') 17 modify('123.com', 'root', 123456, 'update user set password=123')
使用函数式编程时,我们发现,每个函数都需要host,username和password的参数。那么如果有一种办法,能将这些共同的参数封装到一个容器中,就很轻松了
面向对象编程实现过程
1 class sqlhelper: 2 3 def __init__(self, host, username, password): 4 self.host = host 5 self.username = username 6 self.password = password 7 8 def fetch(self, sql): 9 print(self.host) 10 11 def create(self, sql): 12 pass 13 14 def remove(self, sql): 15 pass 16 17 def modify(self, sql): 18 pass 19 20 obj1 = sqlhelper('c1.com', 'root', 123) 21 obj2 = sqlhelper('c2.com', 'gouyc', 456) 22 23 obj1.fetch('select * from a') 24 obj2.fetch('select * from a')
面向对象的三大特征:
一、封装
封装即把对象的共同属性封装到一个容器当中,封装完后属性称为字段,在创建对象时,会自动得到这些字段。所以,使用封装时需要:
- 将字段封装到容器中
- 从容器中获得封装好的字段
第一步:将属性封装到容器中
self是一个形式参数,代表创建的对象本身
当执行obj1 = Foo('wupeiqi', 18)时,self代表obj1,并把wupeiqi 和18分别封装到了Foo类中的name和age字段中。这就是封装。
当执行obj1 = Foo('alex', 73)时,self代表obj2,并把alex 和73分别封装到了Foo类中的name和age字段中。这就是封装。
由此可见,wupeiqi,18和alex,73被分别封装到了对象中,在内存中类似于下图来保存:
而obj1和obj2称为类的对象,对象中保存了各自的字段,而对象本身就是self
第二步、调用封装的字段
调用被封装的内容时,有两种情况:
- 从对象直接调用
- 通过self间接的调用
1、通过对象直接调用
1 class Foo: 2 3 def __init__(self, name, age): 4 self.name = name 5 self.age = age 6 7 obj1 = Foo('wupeiqi', 18) 8 print obj1.name # 直接调用obj1对象的name属性 9 print obj1.age # 直接调用obj1对象的age属性 10 11 obj2 = Foo('alex', 73) 12 print obj2.name # 直接调用obj2对象的name属性 13 print obj2.age # 直接调用obj2对象的age属性
2、通过self间接调用
执行类中的方法时,需要通过self间接调用被封装的内容
1 class Foo: 2 3 def __init__(self, name, age): 4 self.name = name 5 self.age = age 6 7 def detail(self): 8 print self.name 9 print self.age 10 11 obj1 = Foo('wupeiqi', 18) 12 obj1.detail() # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18 13 14 obj2 = Foo('alex', 73) 15 obj2.detail() # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 alex ; self.age 是 78
注:综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。
封装的数据可以是任意类型的包括对象本身
1 class c1(): 2 def __init__(self,name, obj): 3 self.name = name 4 self.obj = obj 5 6 7 class c2(): 8 def __init__(self, name, age): 9 self.name = name 10 self.age = age 11 12 def show(self): 13 return self.name 14 15 class c3(): 16 def __init__(self, a1): 17 self.money = 123 18 self.a1 = a1 19 20 21 c2_obj = c2('gouyc', 18) 22 c1_obj = c1('alex', c2_obj) 23 c3_obj = c3(c1_obj) 24 25 print(c3_obj.a1.name)
注:将c2_obj对象封装到c1_obj中,执行c1对象可以获得c2对象的字段.
补充:使用pickle.load对象时,一定要先导入对应的类,否则会报错
二、继承
- 通过继承,子类可以获得父类的方法和字段.
- 子类可以重写父类的方法(如果子类中有和父类同样的方法,那么子类的方法生效)这叫重写
- 一个子类可以继承多个父类
- 继承相当于是把父类的方法拿到子类中。
单继承、
1 class F1: 2 def show(self): 3 print('F1-show') 4 5 def foo(self): 6 print(self.name) 7 8 class F2(F1): 9 def __init__(self, name): 10 self.name = name 11 12 def bar(self): 13 print('bar') 14 15 def show(self): #重写父类的show方法 16 print('F2-show') 17 18 obj = F2('alex') 19 obj.show()
如果一个类继承了另一个类,在执行类方法时,优先级是先去自己的类中查找方法,如果没有就到父类中寻找,如果父类的方法又调用了自己的方法,而这个方法同时存在于子类和父类当中,那么有两个可能:
- 对象是由子类初始化的,那么就执行子类的方法
- 对象是由父类初始化的,那么就执行父类的方法
1 class S1: 2 def F1(self): 3 self.F2() 4 5 def F2(self): 6 print('from S1.F2') 7 8 class S2(S1): 9 10 def F3(self): 11 self.F1() 12 13 def F2(self): 14 print('from S2.F2') 15 16 obj = S2() 17 obj.F2() 18 19 结果: 20 from S2.F2
1 class S1: 2 def F1(self): 3 self.F2() 4 5 def F2(self): 6 print('from S1.F2') 7 8 class S2(S1): 9 10 def F3(self): 11 self.F1() 12 13 def F2(self): 14 print('from S2.F2') 15 16 obj = S1() 17 obj.F2() 18 19 结果: 20 from S1.F2
多继承(python支持,其他语言不一定支持)、
1 class C1: 2 def f1(self): 3 pass 4 5 class C2: 6 7 def f2(self): 8 pass 9 10 class C3(C2, C1): 11 12 def f3(self): 13 pass 14 15 obj = C3() 16 obj.f1() 17 obj.f2() 18 obj.f3()
注意:上面代码中,c3继承了c2和c1,那么执行obj=c3()时,我们可以调用父类的两个方法,如果两个父类有相同的方法时,会执行哪个呢?
1 class C1: 2 def f2(self): 3 pass 4 5 class C2: 6 7 def f2(self): 8 pass 9 10 class C3(C2, C1): 11 12 def f3(self): 13 pass 14 15 obj = C3() 16 obj.f2() 17 18 结果: 19 from C2.f2
注意:如果子类继承了多个父类,两个父类中有相同的方法时,继承顺序是从左到右,先到c3中寻找f2,没有则到c2中寻找,如果c2中有f2时,就停止寻找,如果c2中没有f2时,就在c1中找。
1 class C0: 2 def f2(self): 3 print('from C0.f2') 4 5 class C1(C0): 6 def f1(self): 7 print('from C1.f1') 8 9 class C2: 10 def f2(self): 11 print('from C2.f2') 12 13 class C3(C1, C2): 14 15 def f3(self): 16 pass 17 18 obj = C3() 19 obj.f2()
1 class C0: 2 def f5(self): 3 print('from C0.f5') 4 5 class C1(C0): 6 def f1(self): 7 print('from C1.f1') 8 9 class C2: 10 def f2(self): 11 print('from C2.f2') 12 13 class C3(C1, C2): 14 15 def f3(self): 16 pass 17 18 obj = C3() 19 obj.f2() 20 21 结果: 22 from C2.f2
- 先到c3类中查找f2,如果没有
- 在到c1中查找f2,如果没有
- 在到c0中查找f2,一直找到最上层的父类,有就执行,没有的话
- 在到c2中查找f2执行。
注意:在python3.x中没有广度优先了。
如果父类没有继承共同的父类的时候,那么继承顺序是一条路走到黑。
1 class C0(): 2 def f2(self): 3 print('from C0.f2 ') 4 5 class C1(C0): 6 def f1(self): 7 print('from C1.f1') 8 9 10 class C2(): 11 def f2(self): 12 print('from C2.f2') 13 14 15 class C3(C1, C2): 16 17 def f3(self): 18 pass 19 20 obj = C3() 21 obj.f2()
c3类继承了c1和c2类,而父类c1继承了c0,另一个父类c2没有继承。这种关系叫父类没有继承共同的父类
如果父类又继承了共同的父类,查找方式是:
1 class C0(): 2 def f2(self): 3 print('from C0.f2 ') 4 5 class C1(C0): 6 def f1(self): 7 print('from C1.f1') 8 9 10 class C2(C0): 11 def f2(self): 12 print('from C2.f2') 13 14 15 class C3(C1, C2): 16 17 def f3(self): 18 pass 19 20 obj = C3() 21 obj.f2() 22 23 结果: 24 from C2.f2