上下文管理器——理解 Python with 关键字
原文:https://www.askpython.com/python/python-with-context-managers
Python with
语句是一个非常有用的。这从 Python 2.5 开始就有了,现在几乎每个 Python 应用程序都在使用它!
这个说法到底有什么用,以至于大家都用?
最有用的东西(事实上唯一的东西!)它所做的就是打开并释放资源。
基本上,它处理打开和关闭程序特定部分可能需要使用的任何资源,并在之后自动关闭它。
现在,让我们用一些例子来更详细地看看这个陈述。
为什么我们需要上下文管理器?
考虑您处理文件的场景。在其他语言中,比如 C,我们必须像这样手动打开和关闭文件:
# Open the file
file_obj = open('input.txt', 'r')
# File operations come here
...
# Manually close the file
file_obj.close()
现在,with
语句会自动为您提取这些内容,这样就不需要每次都手动关闭文件了!
with
语句有一个上下文(块),在这个上下文中它起作用。这个这个作为声明的范围。
当程序从这个上下文中出来,with
自动关闭你的文件!
因此,with
通常被称为上下文管理器。
因此,可以像这样使用相同的文件处理过程,以及with
语句:
with open('input.txt', 'r') as file_obj:
...
注意这是多么的直观。Python with
语句将总是在最后关闭文件,即使程序在上下文/块中异常终止。
这个安全特性使它成为所有 Python 程序员接受的(也是推荐的)选择!
使用 Python with 语句
现在,虽然有很多类已经实现了使用with
的工具,我们还是想看看它是如何工作的,这样我们就可以自己写一个了!
- 首先,
with
语句在一个上下文对象中存储一个对象引用。
上下文对象是包含关于其状态的额外信息的对象,例如模块/范围等。这很有用,因为我们可以保存或恢复该对象的状态。
所以,保持对对象的引用是有意义的!
现在,让我们继续。一旦创建了上下文对象,它就调用对象上的__enter__
dunder 方法。
__enter__
语句是真正为对象打开资源的语句,比如文件/套接字。通常,如果需要,我们可以实现它来保存上下文对象状态。
现在,还记得as
关键字吗?这实际上返回了上下文对象。因为我们需要由 open() 返回的对象,所以我们使用as
关键字来获取上下文对象。
使用as
是可选的,特别是如果您在其他地方有对原始上下文对象的引用。
之后,我们进入嵌套语句块。
一旦嵌套块或结束,如果其中有异常,程序总是对上下文对象执行__exit__
方法!
这就是我们之前谈到的安全第一的特性。所以不管发生什么,我们都会一直使用__exit__
来释放资源,退出上下文。
最后,如果可行的话,__exit__
可以被实现,以便恢复上下文对象状态,使得它回到它所属的任何状态。
好吧,那是一个相当长的解释。为了更清楚,让我们看一个为类创建我们自己的上下文管理器的例子。
为我们的类创建自己的上下文管理器
考虑下面的类,我们将有自己的上下文管理器来处理文件。
class MyFileHandler():
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
# Originally, context object is None
self.context_object = None
# The context manager executes this first
# Save the object state
def __enter__(self):
print("Entered the context!")
self.context_object = open(self.filename, self.mode)
return self.context_object
# The context manager finally executes this before exiting
# Information about any Exceptions encountered will go to
# the arguments (type, value, traceback)
def __exit__(self, type, value, traceback):
print("Exiting the context....")
print(f"Type: {type}, Value: {value}, Traceback: {traceback}")
# Close the file
self.context_manager.close()
# Finally, restore the context object to it's old state (None)
self.context_object = None
# We're simply reading the file using our context manager
with MyFileHandler('input.txt', 'r') as file_handle:
for line in file_handle:
print(line)
仔细观察类方法。我们的处理程序有__init__
方法,它设置上下文对象和相关变量的初始状态。
现在,__enter__
dunder 方法保存对象状态并打开文件。现在,我们在街区里面。
在块执行之后,上下文管理器最后执行__exit__
,在那里上下文对象的原始状态被恢复,并且文件被关闭。
好的,现在让我们检查一下我们的输出。这个应该管用!
输出
Entered the context!
Hello from AskPython
This is the second line
This is the last line!
Exiting the context....
Type: None, Value: None, Traceback: None
好的,看起来我们没有错误!我们刚刚为自定义类实现了自己的上下文管理器。
现在,有另一种创建上下文管理器的方法,它使用生成器。
然而,这有点不方便,一般不推荐,除非你确切地知道自己在做什么,因为你必须自己处理异常。
但是,为了完整起见,您可以在这里看一下使用这种方法。一旦你熟悉了基于类的方法,我会推荐你阅读这篇文章。
结论
在本文中,我们通过使用with
语句学习了如何在 Python 中使用上下文管理器。
参考
Python 写文件
原文:https://www.askpython.com/python/built-in-methods/python-write-file
我们之前已经看到如何用 Python 从文件中读取 。类似的写文件也可以在 Python 编程中实现。但是,在我们开始写入文件之前,我们必须确保打开文件的模式允许这样做。让我们来看看使用哪些模式我们可以实际写入一个文件。
w
–打开文件进行写入,如果文件不存在,则创建一个文件。w+
–打开文件进行读写,a
–打开文件进行追加。数据被附加到文件的末尾,x
–以写入和读取模式创建新文件,r+
–打开文件进行读写。
现在,让我们看看如何使用不同的方法在 Python 中写入文件。
1.Python 使用 Write()函数写文件
使用write()
函数,我们实际上可以直接将一个字符串(作为参数传递)写到一个文件中。
file = open("new_file.txt", "w+")
file.write('Using the write() method')
file.seek(0)
print(file.read())
输出:
Using the write() method
Output: new_file.txt is created
2.在 Python 中使用 writelines()
writelines()
是 Python 中另一个预定义的方法,用于将多行写入一个特定的文件,并以一个字符串元素的列表作为参数传递。
list1=['字符串 1 ','字符串 2 ',……,'字符串 n ']
file _ open _ object . writelines(list 1)
list1=['Python\n','C\n','C++\n','Java']
file=open("new_file.txt", "w+")
file.writelines(list1)
file.seek(0)
print(file.read())
输出:
Python
C
C++
Java
参考文献:
Python XML 解析器
原文:https://www.askpython.com/python/examples/python-xml-parser
有没有遇到过令人讨厌的 XML 文件,需要解析它才能获得重要的值?让我们学习如何创建一个 Python XML 解析器。
<page>
<header>
<type heading="XML Parsing in Python"/>
<type text="Hello from AskPython. We'll be parsing XML"/>
</header>
</page>
我们将看看如何使用 Python 来解析这样的 XML 文件,以获得相关的属性和值。
我们开始吧!
方法 1:使用 ElementTree(推荐)
我们可以使用 ElementTree Python 库来实现这个任务。
这是构建 Python XML 解析器的最简单和推荐的选择,因为这个库在默认情况下与 Python 捆绑在一起。
它不仅提供了方便的访问,因为它已经安装,而且它也相当快。让我们看看如何从测试文件中提取属性。
<page>
<header>
<type heading="XML Parsing in Python"/>
<type text="Hello from AskPython. We'll be parsing XML"/>
</header>
</page>
我们将在核心xml
包中使用xml.etree.ElementTree
接口。
import xml.etree.ElementTree as ET
构建 Python XML 解析器树
让我们首先构造这个解析树的根节点。这是树的最顶层节点,是我们开始解析所必需的。
谢天谢地,这个 API 已经为我们提供了下面的方法:
import xml.etree.ElementTree as ET
root_node = ET.parse('sample.xml').getroot()
print(root_node)
这将自动读取 XML 输入文件,并为我们获取根节点。
输出
<Element 'page' at 0x7f885836b2f0>
好的,看起来它已经被解析了。但是我们还无法证实。因此,让我们解析其他属性,并尝试获取其值。
获取相关属性的值
所以现在,我们的任务是使用 Python XML 解析器获取<heading>
属性中的值。
它在根节点<page>
的位置是<header/type>
,所以我们需要遍历树的该层的所有匹配。
我们可以使用root_node.findall(level)
来实现,其中电平是期望的位置(在我们的例子中是<header/type>
)。
for tag in root_node.find_all(level):
value = tag.get(attribute)
if value is not None: print(value)
在我们正在搜索的级别上,tag.get(attribute)
将获得我们的<attribute>
标签的值。所以,我们只需要在<header/type>
做这件事,并获得<heading>
和<text>
属性的值。就是这样!
import xml.etree.ElementTree as ET
# We're at the root node (<page>)
root_node = ET.parse('sample.xml').getroot()
# We need to go one level below to get <header>
# and then one more level from that to go to <type>
for tag in root_node.findall('header/type'):
# Get the value of the heading attribute
h_value = tag.get('heading')
if h_value is not None:
print(h_value)
# Get the value of the text attribute
t_value = tag.get('text')
if t_value is not None:
print(t_value)
输出
XML Parsing in Python
Hello from AskPython. We'll be parsing XML
我们已经检索了 XML 解析树中该层的所有值!我们已经成功解析了 XML 文件。
再举一个例子,为了搞清楚一切。
现在,假设 XML 文件如下所示:
<data>
<items>
<item name="item1">10</item>
<item name="item2">20</item>
<item name="item3">30</item>
<item name="item4">40</item>
</items>
</data>
这里,我们不仅要获得name
的属性值,还要获得该级别的每个元素的文本值 10、20、30 和 40。
要得到name
的属性值,我们可以像之前一样。我们也可以使用tag.attrib[name]
来获取值。这与tag.get(name)
相同,除了它使用字典查找。
attr_value = tag.get(attr_name)
# Both methods are the same. You can
# choose any approach
attr_value = tag.attrib[attr_name]
要得到文本值,很简单!只需使用:
tag.text
因此,我们这个解析器的完整程序将是:
import xml.etree.ElementTree as ET
# We're at the root node (<page>)
root_node = ET.parse('sample.xml').getroot()
# We need to go one level below to get <items>
# and then one more level from that to go to <item>
for tag in root_node.findall('items/item'):
# Get the value from the attribute 'name'
value = tag.attrib['name']
print(value)
# Get the text of that tag
print(tag.text)
输出
item1
10
item2
20
item3
30
item4
40
对于任意长的 XML 文件,您也可以将这种逻辑扩展到任意级别!您还可以向另一个 XML 文件中写入一个新的解析树。
但是,我将让您从文档中找出答案,因为我已经为您提供了一个构建的起点!
方法 2:使用 BeautifulSoup(可靠)
如果由于某种原因,源 XML 的格式不正确,这也是另一个不错的选择。如果不对文件做一些预处理,XML 可能不能很好地工作。
事实证明, BeautifulSoup 对所有这些类型的文件都非常适用,所以如果您想解析任何类型的 XML 文件,请使用这种方法。
要安装它,使用pip
并安装bs4
模块:
pip3 install bs4
我将为您提供我们之前的 XML 文件的一个小片段:
<data>
<items>
<item name="item1">10</item>
<item name="item2">20</item>
<item name="item3">30</item>
<item name="item4">40</item>
</items>
</data>
我将传递这个文件,然后使用bs4
解析它。
from bs4 import BeautifulSoup
fd = open('sample.xml', 'r')
xml_file = fd.read()
soup = BeautifulSoup(xml_file, 'lxml')
for tag in soup.findAll("item"):
# print(tag)
print(tag["name"])
print(tag.text)
fd.close()
语法类似于我们的xml
模块,所以我们仍然使用value = tag['attribute_name']
和text = tag.text
来获取属性名。和以前一模一样!
输出
item1
10
item2
20
item3
30
item4
40
我们现在已经用bs4
解析过了!如果您的源文件XML
格式不正确,这种方法是可行的,因为 BeautifulSoup 有不同的规则来处理这样的文件。
结论
希望您现在已经很好地掌握了如何轻松构建 Python XML 解析器。我们向您展示了两种方法:一种使用xml
模块,另一种使用 BeautifulSoup 。
参考
- 关于解析 XML 的 StackOverflow 问题
- XML 模块文档
了解 Python xrange()方法
原文:https://www.askpython.com/python/built-in-methods/python-xrange-method
今天在本教程中,我们将讨论 Python xrange()方法。
xrange()
方法仅在 Python 2.x 版本中可用,并用于遍历或迭代序列的循环中。
Python xrange()方法的基础
Python xrange()
方法返回一个xrange
类型的对象,它是一个不可变的序列,通常用于循环。这些对象行为很少,只支持索引、迭代和len()
功能。
xrange(start, stop[, step])
这里:
- **start(可选)**是序列生成的起始点。它被包括在序列中,并且如果没有被提及,则默认设置为 0 ,
- stop 是序列生成停止之前的数字(不含),
- **step(可选)**是函数在序列生成或迭代时将采取的跳转步骤。默认情况下,它的值为 1 。
使用 Python xrange()方法
现在让我们看看实际使用 Python xrange()
方法的各种方式。
1.只有停止参数
两个参数step
和start
是可选的,因为它们分别具有默认值 1 和 0 。因此,我们可以通过指定stop
参数来使用 Python xrange()
方法。
仅提及停止时,xrange()
功能创建一个从 0 到**(停止-1)** 的序列,步长为 1 。看看下面的例子。
# xrange() with only stop parameter
x = xrange(4)
print "Type of returned object = ", type(x)
print "Sequence generated by xrange() 1 parameter: ", list(x)
输出:
Type of returned object = <type 'xrange'>
Sequence generated by xrange() 1 parameter: [0, 1, 2, 3]
这里,该方法生成的序列类型是前面提到的类型xrange
。将xrange()
输出类型转换成一个列表给我们一个包含值 0 到 3(4-1) 和步骤 1 的列表。
2.带有开始和停止参数
同样,我们也可以使用带有两个参数的 Python xrange()
方法。在这种情况下,默认情况下,step
的值为 1 。
# xrange() with start & stop parameters
x = xrange(2, 9)
print "Type of returned object = ", type(x)
print "Sequence generated by xrange() 2 parameters: ", list(x)
输出:
Type of returned object = <type 'xrange'>
Sequence generated by xrange() 2 parameters: [2, 3, 4, 5, 6, 7, 8]
从上面的输出中我们可以看到,Python xrange
对象这次包含了从 **2(开始)**到 8(停止-1) 的值,默认步长为 1。
3.具有所有开始、停止和停止值
当提到所有的参数时,Python xrange()
函数给我们一个xrange
对象,其值的范围从开始到停止-1 ,就像前一个例子一样。但是这一次,从一个元素跳到另一个元素等于通过了step
。
仔细看看下面的例子。这里我们考虑了步长为 5 ,开始=5 ,停止=40 。
# xrange() with 3 parameters
x = xrange(5, 40, 5) #positive step
y = xrange(9, 1, -1) #negative step
print "Sequences generated for 3 parameters by xrange"
print "x : ", list(x)
print "y : ", list(y)
输出:
Sequences generated for 3 parameters by xrange
x : [5, 10, 15, 20, 25, 30, 35]
y : [9, 8, 7, 6, 5, 4, 3, 2]
从输出可以清楚地看出,序列是用范围 5 到 39(40-1) 内的值生成的。对于最后一个元素,因为 40 超过了stop-1
标记,所以不认为是**。**
在循环中使用 Python xrange()
如前所述,xrange()
在 Python 2 中的for
循环结构中被广泛使用。例如,在下面的代码中,我们尝试打印数字 10 的表格。
# using xrange in loops
print "Table of 10: "
for i in xrange(10, 101, 10):
print i
输出:
Table of 10:
10
20
30
40
50
60
70
80
90
100
这里,我们提到了start=10
、stop=101
和step=10
。Stop 被认为是 101 ,因为我们希望序列包含 100(100-1) 元素。正如我们所看到的,我们得到了从 10 到 100 的所有 10 的倍数。
因此,输出是合理的。
Python xrange()与 range()
通常,xrange()
只在用户希望他/她的代码只为 Python 2.x 版本设计时使用,因为它不适用于 Python 3.x 版本。对于 Python 3 ,range()
方法代替了xrange()
方法。
这两个函数的主要区别在于,它们都返回具有不同属性的不同对象。
xrange()
方法返回一个xrange
对象,它是一个不可变的序列,只支持前面提到的迭代、索引和 len 函数。
另一方面,range()
方法返回一个支持主要函数的列表,如切片、 pop() 等。
# xrange() vs range()
x = xrange(1, 10)
y = range(1, 10)
print "Type(x) = ", type(x)
print "Type(y) = ", type(y)
输出:
Type(x) = <type 'xrange'>
Type(y) = <type 'list'>
此外,xrange
对象在我们需要以最小的空间复杂度构建代码时更有用,因为它占用相当恒定的内存大小,与它存储的值的范围无关。
如果你想写一个可以在 Python 2 和 3 上运行或执行的程序,使用range()
方法更有意义,因此推荐使用。
结论
所以在本教程中,我们了解了 Python xrange()
方法的工作和使用。
如有任何问题,欢迎在下面的评论中提问。
参考
- Python range()方法,
- Python 2 中的 range 和 xrange 函数有什么区别?x?–stack overflow 问题。
Python Yagmail 模块——发送电子邮件的简单方法!
原文:https://www.askpython.com/python/examples/python-yagmail-module
读者朋友们,你们好!本文主要关注 Python Yagmail 的实现,以便从我们的应用程序发送电子邮件。
所以,让我们开始吧!!🙂
Python Yagmail 模块是什么?
在目前的情况下,几乎每个企业都有一个在线设置。也就是说,他们有一个更好的销售和市场接触的在线存在。
网站收集的常见数据参数之一是客户的电子邮件地址。我们经常被要求使用我们的电子邮件地址注册网站/门户。
我们的电子邮箱里会收到广告,甚至是促销信息。他们不需要手动输入并向所有客户发送电子邮件。这意味着,以某种自动化的方式,通过门户/应用程序发送电子邮件的过程发生了。
这就是 Python Yagmail 模块出现的原因。使用 Python Yagmail 模块,我们可以通过集成了电子邮件模块的应用程序向客户发送电子邮件。
它利用简单的 Gmail,即 SMTP 客户端,以自动化和用户友好的方式发送电子邮件。我们只需要提供更少的细节,如电子邮件地址、邮件正文等。
该模块可以集成为任何零售或在线应用程序/门户的一部分,这可能是该模块的最佳使用案例。🙂
现在让我们来关注一下实现 Yagmail 模块的步骤!
使用 Python Yagmail 模块发送电子邮件的步骤
首先,我们需要在我们的工作站上安装 Python Yagmail 模块。
使用 pip 命令安装 Yagmail 模块:
pip install yagmail
Python Yagmail module – Installation
安装后,我们必须将模块安装到我们当前的 python 环境中。
import yagmail
一旦导入,我们需要向 Yagmail 模块提供一个帐户,用于验证和发送电子邮件给接收者。也就是说,我们向模块注册了一个用户。通过注册一个电子邮件地址,它使得该模块可以很容易地访问 SMTP 服务器来发送电子邮件。
语法:
yagmail.register('username', 'password')
- 如果我们不希望将密码等敏感数据作为参数,我们也可以创建一个. yagmail 文件,将您的敏感数据放入该文件,而不是直接将其作为参数公开。
既然我们已经注册了用户,现在是时候与 SMTP 客户机建立安全连接了。
我们可以使用下面的自定义命令-
yagmail.SMTP('username', receiver1, receiver2, subject, body)
- 用户名:发件人的电子邮件地址
- receiver:这包含了接收者的电子邮件地址。我们可以在这里添加多个收件人电子邮件地址。
- 主题:电子邮件的简洁标题
- 正文:电子邮件的内容
如果我们没有指定收件人的电子邮件地址,它会将电子邮件发送到发件人的地址。
一旦内容准备好了,我们就继续将内容发送到收件人的电子邮件地址。
为此,Yagmail 为我们提供了 send()函数。在这里,我们将所有内容、收件人的详细信息以及主题和正文打包在一起。
yagmail.send(to = [receiver1, receiver2, etc], subject=subject, contents=body)
贴出这个,我们只需要看着代码为你工作!!
通过 Python Yagmail 发送电子邮件
下面是 Python yagmail 模块的完整实现。您可以复制粘贴以下代码,在您的系统上尝试一下。确保您为计划使用的任何电子邮件地址启用了 SMTP 访问。大多数电子邮件提供商默认情况下会阻止 SMTP 访问,以防止未经授权的应用程序滥用。
import yagmail
yag_mail = yagmail.SMTP(user='[email protected]', password='password', host='smtp.gmail.com')
to= "[email protected]"
subject = "Welcome to Journaldev!!"
body = ["World of infinite knowledge"]
yag_mail.send(to=to, subject=subject, contents=body)
print("Email has been sent successfully to the receiver's address.")
结论
到此为止,我们已经结束了这个话题。如果你遇到任何问题,欢迎在下面评论。
更多与 Python 编程相关的帖子,请继续关注我们。
在那之前,学习愉快!!🙂
python yield–生成器函数真实例子
- Python yield 关键字用于创建一个生成器函数。
- yield 关键字只能在函数体内使用。
- 当函数包含 yield 表达式时,它会自动成为生成器函数。
- 生成器函数返回一个称为生成器的迭代器。
- 生成器控制生成器功能的执行。
- 当第一次调用 generator next()时,生成器函数开始执行。
- 当为生成器调用 next()方法时,它执行生成器函数来获取下一个值。该函数从它停止的地方执行,并且不执行完整的函数代码。
- 生成器在内部维护函数及其变量的当前状态,以便正确检索下一个值。
- 一般我们用 for-loop 从生成器函数中提取所有的值,然后逐个处理。
- 当函数返回大量数据时,生成器函数非常有用。我们可以用 yield 表达式只得到有限的一组数据,然后进行处理,再得到下一组数据。
Python 收益与回报
- 返回语句返回函数的值,然后函数终止。yield 表达式将函数转换成一个生成器,以逐个返回值。
- 当我们必须返回大量数据时,Python return 语句并不合适。在这种情况下,yield 表达式对于仅返回部分数据和节省内存非常有用。
Python yield 示例
假设我们有一个返回随机数列表的函数。
from random import randint
def get_random_ints(count, begin, end):
print("get_random_ints start")
list_numbers = []
for x in range(0, count):
list_numbers.append(randint(begin, end))
print("get_random_ints end")
return list_numbers
print(type(get_random_ints))
nums = get_random_ints(10, 0, 100)
print(nums)
输出:
<class 'function'>
get_random_ints start
get_random_ints end
[4, 84, 27, 95, 76, 82, 73, 97, 19, 90]
当“计数”值不太大时,它工作得很好。如果我们指定 count 为 100000,那么我们的函数将使用大量内存来存储列表中的那么多值。
在这种情况下,使用 yield 关键字创建一个生成器函数是有益的。让我们将函数转换为生成器函数,并使用生成器迭代器逐个检索值。
def get_random_ints(count, begin, end):
print("get_random_ints start")
for x in range(0, count):
yield randint(begin, end)
print("get_random_ints end")
nums_generator = get_random_ints(10, 0, 100)
print(type(nums_generator))
for i in nums_generator:
print(i)
输出:
<class 'generator'>
get_random_ints start
70
15
86
8
79
36
37
79
40
78
get_random_ints end
- 请注意,nums_generator 的类型是 generator。
- 当从生成器中检索第一个元素时,第一个 print 语句只执行一次。
- 一旦生成器函数生成了所有的项,就执行生成器函数中剩余的代码。这就是为什么第二个 print 语句只打印一次,而且是在 for 循环的末尾。
Python 生成器函数真实世界示例
使用生成器功能的一个最流行的例子是读取一个大的文本文件。对于这个例子,我创建了两个 python 脚本。
- 第一个脚本将所有文件行读入一个列表,然后返回它。然后,我们将所有行打印到控制台。
- 第二个脚本使用 yield 关键字一次读取一行,并将其返回给调用者。然后打印到控制台上。
我使用 Python 资源模块来打印两个脚本的内存和时间使用情况。
read_file.py
import resource
import sys
def read_file(file_name):
text_file = open(file_name, 'r')
line_list = text_file.readlines()
text_file.close()
return line_list
file_lines = read_file(sys.argv[1])
print(type(file_lines))
print(len(file_lines))
for line in file_lines:
print(line)
print('Peak Memory Usage =', resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)
print('User Mode Time =', resource.getrusage(resource.RUSAGE_SELF).ru_utime)
print('System Mode Time =', resource.getrusage(resource.RUSAGE_SELF).ru_stime)
读取文件产量. py
import resource
import sys
def read_file_yield(file_name):
text_file = open(file_name, 'r')
while True:
line_data = text_file.readline()
if not line_data:
text_file.close()
break
yield line_data
file_data = read_file_yield(sys.argv[1])
print(type(file_data))
for l in file_data:
print(l)
print('Peak Memory Usage =', resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)
print('User Mode Time =', resource.getrusage(resource.RUSAGE_SELF).ru_utime)
print('System Mode Time =', resource.getrusage(resource.RUSAGE_SELF).ru_stime)
我有四个不同大小的文本文件。
~ du -sh abc.txt abcd.txt abcde.txt abcdef.txt
4.0K abc.txt
324K abcd.txt
26M abcde.txt
263M abcdef.txt
~
以下是我为不同文件运行这两个脚本时的统计数据。
~ python3.7 read_file.py abc.txt
Peak Memory Usage = 5558272
User Mode Time = 0.014006
System Mode Time = 0.008631999999999999
~ python3.7 read_file.py abcd.txt
Peak Memory Usage = 10469376
User Mode Time = 0.202557
System Mode Time = 0.076196
~ python3.7 read_file.py abcde.txt
Peak Memory Usage = 411889664
User Mode Time = 19.722828
System Mode Time = 7.307018
~ python3.7 read_file.py abcdef.txt
Peak Memory Usage = 3917922304
User Mode Time = 200.776204
System Mode Time = 72.781552
~ python3.7 read_file_yield.py abc.txt
Peak Memory Usage = 5689344
User Mode Time = 0.01639
System Mode Time = 0.010232999999999999
~ python3.7 read_file_yield.py abcd.txt
Peak Memory Usage = 5648384
User Mode Time = 0.233267
System Mode Time = 0.082106
~ python3.7 read_file_yield.py abcde.txt
Peak Memory Usage = 5783552
User Mode Time = 22.149525
System Mode Time = 7.461281
~ python3.7 read_file_yield.py abcdef.txt
Peak Memory Usage = 5816320
User Mode Time = 218.961491
System Mode Time = 74.030242
下面是表格形式的数据,以便更好地理解。
| 文件大小 | 返回语句 | 发电机功能 |
| 4 KB | 内存:5.3 兆,时间:0.023 秒 | 内存:5.42 兆,时间:0.027 秒 |
| 324 KB | 内存:9.98 兆,时间:0.028 秒 | 内存:5.37 MB,时间:0.32 秒 |
| 26 兆字节 | 内存:392.8 兆,时间:27.03 秒 | 内存:5.52 兆,时间:29.61 秒 |
| 263 兆字节 | 内存:3.65 GB,时间:273.56 秒 | 内存:5.55 兆,时间:292.99 秒 |
所以生成器函数比 return 语句花费的时间稍微多一点。这很明显,因为它必须跟踪每次迭代器 next()调用中的函数状态。
但是,使用 yield 关键字对内存的好处是巨大的。使用 return 语句时,内存使用量与文件大小成正比。对于发生器函数,它几乎是常数。
注:这里的例子是为了说明当函数产生大量数据时使用 yield 关键字的好处。Python 文件已经有了一个内置的函数 readline(),用于逐行读取文件数据,这个函数内存效率高,速度快,使用简单。
Python yield 发送示例
在前面的例子中,生成器函数向调用者发送值。我们还可以使用 send()函数向生成器函数发送值。
当调用 send()函数来启动生成器时,必须使用 None 作为参数来调用它,因为没有 yield 表达式可以接收该值。否则,我们将得到 类型错误:不能发送非 None 值到一个刚刚启动的生成器 。
def processor():
while True:
value = yield
print(f'Processing {value}')
data_processor = processor()
print(type(data_processor))
data_processor.send(None)
for x in range(1, 5):
data_processor.send(x)
输出:
<class 'generator'>
Processing 1
Processing 2
Processing 3
Processing 4
Python 从示例中产生
“从表达式产生”用于从给定的表达式创建子迭代器。子迭代器产生的所有值都直接传递给调用程序。假设我们想为 get_random_ints()函数创建一个包装器。
def get_random_ints(count, begin, end):
print("get_random_ints start")
for x in range(0, count):
yield randint(begin, end)
print("get_random_ints end")
def generate_ints(gen):
for x in gen:
yield x
我们可以在 generate_ints()函数中使用“yield from”来创建调用程序和子迭代器之间的双向连接。
def generate_ints(gen):
yield from gen
当我们必须向生成器函数发送数据时,“yield from”的实际好处是显而易见的。让我们看一个例子,在这个例子中,生成器函数从调用者那里接收数据,并将其发送给子迭代器进行处理。
def printer():
while True:
data = yield
print("Processing", data)
def printer_wrapper(gen):
# Below code to avoid TypeError: can't send non-None value to a just-started generator
gen.send(None)
while True:
x = yield
gen.send(x)
pr = printer_wrapper(printer())
# Below code to avoid TypeError: can't send non-None value to a just-started generator
pr.send(None)
for x in range(1, 5):
pr.send(x)
输出:
Processing 1
Processing 2
Processing 3
Processing 4
创建包装函数需要很多代码。我们可以在这里简单地使用“yield from”来创建包装函数,结果将保持不变。
def printer_wrapper(gen):
yield from gen
结论
Python yield 关键字创建一个生成器函数。当函数通过将数据分成多个块来返回大量数据时,这很有用。我们还可以使用 send()函数向生成器发送值。“yield from”语句用于从生成器函数创建子迭代器。
参考资料:
Python zip()函数
原文:https://www.askpython.com/python/built-in-methods/python-zip-function
Python zip()函数在里面存储数据。该函数接受 iterable 元素作为输入,并返回 iterable 作为输出。
如果没有向 python zip 函数提供可迭代元素,它将返回一个空迭代器。
因此,它从 iterables 中聚合元素,并返回元组的 iterables。
Python Zip()函数语法:
zip(*iterators)
Python zip()函数参数:
zip()函数返回的值:
这个函数从相应的容器中返回一个 iterable 对象映射值。
**举例:**对 Python zip()函数的基本了解
# initializing the input list
city = [ "Pune", "Ajanta", "Aundh", "Kochi" ]
code = [ 124875, 74528, 452657, 142563 ]
# zip() to map values
result = zip(city, code)
result = set(result)
print ("The zipped outcome is : ",end="")
print (result)
输出:
The zipped outcome is : {('Ajanta', 74528), ('Kochi', 142563), ('Aundh', 452657), ('Pune', 124875)}
Python zip()函数具有多个可迭代项
如果用户将多个 iterable 传递给 python zip()函数,该函数将返回一个包含与 iterable 相对应的元素的元组的 iterable。
举例:
numbers = [23,33,43]
input_list = ['five', 'six', 'seven']
# No iterables being passed to zip() function
outcome = zip()
result = list(outcome)
print(result)
# Two iterables being passed to zip() function
outcome1 = zip(numbers, input_list)
result1 = set(outcome1)
print(result1)
输出:
[]
{(23, 'five'), (33, 'six'), (43, 'seven')}
Python zip()函数具有长度不等的可迭代元素
numbers = [23, 33, 43]
input_list = ['one', 'two']
input_tuple = ('YES', 'NO', 'RIGHT', 'LEFT')
# the size of numbers and input_tuple is different
outcome = zip(numbers, input_tuple)
result = set(outcome)
print(result)
result1 = zip(numbers, input_list, input_tuple)
outcome1 = set(result1)
print(outcome1)
输出:
{(33, 'NO'), (43, 'RIGHT'), (23, 'YES')}
{(23, 'one', 'YES'), (33, 'two', 'NO')}
zip()函数来解压缩这些值
**"*" operator**
用于解压缩值,即将元素转换回独立的值。
alphabets = ['a', 'c', 'e']
number = [1, 7, 9]
result = zip(alphabets, number)
outcome = list(result)
print(outcome)
test, train = zip(*outcome)
print('test =', test)
print('train =', train)
输出:
[('a', 1), ('c', 7), ('e', 9)]
test = ('a', 'c', 'e')
train = (1, 7, 9)
结论
在本文中,我们已经了解了 Python 的 zip()函数的工作原理。
参考
- Python zip()函数
- zip()函数文档
Python2 与 python 3——简单比较
你好,初学者!你一定听说过 Python2 对 Python3,有些人用 2 版本,有些人用 3 版本。今天就让我们了解一下 Python 两个版本的区别。
Python2 和 Python3 的主要区别
让我们通过理解一些最常用的函数以及它们在两个版本中的不同之处,来了解 Python 2.x 和 Python 3.x 的区别。
1.print
声明
| Python 版本 | 语法 |
| Python2 | 打印“我是 Python2 版” |
| Python3 | 打印(“我是 Python3 版”) |
通常,上述两种语法的输出是完全相同的。但是 Python3 中括号的使用使得用户更容易阅读。
2.input
声明
所有程序都需要用户输入,只有在这里把它添加到列表中才有意义。让我们看看如何在 Python2 和 Python3 中使用输入法。
| Python 版本 | 语法 |
| Python2 | raw_input():用于字符串
input():用于整数 |
| Python3 | input():用于所有需要的输入 |
3.variables
在打印报表时
我们如何在 Python2 和 Python3 之间使用格式字符串方法在打印语句中使用变量?
| Python 版本 | 语法 |
| Python2 | msg = “Hello”
print("输入的消息是% " % msg) |
| Python3 | msg = “Hello”
print("输入的消息是{0} ")。格式(消息)) |
4.错误处理
在 python3 中,程序员需要在 except
块中添加as
作为额外的关键字。
| Python 版本 | 语法 |
| Python2 | 尝试:
//代码
除<错误>,错误:
//代码 |
| Python3 | 试:
//代码
除<错误>为 err:
//代码 |
5.Python 中的除法运算
在 Python2 的情况下,除法运算产生一个整数。另一方面,Python3 在除法运算后返回一个浮点值。
6.迭代函数
在 Python2 中,[xrange()](https://www.askpython.com/python/built-in-methods/python-xrange-method)
用于迭代,而在 Python3 中,新的高级函数range()
用于迭代。
Python2 和 Python3 哪个好?
现在大多数开发者都在创建与 Python 3 严格兼容的库。它也比 Python2 更容易编码和理解
此外,在 Python3 中,字符串以 Unicode 的形式存储,这比 Python2 中使用的 ASCII 码更加通用。最后,Python3 消除了开发冲突,因为它允许输入 Python2 不支持的。
除此之外,Python 3 支持所有现代编程,如人工智能、机器学习和数据科学概念。
简单来说: Python2 是过去,Python3 是未来!
结论
谈到更喜欢哪个版本,Python2 还是 Python3,我们可以断定 Python 3 是直接的赢家。另外,如果你是一个新的程序员,我会建议你选择 Python3。
编写代码的 Pythonic 方式
原文:https://www.askpython.com/python/examples/pythonic-way-of-coding
在大多数编程语言中,我们经常遇到声称它是最强大的语言的说法。嗯,这个说法好像比较主观,为什么会这样呢?这是因为用一种语言编写的程序可以用另一种语言编写。
不同语言的语法可能不同,但不存在一种语言可以实现而另一种语言不能实现的算法。在本文中,我们将看到 Python 在最佳实践、简单性和可读性方面提供的一些方法,可以表述为Python 化的 。
Pythonic 代码的要点
就像任何其他语言一样,Python 中有各种各样的方法或设计模式。Python 本身使用的语法读起来非常接近英语,我们可以找到大量的文章或在线评论,大部分来自其他语言的人,Python 可以在几周内学会等等。这对于任何语言来说都是不正确的,对于 Python 来说更是如此。
Python 化 指的是 Python 特有的惯用编码做法,确实不仅仅是使用 Python 语法和使用标准库。
Python 也被称为习惯用法,这意味着基于 Python 代码与标准库提供的特性保持一致的想法来编写 Python 代码。对于不同的程序员来说,这种说法可能是不同的,它当然不是任何人的绝对指南。
这是像一个有经验的程序员一样用最佳实践和技术编写 Python 的想法,就像任何其他语言一样,它通常被一个巨大的社区所遵循。
我们到底为什么需要 Pythonic 代码?
每当我们编写一个程序时,它都是为了被正确执行。编写程序有多种方式,但有些方式可以被视为**【更多】正确的方式。这对 Python 来说尤其如此,因为它使用极简语法,可读性很强。所以,如果我们用错了【少】**的正确方式,往往很难被忽视。
用“更”正确的方式编写代码有很多好处。其中一些可以表述为:
- 我们正在利用数千名非常聪明的开发人员,他们拥有多年编写 Python 的经验,并对开源语言做出了贡献。利用他们长期使用该语言所获得的专业知识,实现使用 Python 的最佳实践和惯用方法,这当然是一个好主意。
- 具体谈到 CPython,它期望某种类型的代码实现以提高效率,因为它已经针对许多操作进行了调整。例如,我们可以通过使用 for 循环 从列表中创建子列表,或者我们可以使用 切片 来实现相同的目的。切片稍微好一点,因为它的工作方式与我们预期的完全一样。
- 一段代码应该是易于阅读和全面的。比方说,当我们看到常见的模式如 列表理解 时,我们甚至可以在解析所有符号之前更快地理解代码。相反,以非 pythonic 的方式,我们必须分析整个代码才能理解它是如何工作的。因此,以惯用的方式编写一段代码通常更干净、更简单。
作为 Python 开发者,这些对我们来说是显而易见的优势。然而,还有一些不太明显或更广泛的好处,例如:
- 当我们运行开源项目时,如果使用最佳实践,人们更容易做出贡献。为我们的项目做出贡献的人看到代码以聪明的方式编写会很兴奋。错过这个想法的项目之一是传统的 T2 PyPI。当我们 pip 安装 任何包时,我们运行的就是 PyPI 。它已经存在很多年了,但是很难找到开源的贡献者。嗯, PyPI 源代码缺乏惯用的实践。它由一个文件中的数千行代码和一个相似的代码库组成。所以,当人们试图让它变得更好时,他们很难读懂这些代码。
值得庆幸的是,它被重写并在 PyPI 的官方网站上发布,使用了最佳实践和现代习语,当然这次有更多的贡献者。
- 使用封闭的源代码工作,例如为一个组织或公司工作,只有最好的开发人员会被期望工作并被保留。因此,项目中的最佳编码实践和一致性为那些开发人员提供了在更习惯、更易理解和更可读的代码上工作的好处。
Pythonic 方式的代码示例
让我们试着通过一些例子来对我们在本文前面讨论过的 Pythonic 代码有一个大致的了解。
1。 命名约定
也被称为标识符名称的变量作为一个基本部分在所有编程语言中使用。通常,命名变量没有固定的准则,但是遵循一个模式会有所帮助。
PEP8 提供了一些遵循 Pythonic 方式命名变量的最佳实践或风格指南。即使只是简单地看一眼,也能很好地了解正在阅读的代码类型。下面提供了一些例子。
| 命名惯例 | 摘自人教版 8 风格指南 |
| 包装 | 公用事业 |
| 模块 | db_utils, dbutils, db_connect |
| 班级 | 客户详细信息 |
| 功能 | 创建订单 |
| 变量 | 订单 id |
| 常数 | 运输 _ 成本 |
PEP 8 Style Guide
2。 使用 f 字符串进行字符串格式化
使用字符串输出值或返回包含表达式的插值字符串的语句是 Python 中的一种常见模式。早些时候,字符串被连接或者使用 +操作符连接,这导致了一长串代码,看起来非常混乱,经常令人困惑。这个问题很快得到解决,语言提供了一些非常简洁的解决方案。
在 Python 3.6 中引入了 f 弦 ,为上述问题提供了更好的解决方案。f 字符串可以被认为是对用 Python 编写字符串的改进,因为用 f 字符串格式编写的代码不会向后兼容,但是实现它们符合 Python 的标准。让我们通过一些例子来获得一个概述。
first_name, age, job = "John", 33, "programmer"
# Method 1: String Concatenation
print(first_name + " " + "is a" + " " + str(age) + " " + "year old" + " " + job)
# Method 2: % Conversion specifier
print("%s is a %d year old %s" % (first_name, age, job))
# Method 3: Using format: Until Python 3.6
print("{0} is a {1} year old {2}".format(first_name, age, job))
# Method 4: The Pythonic Way: From Python 3.6 and above
print(f"{first_name} is a {age} year old {job}")
"""
Output:
John is a 33 year old programmer
John is a 33 year old programmer
John is a 33 year old programmer
John is a 33 year old programmer
"""
3。使用 enumerate()而不是 len()或 range()函数与 for-loops
通常,我们必须使用 for-loops 来迭代 Python 中的可迭代对象,例如列表、字符串或元组,并且还需要通过它们进行索引。有很多方法可以实现这一点。一些常见的模式使用 len()
或 range()
函数来访问那些可迭代对象的索引。Python 有一个内置的enumerate()
函数来执行这个操作,这可以被认为是 python 提供了对索引的直接访问,而不是使用多个函数对其进行编码。
# ------------------------------
# Looping and Indexing through
# -----------------------------
# Method 1
greet = "hello"
i = 0
for eachChar in greet:
print(i, eachChar)
i += 1
"""
0 h
1 e
2 l
3 l
4 o
"""
# Method 2: A better way
greet = "there"
for idx in range(len(greet)):
print(idx, greet[idx])
"""
0 t
1 h
2 e
3 r
4 e
"""
# Method 3: The Pythonic way: enumerate()
greet = "hello"
for idx, eachChar in enumerate(greet):
print(idx, eachChar)
"""
0 h
1 e
2 l
3 l
4 o
"""
4。使用列表理解代替 for 循环
列表理解是 Python 特有的。这是我们用 Python 快速创建列表的一种方式,而不是循环和使用 append。它提供了一个更短的语法来基于原始列表中包含的条目创建一个全新的列表,或者更具体地说是基于 iterable 对象。下面是使用 append 函数和更多的python 式列表理解的例子。请注意,它不能被过度使用,因为我们不希望在一行代码中有太多的逻辑,但它在各种情况下都非常有用。它使我们的代码简洁易读。
# Using loops
my_list = []
for char in "hello":
my_list.append(char)
print(my_list) # ['h', 'e', 'l', 'l', 'o']
# The Pythonic Way: Using List Comprehensions
my_list1 = [char for char in "hello"]
print(my_list1) # ['h', 'e', 'l', 'l', 'o']
5。合并字典
Python 中到处都在使用字典。它们是最重要的数据结构之一,有多种用途。字典中的键|值对是构建块,在 Python 中对它们执行多重操作是很常见的。对于这个例子,我们将按照惯例或程序以及一些 Pythonic 方式来合并字典。
# Declaring two variables for dictionaries
customer_details = {"name": "john", "age": 34, "email": "[email protected]"}
order_items = {"item1": "apple", "item2": "orange"}
# Method 1: Not So Pythonic: Using Loops
order_details = {}
for i in customer_details:
order_details[i] = customer_details[i]
for i in order_items:
order_details[i] = order_items[i]
print(f"Result_one: {order_details}")
# The Pythonic way: Spreading out and merging using **kwargs
order_details = {**customer_details, **order_items}
print(f"Result_two: {order_details}")
# Python 3.10 Updated: Union Operator (with | pipe character)
# The Pythonic Way
order_details = customer_details | order_items
print(f"Result_three: {order_details}")
"""
Output:
Result_one: {'name': 'john', 'age': 34, 'email': '[email protected]', 'item1': 'apple', 'item2': 'orange'}
Result_two: {'name': 'john', 'age': 34, 'email': '[email protected]', 'item1': 'apple', 'item2': 'orange'}
Result_three: {'name': 'john', 'age': 34, 'email': '[email protected]', 'item1': 'apple', 'item2': 'orange'}
"""
结论
在所有编程语言中,都有特定于它们的最佳实践。作为最常用的语言之一,Python 也不例外。它有其久经考验的技术和写作风格。编写 Pythonic 代码不仅使我们的代码更简单易读,而且易于维护。
惯用的 Python 提供了一种易于识别的设计模式,这种模式使得编程成为一种无缝的体验,混淆最小。在本文中,我们浏览了其中的一些方法,以获得 Pythonic 方式的概述。
还有很多其他的例子,而且随着时间的推移,这种例子只会越来越多。Python 确实在 Python 开发人员社区中占有重要地位。
在 PyTorch 中创建自定义数据集
原文:https://www.askpython.com/python-modules/pytorch-custom-datasets
在本文中,我们将学习为 PyTorch 创建自定义数据集。
在机器学习中,模型和训练它的数据一样好。
有许多预先构建的标准数据集,如 MNIST 、CIFAR 和 ImageNet,用于初学者教学或基准测试。但是这些预定义的数据集并不多,如果你正在处理一个相对较新的问题,你可能没有预定义的数据集,你需要使用自己的数据集进行训练。
在本教程中,我们将了解一些使用 PyTorch 从自定义数据中提取的初级数据集。
了解 PyTorch 数据集和数据加载器类
用于处理数据样本的代码可能会变得混乱,难以维护;理想情况下,我们希望数据集代码与模型训练代码分离,以获得更好的可读性和模块化。
PyTorch 提供了两个数据原语:torch.utils.data.DataLoader
和torch.utils.data.Dataset
,它们允许您使用预加载的数据集以及您自己的数据。Dataset
存储样品及其相应的标签,DataLoader
在Dataset
周围包裹一个可重复标签,以便于获取样品。
因此,Dataset 是负责将数据从磁盘加载到计算机可读形式的类。它使用一种懒惰的方式来加载内存-它只在数据加载器或用户需要将数据从磁盘加载到内存时才加载内存。这是存储器有效的,因为所有的图像不是一次存储在存储器中,而是根据需要读取。
torch 数据集类是表示数据集的抽象类。为了创建自定义数据集,我们可以从这个抽象类继承。但是一定要定义两个非常重要的功能:
__len__
以便len(dataset)
返回数据集的大小。__getitem__
支持索引,以便dataset[i]
可用于获取第 i i 个样本。
数据加载器只是调用这些方法来加载内存。在本文中,我们将只关注自定义数据集的创建。数据加载器也可以进行很大程度的扩展,但这超出了本文的范围。
既然我们已经学习了DataLoader
和Dataset
的基本功能,我们将看看现实生活中的一些例子。
从未标记的图像加载自定义数据集
这是一个相对简单的例子,将一个文件夹中的所有图像加载到一个数据集中,用于 GAN 训练。所有的数据都来自同一个类,所以你现在不需要关心标签。
1.初始化自定义数据集类
# Imports
import os
from PIL import Image
from torch.utils.data import Dataset
from natsort import natsorted
from torchvision import datasets, transforms
# Define your own class LoadFromFolder
class LoadFromFolder(Dataset):
def __init__(self, main_dir, transform):
# Set the loading directory
self.main_dir = main_dir
self.transform = transform
# List all images in folder and count them
all_imgs = os.listdir(main_dir)
self.total_imgs = natsorted(all_imgs)
现在我们需要为自定义数据集定义两个专门的函数。
2.定义 len 函数
该函数将允许我们识别已经从我们的定制数据集中成功加载的项目的数量。
def __len__(self):
# Return the previously computed number of images
return len(self.total_imgs)
3.定义 getitem 函数
def __getitem__(self, idx):
img_loc = os.path.join(self.main_dir, self.total_imgs[idx])
# Use PIL for image loading
image = Image.open(img_loc).convert("RGB")
# Apply the transformations
tensor_image = self.transform(image)
return tensor_image
定义数据集后,您可以使用,
dataset = LoadFromFolder(main_dir="./data", transform=transform)
dataloader = DataLoader(dataset)
print(next(iter(dataloader)).shape) # prints shape of image with single batch
从带标签的图像加载自定义数据集
假设我们有一个更复杂的问题,比如猫狗分类器。我们现在必须标记数据集的图像。为此,我们有一个非常特殊的 PyTorch 数据集类 ImageFolder
假设我们有以下目录结构:
所有猫的图片都在猫文件夹里,所有狗的图片都在狗文件夹里。如果您碰巧有以下目录结构,您可以使用
from torchvision.datasets import ImageFolder
dataset = ImageFolder(root="./root", transform=transform)
dataloader = DataLoader(dataset)
print(next(iter(dataloader)).shape) # prints shape of image with single batch
你可以通过继承 ImageFolder 类来改变图片的标签和加载方式。
载入自定音频数据集
如果您正在处理音频,同样的技术也适用于音频。唯一改变的是数据集长度的测量方式和文件在内存中的加载方式。
from torch.utils.data import Dataset
class SpectrogramDataset(Dataset):
def __init__(self,file_label_ds, transform, audio_path=""):
self.ds= file_label_ds
self.transform = transform
self.audio_path=audio_path
# The length of the dataset
def __len__(self):
return len(self.ds)
# Load of item in folder
def __getitem__(self, index):
file,label=self.ds[index]
x=self.transform(self.audio_path+file)
return x, file, label
# file_label_ds is a dataset that gives you the file name and label.
dataset = SpectrogramDataset(file_label_ds, transform)
结论
这就把我们带到了文章的结尾。敬请关注更多关于深度学习和 PyTorch 的文章。
PyTorch Lightning:如何训练你的第一个模型?
在本文中,我们将使用 PyTorch Lightning 训练我们的第一个模型。自 2016 年成立以来,PyTorch 一直是许多研究人员的首选。它变得流行是因为它更 pythonic 化的方法和对 CUDA 非常强的支持。然而,它有一些样板代码的基本问题。一些功能,如使用多个 GPU 的分布式培训,是为高级用户准备的。
PyTorch lightning 是 PyTorch 的一个包装器,旨在给 PyTorch 一个类似 Keras 的界面,而不牺牲任何灵活性。如果你已经使用 PyTorch 作为你的日常驱动,PyTorch-lightning 可以成为你的工具集的一个很好的补充。
PyTorch Lightning 入门
我们将在这里以一种简单易懂的方式回顾创建我们的第一个模型的步骤。因此,没有任何进一步的麻烦,让我们马上开始吧!
1.安装 PyTorch 闪电
要安装 PyTorch-lightning,您可以运行简单的 pip 命令。如果你想从一些预定义的数据集开始,闪电模块也会派上用场。
pip install pytorch-lightning lightning-bolts
2.导入模块
首先,我们导入 pytorch 和 pytorch-lightning 模块。
import torch
from torch.nn import functional as F
from torch import nn
import pytorch_lightning as pl
可能会有一个常见的问题:“当我们已经在使用闪电时,为什么我们还需要火炬?”
嗯,闪电让 torch 的编码速度更快。lightning 建立在 torch 之上,可轻松扩展 torch 模块,允许用户在必要时进行关键的特定应用程序更改。
3.设置 MNIST 数据集
与 base PyTorch 不同,lightning 使数据库代码更易于用户访问和组织。
数据模块只是 train_dataloader、val_dataloader、test_dataloader 以及所需的匹配转换和数据处理/下载步骤的集合。
https://pytorch-lightning.readthedocs.io/en/stable/extensions/datamodules.html#what-is-a-datamodule
在 PyTorch 中, MNIST 数据模块通常定义如下:
from torchvision import datasets, transforms
# transforms
# prepare transforms standard to MNIST
transform=transforms.Compose([transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))])
mnist_train = MNIST(os.getcwd(), train=True, download=True, transform=transform)
mnist_train = DataLoader(mnist_train, batch_size=64)
正如您所看到的,数据模块并没有真正构造成一个块。如果您希望添加更多功能,如数据准备步骤或验证数据加载器,代码会变得更加混乱。Lightning 将代码组织成一个LightningDataModule
类。
在 PyTorch-Lightning 中定义数据模块
1.设置数据集
让我们首先使用LightningDataModule
加载并设置数据集。
from torchvision.datasets import MNIST
from torchvision import transforms
class MNISTDataModule(pl.LightningDataModule):
def __init__(self, data_dir: str = './'):
super().__init__()
self.data_dir = data_dir
self.transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
# self.dims is returned when you call dm.size()
# Setting default dims here because we know them.
# Could optionally be assigned dynamically in dm.setup()
self.dims = (1, 28, 28)
def prepare_data(self):
# download
MNIST(self.data_dir, train=True, download=True)
MNIST(self.data_dir, train=False, download=True)
def setup(self, stage = None):
# Assign train/val datasets for use in dataloaders
if stage == 'fit' or stage is None:
mnist_full = MNIST(self.data_dir, train=True, transform=self.transform)
self.mnist_train, self.mnist_val = random_split(mnist_full, [55000, 5000])
# Assign test dataset for use in dataloader(s)
if stage == 'test' or stage is None:
self.mnist_test = MNIST(self.data_dir, train=False, transform=self.transform)
preapre_data
函数下载数据并以 torch 可读的形式保存。setup
函数将数据集分为训练、测试和验证。这些函数可以任意复杂,这取决于数据需要多少预处理。
2.定义数据加载器
现在我们有了设置,我们可以添加数据加载器函数。
def train_dataloader(self):
return DataLoader(self.mnist_train, batch_size=32)
def val_dataloader(self):
return DataLoader(self.mnist_val, batch_size=32)
def test_dataloader(self):
return DataLoader(self.mnist_test, batch_size=32)
3.最后看一下 MNIST 数据模块
最后的LightningDataModule
是这样的:
class MNISTDataModule(pl.LightningDataModule):
def __init__(self, data_dir: str = './'):
super().__init__()
self.data_dir = data_dir
self.transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
# self.dims is returned when you call dm.size()
# Setting default dims here because we know them.
# Could optionally be assigned dynamically in dm.setup()
self.dims = (1, 28, 28)
def prepare_data(self):
# download
MNIST(self.data_dir, train=True, download=True)
MNIST(self.data_dir, train=False, download=True)
def setup(self, stage = None):
# Assign train/val datasets for use in dataloaders
if stage == 'fit' or stage is None:
mnist_full = MNIST(self.data_dir, train=True, transform=self.transform)
self.mnist_train, self.mnist_val = random_split(mnist_full, [55000, 5000])
# Assign test dataset for use in dataloader(s)
if stage == 'test' or stage is None:
self.mnist_test = MNIST(self.data_dir, train=False, transform=self.transform)
def train_dataloader(self):
return DataLoader(self.mnist_train, batch_size=32)
def val_dataloader(self):
return DataLoader(self.mnist_val, batch_size=32)
def test_dataloader(self):
return DataLoader(self.mnist_test, batch_size=32)
MNIST 数据模块在 PyTorch-bolts 数据模块中预定义。如果您不想为自己编写整个代码而烦恼,您可以只导入数据模块并开始使用它。
from pl_bolts.datamodules import MNISTDataModule
# Create MNIST DataModule instance
data_module = MNISTDataModule()
现在我们已经有了现成的数据,我们需要模型来进行训练。
创建多感知器模型
照明模型非常类似于 PyTorch 模型的基础类,除了它有一些特殊的类函数来简化训练。__init__
和forward
方法与 PyTorch 完全相似。我们正在创建一个 3 层感知,每层感知的数量为(128,256,10)。还有一个大小为 28 * 28 (784)的输入图层,它采用展平的 28×28 MNIST 图像。
1.基本 PyTorch 型模型
class MyMNISTModel(nn.Module):
def __init__(self):
super().__init__()
# mnist images are (1, 28, 28) (channels, width, height)
self.layer_1 = nn.Linear(28 * 28, 128)
# The hidden layer of size 256
self.layer_2 = nn.Linear(128, 256)
# 3rd hidden layer of size 10.
# This the prediction layer
self.layer_3 = nn.Linear(256, 10)
def forward(self, x):
batch_size, channels, width, height = x.size()
# Flatten the image into a linear tensor
# (b, 1, 28, 28) -> (b, 1*28*28)
x = x.view(batch_size, -1)
# Pass the tensor through the layers
x = self.layer_1(x)
x = F.relu(x)
x = self.layer_2(x)
x = F.relu(x)
x = self.layer_3(x)
# Softmax the values to get a probability
x = F.log_softmax(x, dim=1)
return x
让我们使用一个随机的(28,28)值来检查这个模型是否有效。
net = MyMNISTModel()
x = torch.randn(1, 1, 28, 28)
print(net(x).shape)
输出:
torch.Size([1, 10])
1 表示批次,10 表示输出类的数量。所以我们的模型运行良好。
2.定义初始化和转发功能
PyTorch 数据模块看起来完全相似,除了它将从*pl*.*LightningModule*
派生它的属性。闪电网络将会是这样的:
class MyMNISTModel(pl.LightningModule):
def __init__(self):
super().__init__()
...
def forward(self, x):
....
除了这些基本的 torch 功能,lighting 还提供了一些功能,允许我们定义在培训、测试和验证循环中发生了什么。
2.定义培训和验证循环
为模型的训练和验证步骤定义训练循环。
def training_step(self, batch, batch_idx):
x, y = batch
# Pass through the forward function of the network
logits = self(x)
loss = F.nll_loss(logits, y)
return loss
def validation_step(self, batch, batch_idx):
x, y = batch
logits = self(x)
loss = F.nll_loss(logits, y)
return loss
def test_step(self, batch, batch_idx):
x, y = batch
logits = self(x)
loss = F.nll_loss(logits, y)
y_hat = torch.argmax(logits, dim=1)
accuracy = torch.sum(y == y_hat).item() / (len(y) * 1.0)
output = dict({
'test_loss': loss,
'test_acc': torch.tensor(accuracy),
})
return output
3.优化者
lightning 模型允许我们在模型定义中为特定的模型定义优化器。
# We are using the ADAM optimizer for this tutorial
def configure_optimizers(self):
return torch.optim.Adam(self.parameters(), lr=1e-3)
4.最后看一下我们的模型
最终的闪电模型应该是这样的:
class MyMNISTModel(pl.LightningModule):
def __init__(self):
super().__init__()
# mnist images are (1, 28, 28) (channels, width, height)
self.layer_1 = nn.Linear(28 * 28, 128)
# The hidden layer of size 256
self.layer_2 = nn.Linear(128, 256)
# 3rd hidden layer of size 10.
# This the prediction layer
self.layer_3 = nn.Linear(256, 10)
def forward(self, x):
batch_size, channels, width, height = x.size()
# Flatten the image into a linear tensor
# (b, 1, 28, 28) -> (b, 1*28*28)
x = x.view(batch_size, -1)
# Pass the tensor through the layers
x = self.layer_1(x)
x = F.relu(x)
x = self.layer_2(x)
x = F.relu(x)
x = self.layer_3(x)
# Softmax the values to get a probability
x = F.log_softmax(x, dim=1)
return x
def training_step(self, batch, batch_idx):
x, y = batch
# Pass through the forward function of the network
logits = self(x)
loss = F.nll_loss(logits, y)
return loss
def validation_step(self, batch, batch_idx):
x, y = batch
logits = self(x)
loss = F.nll_loss(logits, y)
return loss
def test_step(self, batch, batch_idx):
x, y = batch
logits = self(x)
loss = F.nll_loss(logits, y)
y_hat = torch.argmax(logits, dim=1)
accuracy = torch.sum(y == y_hat).item() / (len(y) * 1.0)
output = dict({
'test_loss': loss,
'test_acc': torch.tensor(accuracy),
})
return output
def configure_optimizers(self):
return torch.optim.Adam(self.parameters(), lr=1e-3)
我们现在已经有了数据和模型。让我们继续用数据训练模型。
5.训练模型
与传统的样板循环寻找损失并进行反向传递不同,pytorch-lighting 模块中的培训师无需太多代码就能为我们完成这项工作。
首先,我们在 lightning 中用特定的参数初始化一个训练器。
from pytorch_lightning import Trainer
# Set gpus = 0 for training on cpu
# Set the max_epochs for maximum number of epochs you want
trainer = Trainer(gpus=1, max_epochs=20)
用 MNISTDataModule 拟合数据集
trainer.fit(net, data_module)
6.结果
让我们检查一下训练数据集的最终准确性,
trainer.test(test_dataloaders=data_module.train_dataloader())
输出:
--------------------------------------------------------------------------------
DATALOADER:0 TEST RESULTS
{'test_acc': tensor(.98), 'test_loss': tensor(0.0017, device='cuda:0')}
--------------------------------------------------------------------------------
在训练数据集中获得高精度可能表明过度拟合。因此,我们还需要在我们之前分离的测试数据集上测试我们的模型。让我们在验证数据集上检查模型的最终准确性。
trainer.test(test_dataloaders=data_module.test_dataloader())
输出:
--------------------------------------------------------------------------------
DATALOADER:0 TEST RESULTS
{'test_acc': tensor(.96), 'test_loss': tensor(0.0021, device='cuda:0')}
--------------------------------------------------------------------------------
因此,有了这些结果,我们就可以确认模型在数据上训练得很好。
结论
就这样,我们结束了关于 PyTorch-lightning 的教程。PyTorch-lightning 相对较新,发展很快,所以我们可以期待在不久的将来会有更多的功能。所以敬请关注更多关于机器学习和深度学习的此类文章。
py torch——简单的初学者参考
PyTorch 在短短四年前首次亮相,是风靡数据科学行业的模块之一。
它为用户提供了文档完整的代码、教程和示例,帮助他们开始使用 PyTorch,在数据科学家和研究人员看来,这是一个巨大的成功。
PyTorch 的创造者也是致力于 TorchVision 和 TorchText 的人,这两个模块被认为在计算机视觉和自然语言处理领域非常有用。
PyTorch 是一个主要基于使用 Python 中的张量和动态神经网络的模块,但是也可以扩展到使用不同的领域。
如果您想与 PyTorch 合作,我们可以帮助您从这里开始!
还建议使用 Anaconda 进行数据科学和机器学习,所以,你可能也想了解一下。
安装 PyTorch
PyTorch 官方网站为我们提供了一个简单的界面,我们可以根据您的发行版和操作系统来使用和检索所需的安装命令。
如果您希望将正常环境与数据科学环境分开,您应该考虑创建虚拟环境。
Pick your flavor of PyTorch
稍微摆弄一下,为您的本地 PyTorch 库选择一个合适的版本,然后我们就可以进去使用 PyTorch 了。
从 PyTorch 开始
如果你已经安装了 PyTorch,太好了!我们现在都准备好开始工作了。
1.0 张量?
如果你曾经在 Python 中处理过大型矩阵,你可能会使用 NumPy 。这是因为 NumPy 在处理多维数组时提供了强大的支持,允许在 n 维数组上处理各种不同的操作。
PyTorch 用张量技术给这个领域带来了竞争。
张量在某种意义上是多维数组,很像 NumPy 所提供的。然而,不同之处在于,在与 GPU 一起工作时,张量得到了很好的支持。
谷歌的 Tensorflow 也在张量上运行,以处理和处理数据。
那么,我们如何开始使用张量和 PyTorch 呢?让我们找出答案。
1.1.进口火炬
我们已经知道,使用任何模块都首先需要一个 导入 来将它包含在脚本中。因此,我们就这么做吧,
# Importing torch to use in the script.
import torch
1.2.创建张量
使用torch
模块创建张量(本质上是矩阵)非常简单。这里有一些初始化/创建张量对象的方法。
# Creating tensors with strict numbers
ten1 = torch.tensor(5)
ten2 = torch.tensor(8)
print(ten1, ten2)
# Output : tensor(5) tensor(8)
# Creating a matrix of zeros using the zeros function
ten3 = torch.zeros((3, 3))
print(ten3)
# tensor([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
# Creating a matrix of random numbers
ten4 = torch.randn(3, 3)
print(ten4)
# tensor([[-0.9685, 0.7256, 0.7601],
[-0.8853, 0.4048, -1.0896],
[0.6743, 1.5665, 0.2906]])
1.3.基本张量运算
张量在很多方面都可以使用,就像 NumPy 模块创建的矩阵一样。
我们可以进行基本的数字运算,
firstten = torch.tensor(3)
secondten = torch.tensor(6)
# Addition of tensors
print(firstten + secondten)
# Output : tensor(9)
# Subtraction of tensors
print(firstten - secondten)
# Output : tensor(-3)
# Multiplication of tensors
print(firstten * secondten)
# Output : tensor(18)
# Division of tensors
print(firstten / secondten)
# Output : tensor(0.5000)
1.4.与张量一起前进
张量不仅仅可以用于简单的运算,在 Python 中,简单的运算通常可以用变量来完成。
它们支持对它们执行多种操作,通常在 PyTorch 脚本的许多操作中用作变量。
用类似矩阵乘法 torch.mm
的函数,创建等间距张量torch.linspace
,用类似torch.sin(x)
的数学函数处理数学函数。
毫不奇怪,所提供的功能允许嵌入数学方法的深度计算。
如果你希望通过例子来研究张量的工作,你可能希望看这里的。
下一步是什么?
除了使用通常的张量和默认提供的函数之外,研究 PyTorch 提供的另一个模块可能会有所帮助。
张量本身终究只是一个基础。真正的力量在于模块提供的使用这种媒介进行计算的应用程序用法。
PyTorch 为我们提供了为与神经网络一起工作而设计的模块,称为torch.nn
。
torch.nn
模块包含各种各样的功能来帮助它执行基于神经网络的操作,
使用 PyTorch 作为数据科学模块的下一步就是处理这些问题。
结论
PyTorch 仍在开发中,但它提供的功能被广泛认为优于许多数据科学模块。
有大量的模块被创建来与 PyTorch 兼容,也有大量的资源帮助使用它们。
PyTorch 是一个开源项目,这意味着您可以参与该项目并为其未来版本做出贡献。
这里是 GitHub 链接,这里是为了开源!干杯!
查看我们的其他文章,这些文章将对您的数据科学项目有所帮助——Pandas和使用 sklearn 进行培训和测试。
参考
- 【PyTorch 官方文档
- 【PyTorch 入门教程
- 使用 PyTorch 的资源
Python 中 PyVista 的介绍
原文:https://www.askpython.com/python-modules/pyvista-in-python
PyVista(以前的“vtki ”)是一个适应性强的辅助模块和可视化工具包(VTK)的高级 API。它是 VTK 的简化界面,支持基于 Python 的网格分析和 3D 图形绘制。2019 年 5 月由 C. Bane Sullivan 和 Alexander A. Kaszynski(研究论文)提出。在深入研究 PyVista 的细节之前,让我们先快速了解一下 VTK。
VTK 介绍(可视化工具包)
VTK 是一个前沿的工具包,由 C++类库和解释接口层组成,如 Java、Python 和 Tcl/Tk。它融合了 C++的执行速度和 Python 的快速原型制作能力。
开源包 VTK 包括一个强大的处理和渲染管道,以及许多先进的可视化方法。VTK 的设计基于强大的管道概念。以下是这一概念的基本组成部分的总结:
VTK Pipeline
然而,当使用 VTK 时,简单的应用程序(如构建网格对象)需要很长的代码,但是 PyVista 只需几行 Pythonic 和简单的代码就可以完成相同的操作。
PyVista 通过 NumPy 库封装了 VTK,各种类和方法允许直接访问数组。它允许空间数据、快速原型和网格分析的可视化集成。
PyVista 的 Python 实现
本节将介绍 PyVista 实现,并显示各种 3D 形状和对象。我们将从使用下面的代码片段导入 PyVista 模块以及该模块下的示例开始。
import pyvista as pv
from pyvista import examples
我们将利用一个内置的示例文件,以网格的形式显示飞机。请看下面的代码片段。我们还将在下面的代码片段中读取平面文件的网格数据。
plane_file = examples.planefile
plane_mesh = pv.read(plane_file)
下一步是使用下面的代码在 3D 图上绘制平面及其网格。第三行代码将网格和平面结合在一起。
cpos = plane_mesh.plot()
plane_plotter = pv.Plotter()
plane_plotter.add_mesh(plane_mesh)
输出如下所示。
PyVista Plane Output
看起来很棒,对吧?让我们尝试一些其他形状和物体,看看惊人的结果。下面的代码片段将帮助我们得到一个门卫作为输出。
mesh = examples.download_doorman()
mesh.plot(cpos="xy")
PyVista Doorman Output
哇哦。多详细的模型啊?我相信你也对结果感到惊讶。我们再来看看最后一个对象!下面的代码片段将会产生一些令人惊奇的东西。只要试一试,你就会惊叹不已。
mesh = examples.download_bunny_coarse()
cpos = [(0.2, 0.3, 0.9), (0, 0, 0), (0, 1, 0)]
mesh.plot(cpos=cpos, show_edges=True, color=True)
PyVista Bunny Output
屏幕上的小兔子真可爱,对吧?
结论
我希望你喜欢 PyVista 上的教程,并在这个教程中学到一些新东西。如果你喜欢这个教程,我建议你也看看下面的教程:
感谢您的阅读!
使用 PyYAML 进行 Python YAML 处理
YAML 代表 YAML 标记语言。它广泛用于为许多不同的 DevOps 工具和应用程序编写和存储配置文件。它以文本文件的形式编写,易于人类阅读,易于阅读和理解。它使用**。yaml** 或**。yml** 作为扩展。它类似于其他数据序列化语言,如 JSON 和 XML。
数据序列化是通过网络执行配置文件传输和恢复的标准格式。
使用 YAML 用 Python 编写的数据序列化文件可以很容易地通过网络发送,然后可以使用另一种编程语言对其进行反序列化。它支持多种语言,如 Python、JavaScript、Java 等等。这些语言有 YAML 库,使它们能够解析和使用 YAML 文件。在本文中,我们将使用 Python 通过一些例子来回顾 YAML。它还支持列表、字典和数组等数据结构。
YAML vs XML vs JSON
让我们看一个配置文件的例子,看看三个版本,以获得概述和语法。
YAML——YAML 不是一种标记语言
configuration:
name: my-api-config
version: 1.0.0
about: "some description"
description: |
Lorem ipsum dolor sit amet,
consectetur adipiscing elit
scripts:
"start:dev": main.py
keywords: ["hello", "there"]
XML–可扩展标记语言
<configuration>
<name>my-api-config</name>
<version>1.0.0</version>
<about>some description</about>
<description>Lorem ipsum dolor sit amet, consectetur adipiscing elit</description>
<scripts>
<start:dev>main.py</start:dev>
</scripts>
<keywords>hello</keywords>
<keywords>there</keywords>
</configuration>
JSON–JavaScript 对象符号
{
"configuration": {
"name": "my-api-config",
"version": "1.0.0",
"about": "some description",
"description": "Lorem ipsum dolor sit amet, \nconsectetur adipiscing elit\n",
"scripts": {
"start:dev": "main.py"
},
"keywords": [
"hello",
"there"
]
}
}
破解一份 YAML 的文件
我们示例中的 YAML 文件显示了应用程序的一些配置设置。与其他两种配置文件格式相比,有一些明显的区别,它们甚至使用了更多的符号解析。YAML 的核心是使用键:值对在文件中存储数据。这些键应该是字符串,它们可以用引号或者不用引号来写。这些值可以接受多种数据类型,如整数、字符串、列表、布尔值等。
写入 YAML 文件时,需要正确的缩进。使用制表符是不允许的,所以我们需要小心,否则我们将有林挺错误在我们的文件中。所以,它真的很简单,也很易读。不像 XML 或 JSON 文件,我们不必在阅读时解析多个符号。
configuration:
name: my-api-config
version: 1.0.0
about: "some description"
# This is a comment
description: |
Lorem ipsum dolor sit amet,
consectetur adipiscing elit
scripts:
"start:dev": main.py
keywords: ["hello", "there"]
我们还可以像上面写的那样在文件中包含注释,以及使用 |
管道字符的多行字符串,如示例代码所示。
用 PyYaml 处理 YAML 文件
在本节中,我们将使用 Python 的 PyYaml 模块对 YAML 文件执行一些基本操作,如读取、写入和修改数据。
- 安装
PyYaml
pip install pyyaml
读取一个yaml
文件
假设我们有一个带有一些配置的 yaml 文件,我们想用 Python 读取其中的内容。
文件名 : config_one.yml
configuration:
name: my-api-config
version: 1.0.0
about: some description
stack:
- python
- django
接下来,我们将创建一个新的 python 文件,并尝试读取 yml 文件。
文件名 : PyYaml.py
import yaml
with open("config_one.yml", "r") as first_file:
data = yaml.safe_load(first_file)
print(type(data))
print(data)
"""
Output:
<class 'dict'>
{'configuration': {'name': 'my-api-config', 'version': '1.0.0', 'about': 'some description', 'stack': ['python', 'django']}}
"""
说明:
我们正在使用 import yaml
导入**pyyaml**
模块。要读取一个 yaml 文件,我们首先必须以读取模式打开文件,然后使用 safe_load()
加载内容。由于不同的构造函数,比如load()
函数,所以有多个加载器。*使用load()
并不安全,因为它允许执行几乎任何脚本,包括恶意代码,这一点也不安全。*因此,safe_load()
是推荐的方式,它不会创建任何任意对象。
我们使用 Python 代码打印出 yaml 文件中的数据类型。控制台显示输出为 **<class dict>**
,包含的数据格式化为字典,存储为 key: value
对。
修改我们的yaml
文件
要修改我们已经加载的文件,我们必须首先确定数据类型。如果键的值是一个字符串,我们必须在更新 **key: value**
对之前将所有的附加值放在一个列表中。
import yaml
with open("config_one.yml", "r") as first_file:
data = yaml.safe_load(first_file)
print(type(data))
# Accessing our <class dict> and modifying value data using a key
data["configuration"]["stack"] = ["flask", "sql"]
# Appending data to the list
data["configuration"]["stack"].append("pillow")
print(data)
"""
Output:
<class 'dict'>
{'configuration': {'name': 'my-api-config', 'version': '1.0.0', 'about': 'some description', 'stack': ['flask', 'sql', 'pillow']}}
"""
说明:
我们在这里有一个嵌套字典,我们正在使用我们试图修改其值的键来访问数据。还有一个 append()
功能,用于向值列表添加另一个项目。请注意,这些修改仅在运行时执行。我们将把这些值写入新的 yaml 文件。
用修改后的数据写入一个yaml
文件
只需几行代码,就可以将上述数据以及修改后的值写入一个新文件中。
import yaml
with open("config_one.yml", "r") as first_file:
data = yaml.safe_load(first_file)
print(type(data))
# Accessing our <class dict> and modifying value data using a key
data["configuration"]["stack"] = ["flask", "sql"]
# Appending data to the list
data["configuration"]["stack"].append("pillow")
print(data)
# Writing a new yaml file with the modifications
with open("new_config.yaml", "w") as new_file:
yaml.dump(data, new_file)
文件名 : new_config.yaml
configuration:
about: some description
name: my-api-config
stack:
- flask
- sql
- pillow
version: 1.0.0
解释:
我们必须使用下面的语法提供新的文件名,然后使用带有两个参数的 yaml.dump
,数据变量包含原始的 yaml 代码以及对它所做的更改,第二个参数作为声明用于执行 write 方法的**new_file**
变量。我们可以看到,新文件保留了原始文件中的代码以及我们对其进行的更改。
摘要
在本文中,我们介绍了 yaml 文件的基本结构,并使用它来读取、修改和写入新文件的配置。我们还对同一个 YAML 文件使用了不同的语法,并将它与 JSON 和 XML 进行了比较。用于编写 YAML 文件的极简方法显然非常简单,易于阅读,这使得它成为各种技术栈使用的最流行的文本格式配置文件之一。