python学习之路——基础篇(3)模块(续)

时间:2022-01-26 08:42:57

re正则表达式、shutil、ConfigParser、xml

一、re

  • 正则元字符和语法:
语法 说明   表达式 完全匹配字符
          字符
一般字符   匹配自身 abc   abc
. 匹配除换行符“\n”外,任意一个字符 a.c abc
\       转义字符,将特殊字符转义为本身

a\.c

a\\c

a.c

a\c

[...]

匹配字符集任意一个字符,或者“-”表示一个集合范围

如:[a-zA-Z0-9]匹配范围中任意一个字符;或者[^]

匹配否定,对括号中的内容取反。

[abc]efg

aefg

befg

cefg

         预定义字符集
\d 数字:[0-9] a\dc a1c
\D 非数字:[^\d] a\Dc abc
\s 空白字符:[<空格>\t\r\n\f\v] a\sc a c
\S 非空白字符:[^\s] a\Sc abc
\w 字符:[a-zA-Z0-9_]   a\wc abc
\W  非单词字符:[^\w] a\Wc a c
                           数量词
*   匹配前一个字符0次或无数次 a*b

aab

ab

b

+   匹配前一个字符1次或无数次 a+b

aab

aaaab

? 匹配前一个字符0次或1次 a?b

b

ab

{m} 匹配前一个字符m次 a{2}c aac
{m,n}

匹配前一个字符m次到n次。m与n可以省略

如果省略m,表示0次到n次;省略n表示从m次到

无数次

a{1,2}c

ac

aac

*? +? ??

{m,n}?

使*、+、?、{m,n}变为非贪婪模式 见后文
                    边界匹配
^ 匹配字符串开头 ^abc abc
$ 匹配字符串结尾 abc$ abc
\A 仅匹配字符串开头 \Aabc abc
\Z 仅匹配字符串结尾 abc\Z abc
\b
匹配一个单词边界,也就是指单词和空格间的位置。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”
ab\b ab
\B
匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”
ab\Bc abc
                    逻辑与分组
|

代表左右表达式任意匹配一个。

它总是先匹配左边的,一旦匹配成功,则跳过右边表达式。

如果|没有被包含在()中,他的范围将是整个表达式。

abc|def

abc

def

()

被括号括起来的表达式将视为分组。

从表达式左边开始,每遇到一个分组的左括号“(“,编号+1

分组表达式作为一个整体,可以后接数量词。表达式中|仅在分组中生效。

(abc){2}

(abc|bcd)

abcabc

abc

(?P<name>...) 分组,除了原有编号外,再指定一个别名。group(1)=group(name) (?P<id>abc) abc
(?P=name)引用别名为name的分组匹配到的字符串(?P<id>123)abc(?P=id)123abc123
  • 数量词的贪婪模式与非贪婪模式

  正则表达式通常用于在文本中查找匹配的字符串。Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪的则相反,总是尝试匹配尽可能少的字符。例如:正则表达式"ab*"如果用于查找"abbbc",将找到"abbb"。而如果使用非贪婪的数量词"ab*?",将找到"a"。

  • 反斜杠的困扰

  与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。同样,匹配一个数字的"\\d"可以写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。

  • re相关匹配方法
  1. match

    match,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None

    

 import re

 text="the Attila the Hun show"
m = re.match(".",text)
print(m.group()) #"t" 或者group(0)取得匹配所有结果 m = re.match("(.)(.)(.)",text)
print(m.group(0)) #"the" #分组
print(m.group(1,2,3)) #('t','h','e') 匹配后得分组 #将正则编译成Pattern对象
pattern = re.compile(".")
m = pattern.match(text)
print(m.group()) #'t'

  2. search

    search, 浏览整个字符串去匹配第一个,未匹配成功返回None

 import re
text = "Example 3:there is 1 date 11/5/2016 in here"
m = re.search("(\d{1,2})/(\d{1,2})/(\d{2,4})",text)
print(m.group(1),m.group(2),m.group(3))# 11 5 2016

3. sub

    替换匹配成功的指定位置字符串

 import re
# sub(pattern, repl, string, count=0, flags=0)
# pattern: 正则模型
# repl : 要替换的字符串或可执行对象
# string : 要匹配的字符串
# count : 指定匹配个数
# flags : 匹配模式
text = "you're no fun anymore fun"
m = re.sub("fun","entertaining",text,2)
print(m)
# "you're no entertaining anymore entertaining"

4. spilt

          根据正则匹配分隔字符串

import re
# split(pattern, string, maxsplit=0, flags=0)
# pattern: 正则模型
# string : 要匹配的字符串
# maxsplit:指定分割个数
# flags : 匹配模式 # 无分组
origin = "hello alex bcd alex lge alex acd 19"
r = re.split("alex", origin, 1)
print(r) #["hello","bcd alex lge alex acd 19"] # 有分组
origin = "hello alex bcd alex lge alex acd 19"
r1 = re.split("(alex)", origin, 1)
print(r1) # ["hello","alex","bcd alex lge alex acd 19"] r2 = re.split("(al(ex))", origin, 1)
print(r2) # ["hello","alex","ex","bcd alex lge alex acd 19"]

5. findall

    获取非重复的匹配列表;如果有一个组则以列表形式返回,且每一个匹配均是字符串;如果模型中有多个组,则以列表形式返回,且每一个匹配均是元祖;

    空的匹配也会包含在结果中
 # 无分组
origin = "hello alex bcd abcd lge acd 19"
r = re.findall("a\w+",origin)
print(r) # ["alex","abcd","acd"] # 有分组
origin = "hello alex bcd abcd lge acd 19"
r = re.findall("a((\w*)c)(d)", origin)
print(r) # 匹配两个字符串"abcd"&"acd"先将匹配最外层分组的元素放入元祖#中,再将内层分组匹配的元素放入元祖中结果[("bc","b","d"),("c","","d")]
IP:
^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$
手机号:
^1[3|4|5|8][0-9]\d{8}$
邮箱:
[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+

二、shutil

高级文件、文件夹、压缩包处理模块

  1. 将文件内容拷贝到另一个文件

    shutil.copyfileobj(fsrc, fdst[, length])

 import shutil
shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))

  2. 拷贝文件

    shutil.copyfile(src, dst)

 shutil.copyfile('f1.log', 'f2.log')

  3. 仅拷贝权限。内容、组、用户均不变

    shutil.copymode(src, dst)

 shutil.copymode('f1.log', 'f2.log')

  4. 仅拷贝状态的信息,包括:mode bits, atime, mtime, flags

    shutil.copystat(src, dst)

 shutil.copystat('f1.log', 'f2.log')

  5. 拷贝文件和权限

    shutil.copy(src, dst)

 shutil.copy('f1.log', 'f2.log')

  6. 拷贝文件和状态信息

    shutil.copy2(src, dst)

 shutil.copy2('f1.log', 'f2.log')

  7. 递归的去拷贝文件夹

    shutil.ignore_patterns(*patterns) 忽略某些格式文件
    shutil.copytree(src, dst, symlinks=False, ignore=None)

 import shutil
shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
 import shutil
shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))

 8. 递归的去删除文件

    shutil.rmtree(path[, ignore_errors[, onerror]])

 import shutil
shutil.rmtree('folder1')

  9. 递归的去移动文件,它类似mv命令,其实就是重命名。

    shutil.move(src, dst)

 import shutil
shutil.move('folder1', 'folder3')

  10. 创建压缩包并返回文件路径,例如:zip、tar

    shutil.make_archive(base_name, format,...) 这个功能只能压缩一个文件夹

  • base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,如:www =>保存至当前路径如:/Users/lcy/www =>保存至/Users/lcy/
  • format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
  • root_dir: 要压缩的文件夹路径(默认当前目录)
  • owner: 用户,默认当前用户
  • group: 组,默认当前组
  • logger: 用于记录日志,通常是logging.Logger对象
#将 /Users/lcy/Downloads/test 下的文件打包放置当前程序目录
import shutil
ret = shutil.make_archive("www", 'gztar', root_dir='/Users/lcy/Downloads/test')
#将 /Users/lcy/Downloads/test 下的文件打包放置 /Users/lcy/目录
import shutil
ret = shutil.make_archive("/Users/lcy/www", 'gztar', root_dir='/Users/lcy/Downloads/test')

附加:ZipFile 和 TarFile一般用这个较多

 import zipfile

 # 压缩
z = zipfile.ZipFile('laxi.zip', 'w') #创建一个压缩包 如果以“a”模式打开 追加 在已存在追加文件放入压缩包
z.write('a.log') #将文件写到这个压缩包中
z.write('data.data')
z.close()
# 解压
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall() #解压全部
z.close()
 # 解压 单个文件
z= zipfile.ZipFile("la.zip","r")
for item in z.namelist(): # 将打印出压缩包中成员文件
print(item)
z.extract(member) #根据item 解压某个文件名
z.close()

tarfile模块

 import tarfile

 # 压缩
tar = tarfile.open('your.tar','w')
tar.add('/Users/wupeiqi/PycharmProjects/bbs2.log', arcname='bbs3.log')# arcname 改压缩文件的名字
tar.add('/Users/wupeiqi/PycharmProjects/cmdb.log', arcname='cmdb2.log')
tar.close() # 解压
tar = tarfile.open('your.tar','r')
tar.extractall() # 可设置解压地址
#tar.getmembers() 来获取压缩包中的成员,返回是所有成员对象类型为tarfile.TarInfo;获取某个文件名对象obj=tar.getmeber("文件名")然后tar.extract(obj)解压单个文件
tar.close()

三、ConfigParse

  configparser用于处理特定格式的文件,其本质上是利用open来操作文件。

#指定格式文件如下
[section1] # 节点
k1 = v1 # 值
k2:v2 # 值 [section2] # 节点
k1 = v1 # 值
  1. 获取所有节点
 import configparser

 config = configparser.ConfigParser()
config.read('xxxooo', encoding='utf-8')
ret = config.sections()
print(ret)

  2. 获取指定节点下所有的键值对

 import configparser

 config = configparser.ConfigParser()
config.read('conf', encoding='utf-8')
ret = config.items('section1')

  3. 获取指定节点下所有的建

import configparser

config = configparser.ConfigParser()
config.read('conf', encoding='utf-8')
ret = config.options('section1')
print(ret)

  4. 获取指定节点下指定key的值

 import configparser

 config = configparser.ConfigParser()
config.read('conf', encoding='utf-8') v = config.get('section1', 'k1')
# v = config.getint('section1', 'k1')
# v = config.getfloat('section1', 'k1')
# v = config.getboolean('section1', 'k1')

  5. 检查、删除、添加节点

 import configparser

 config = configparser.ConfigParser()
config.read('conf', encoding='utf-8') # 检查
has_sec = config.has_section('section1')
print(has_sec) # 添加节点
config.add_section("SEC_1")
config.write(open('conf', 'w')) # 删除节点
config.remove_section("SEC_1")
config.write(open('conf', 'w'))

  6. 检查、删除、设置指定组内的键值对

import configparser

config = configparser.ConfigParser()
config.read('conf', encoding='utf-8') # 检查
has_opt = config.has_option('section1', 'k1')
print(has_opt) # 删除
config.remove_option('section1', 'k1')
config.write(open('conf', 'w')) # 设置
config.set('section1', 'k10', "")
config.write(open('conf', 'w')) # 从内存写到文件

四、XML

xml文件格式:

<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2023</year>
<gdppc>141100</gdppc>
<neighbor direction="E" name="Austria" />
<neighbor direction="W" name="Switzerland" />
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2026</year>
<gdppc>59900</gdppc>
<neighbor direction="N" name="Malaysia" />
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2026</year>
<gdppc>13600</gdppc>
<neighbor direction="W" name="Costa Rica" />
<neighbor direction="E" name="Colombia" />
</country>
</data>
 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 节点功能一览表

func

  1. 解析xml文件  
  • 解析文件为xml对象
 from xml.etree import ElementTree as ET

 # 直接解析xml文件
tree = ET.parse("xo.xml") # 获取xml文件的根节点
root = tree.getroot()
  • 解析字符串
 from xml.etree import ElementTree as ET

 # 打开文件,读取XML内容
str_xml = open('xo.xml', 'r').read() # 将字符串解析成xml特殊对象,root代指xml文件的根节点
root = ET.XML(str_xml)

  2. 操作xml

  •   遍历xml所有节点
 from xml.etree import  ElementTree as ET

 ## 打开xml文件 通过返回对象tree进行相关操作
tree = ET.parse("xo.xml") tree =>ElementTree
#
##获取根节点 root可以获取相关节点属性 tag为根节点名字 节点属性attrib 标签中间的值<xml>text</xml>
root = tree.getroot()
print(root,root.tag,root.attrib)
#
#遍历节点
for child in root:
print(child, child.tag, child.attrib)
for grandechild in child:
print(grandechild, grandechild.tag, grandechild.attrib,grandechild.text)
  • 遍历指定节点,删除修改等
   # 解析字符串形式 得到一个 xml对象
# 打开文件,读取XML内容
str_xml = open('xo.xml', 'r').read() # 将字符串解析成xml特殊对象,root代指xml文件的根节点
root = ET.XML(str_xml) ############ 操作 ############ # 顶层标签
print(root.tag) # 循环所有的year节点
for node in root.iter('year'):
# 将year节点中的内容自增一
new_year = int(node.text) +
node.text = str(new_year) # 设置属性
node.set('name', 'alex')
node.set('age', '')
# 删除属性
del node.attrib['name']
############ 保存文件 ############
tree = ET.ElementTree(root)
tree.write("newnew.xml", encoding='utf-8') # 只有tree 才有write 写操作 《=所以无论是文件操作还是字符串形式xml

  3. 创建xml

  • SubElement
  • Element与append也可以创建
  • makeElement与append 也可以自己创建
 from xml.etree import ElementTree as ET

 from xml.dom import minidom

 def prettify(elem):
"""将节点转换成字符串,并添加缩进。
"""
rough_string = ET.tostring(elem, 'utf-8')
reparsed = minidom.parseString(rough_string)
return reparsed.toprettyxml(indent="\t")
# 创建根节点
root = ET.Element("famliy") # 创建节点大儿子
son1 = ET.SubElement(root, "son", attrib={'name': '儿1'})
# 创建小儿子
son2 = ET.SubElement(root, "son", attrib={"name": "儿2"}) # 在大儿子中创建一个孙子
grandson1 = ET.SubElement(son1, "age", attrib={'name': '儿11'})
grandson1.text = '孙子' #
#et = ET.ElementTree(root) #生成文档对象
#et.write("test.xml", encoding="utf-8", xml_declaration=True, short_empty_elements=False) # 调用缩进函数 所以得到的字符串就包含了缩进
raw_str = prettify(root) f = open("xxxoo.xml",'w',encoding='utf-8')
f.write(raw_str)
f.close()

makeelement

 from xml.etree import ElementTree as ET

 # 创建根节点
root = ET.Element("famliy") # 创建大儿子
# son1 = ET.Element('son', {'name': '儿1'})
son1 = root.makeelement('son', {'name': '儿1'})
# 创建小儿子
# son2 = ET.Element('son', {"name": '儿2'})
son2 = root.makeelement('son', {"name": '儿2'}) # 在大儿子中创建两个孙子
# grandson1 = ET.Element('grandson', {'name': '儿11'})
grandson1 = son1.makeelement('grandson', {'name': '儿11'})
# grandson2 = ET.Element('grandson', {'name': '儿12'})
grandson2 = son1.makeelement('grandson', {'name': '儿12'}) son1.append(grandson1)
son1.append(grandson2) # 把儿子添加到根节点中
root.append(son1)
root.append(son1) tree = ET.ElementTree(root)
tree.write('oooo.xml',encoding='utf-8', short_empty_elements=False)

makeelement

Element

 from xml.etree import ElementTree as ET

 # 创建根节点
root = ET.Element("famliy") # 创建节点大儿子
son1 = ET.Element('son', {'name': '儿1'})
# 创建小儿子
son2 = ET.Element('son', {"name": '儿2'}) # 在大儿子中创建两个孙子
grandson1 = ET.Element('grandson', {'name': '儿11'})
grandson2 = ET.Element('grandson', {'name': '儿12'})
son1.append(grandson1)
son1.append(grandson2) # 把儿子添加到根节点中
root.append(son1)
root.append(son1) tree = ET.ElementTree(root)
tree.write('oooo.xml',encoding='utf-8', short_empty_elements=False)

Element