From 31c8d7831882c245ca7ac3bce64a2ba7e9a7d4dd Mon Sep 17 00:00:00 2001 From: "Xingyu.Wang" Date: Mon, 16 Jul 2018 18:31:29 +0800 Subject: [PATCH 1/5] PRF:20180704 Install an NVIDIA GPU on almost any machine.md @hopefully2333 --- ...all an NVIDIA GPU on almost any machine.md | 99 +++++++++---------- 1 file changed, 46 insertions(+), 53 deletions(-) diff --git a/translated/tech/20180704 Install an NVIDIA GPU on almost any machine.md b/translated/tech/20180704 Install an NVIDIA GPU on almost any machine.md index 7f49fcda9d..4731d0ae8f 100644 --- a/translated/tech/20180704 Install an NVIDIA GPU on almost any machine.md +++ b/translated/tech/20180704 Install an NVIDIA GPU on almost any machine.md @@ -1,137 +1,127 @@ -在绝大部分类型的机器上安装 NVIDIA 显卡驱动 +如何在绝大部分类型的机器上安装 NVIDIA 显卡驱动 ====== ![](https://fedoramagazine.org/wp-content/uploads/2018/06/nvidia-816x345.jpg) -无论是研究还是娱乐,安装一个最新的显卡驱动都能提升你的计算机性能,并且使你能全方位地实现新功能。本安装指南使用 Fedora 28 的新的第三方仓库来安装 NVIDIA 驱动。它将引导您完成硬件和软件两方面的安装,并且涵盖你需要得到的 NVIDIA 显卡启动和运行的一切。这个流程适用于任何支持 UEFI 的计算机和任意新的 NVIDIA 显卡。 +无论是研究还是娱乐,安装一个最新的显卡驱动都能提升你的计算机性能,并且使你能全方位地实现新功能。本安装指南使用 Fedora 28 的新的第三方仓库来安装 NVIDIA 驱动。它将引导您完成硬件和软件两方面的安装,并且涵盖需要让你的 NVIDIA 显卡启动和运行起来的一切知识。这个流程适用于任何支持 UEFI 的计算机和任意新的 NVIDIA 显卡。 ### 准备 本指南依赖于下面这些材料: - * 一台使用 UEFI 的计算机,如果你不确定你的电脑是否有这个这个固件,请运行 sudo dmidecode -t 0。如果输出中出现了“UEFI is supported”,你的安装过程就可以继续了。不然的话,虽然可以在技术上更新部分电脑来支持 UEFI,但是这个过程的要求很苛刻,我们通常不建议你这么使用。 - * 一个现代的,支持 UEFI 的 NVIDIA 的显卡 - * 一个满足你的 NVIDIA 显卡的功率和接线要求的电源(有关详细信息,请参考硬件和修改的章节) + * 一台使用 [UEFI][1] 的计算机,如果你不确定你的电脑是否有这种固件,请运行 `sudo dmidecode -t 0`。如果输出中出现了 “UEFI is supported”,你的安装过程就可以继续了。不然的话,虽然可以在技术上更新某些电脑来支持 UEFI,但是这个过程的要求很苛刻,我们通常不建议你这么使用。 + * 一个现代的、支持 UEFI 的 NVIDIA 的显卡 + * 一个满足你的 NVIDIA 显卡的功率和接线要求的电源(有关详细信息,请参考“硬件和修改”的章节) * 网络连接 * Fedora 28 系统 - - ### 安装实例 这个安装示例使用的是: * 一台 Optiplex 9010 的主机(一台相当老的机器) - * NVIDIA GeForce GTX 1050 Ti XLR8 游戏超频版 4 GB GDDR5 PCI Express 3.0 显卡 - * 为了满足新显卡的电源要求,电源升级为 EVGA – 80 PLUS 600 W ATX 12V/EPS 12V,这个最新的 PSU 比推荐的最低要求高了 300 W,但在大部分情况下,满足推荐的最低要求就足够了。 + * [NVIDIA GeForce GTX 1050 Ti XLR8 游戏超频版 4 GB GDDR5 PCI Express 3.0 显卡][2] + * 为了满足新显卡的电源要求,电源升级为 [EVGA – 80 PLUS 600 W ATX 12V/EPS 12V][3],这个最新的电源(PSU)比推荐的最低要求高了 300 W,但在大部分情况下,满足推荐的最低要求就足够了。 * 然后,当然的,Fedora 28 也别忘了. - - ### 硬件和修改 -#### PSU +#### 电源(PSU) -打开你的台式机的机箱,检查印刷在电源上的最大输出功率。然后,查看你的 NVIDIA 显卡的文档,确定推荐的最小电源功率要求(以瓦特为单位)。除此之外,检查你的显卡,看它是否需要额外的接线,例如 6 针口连接器,大多数的入门级显卡只从主板获取电力,但是有一些显卡需要额外的电力,如果出现以下情况,你需要升级的 PSU: +打开你的台式机的机箱,检查印刷在电源上的最大输出功率。然后,查看你的 NVIDIA 显卡的文档,确定推荐的最小电源功率要求(以瓦特为单位)。除此之外,检查你的显卡,看它是否需要额外的接线,例如 6 针连接器,大多数的入门级显卡只从主板获取电力,但是有一些显卡需要额外的电力,如果出现以下情况,你需要升级你的电源: 1. 你的电源的最大输出功率低于显卡建议的最小电源功率。注意:根据一些显卡厂家的说法,比起推荐的功率,预先构建的系统可能会需要更多或更少的功率,而这取决于系统的配置。如果你使用的是一个特别耗电或者特别节能的配置,请灵活决定你的电源需求。 2. 你的电源没有提供必须的接线口来为你的显卡供电。 - - -PSU 的更换很容易,但是在你拆除你当前正在使用的电源之前,请务必注意你的接线布局。除此之外,请确保你选择的 PSU 适合你的机箱。 +电源的更换很容易,但是在你拆除你当前正在使用的电源之前,请务必注意你的接线布局。除此之外,请确保你选择的电源适合你的机箱。 #### CPU -虽然在大多数老机器上安装高性能的 NVIDIA 显卡是可能的,但是一个缓慢或受损的 CPU 会阻碍显卡性能的发挥,如果要计算在你的机器上瓶颈效果的影响,请点击这里。知道你的 CPU 性能来避免高性能的显卡和 CPU 无法保持匹配是很重要的。升级你的 CPU 是一个潜在的考虑因素。 +虽然在大多数老机器上安装高性能的 NVIDIA 显卡是可能的,但是一个缓慢或受损的 CPU 会阻碍显卡性能的发挥,如果要计算在你的机器上瓶颈效果的影响,请点击[这里][4]。了解你的 CPU 性能来避免高性能的显卡和 CPU 无法保持匹配是很重要的。升级你的 CPU 是一个潜在的考虑因素。 #### 主板 在继续进行之前,请确认你的主板和你选择的显卡是兼容的。你的显卡应该插在最靠近散热器的 PCI-E x16 插槽中。确保你的设置为显卡预留了足够的空间。此外,请注意,现在大部分的显卡使用的都是 PCI-E 3.0 技术。虽然这些显卡如果插在 PCI-E 3.0 插槽上会运行地最好,但如果插在一个旧版的插槽上的话,性能也不会受到太大的影响。 ### 安装 + +1、 首先,打开终端更新你的包管理器(如果没有更新的话): + ``` sudo dnf update - ``` -2\. 然后,使用这条简单的命令进行重启: +2、 然后,使用这条简单的命令进行重启: + ``` reboot - ``` -3\. 在重启之后,安装 Fedora 28 的工作站仓库: +3、 在重启之后,安装 Fedora 28 的工作站的仓库: + ``` sudo dnf install fedora-workstation-repositories - ``` -4\. 接着,设置 NVIDIA 驱动仓库: +4、 接着,设置 NVIDIA 驱动的仓库: + ``` sudo dnf config-manager --set-enabled rpmfusion-nonfree-nvidia-driver - ``` -5\. 然后,再次重启。 +5、 然后,再次重启。 + +6、 在这次重启之后,通过下面这条命令验证是否添加了仓库: -6\. 在这次重启之后,通过下面这条命令验证是否添加了仓库: ``` sudo dnf repository-packages rpmfusion-nonfree-nvidia-driver info - ``` -如果加载了多个 NVIDIA 工具和它们各自的参数,请继续进行下一步。如果没有,你可能在添加新仓库的时候遇到了一个错误。你应该再试一次。 +如果加载了多个 NVIDIA 工具和它们各自的 spec 文件,请继续进行下一步。如果没有,你可能在添加新仓库的时候遇到了一个错误。你应该再试一次。 -7\. 登陆,连接到互联网,然后打开软件应用程序。点击加载项>硬件驱动> NVIDIA Linux 图形驱动>安装。 +7、 登录,连接到互联网,然后打开“软件”应用程序。点击“加载项>硬件驱动> NVIDIA Linux 图形驱动>安装”。 +如果你使用更老的显卡或者想使用多个显卡,请进一步查看 [RPMFusion 指南][8]。最后,要确保启动成功,设置 `/etc/gdm/custom.conf` 中的 `WaylandEnable=false`,确认避免使用安全启动。 接着,再一次重启。 -8\. 在重新启动后,转到侧栏上的‘显示应用程序’,然后打开新添加的 NVIDIA X 服务器设置应用程序。一个图形界面会被打开,然后出现一个对话框并包含以下信息: +8、这个过程完成后,关闭所有的应用并**关机**。拔下电源插头,然后按下电源按钮以释放余电,避免你被电击。如果你对电源有开关,关闭它。 -![NVIDIA X Server Prompt][5] +9、 最后,安装显卡,拔掉老的显卡并将新的显卡插入到正确的 PCI-E x16 插槽中。成功安装新的显卡之后,关闭你的机箱,插入电源 ,然后打开计算机,它应该会成功启动。 -请参考应用程序的建议,但是在这样做之前,请确保你的 NVIDIA 显卡就在手里,并且已准备好去安装。请注意在以 root 身份运行 nvidia xconfig 的时候,如果在没有立刻安装显卡的情况下关闭电源,这可能会造成严重损坏。这样做可能会导致你的电脑无法启动,并强制你通过重启屏幕来修复系统。重新安装 Fedora 会修复这些问题,但是效果会更加糟糕。 - -如果你已准备好继续,请输入下面这条命令: -``` -sudo nvidia-xconfig - -``` - -如果系统提示你完成任何地下载,请选择接收然后继续。 - -9\. 一旦这个过程完成,关闭所有的应用程序并关闭电脑,拔掉机器的电源。然后,按一下电源按钮来释放掉多有的剩余电量,以此来保护你自己不会被点击。如果你的 PSU 有电源开关,请将其关闭。 - -10\. 最后,安装显卡,拔掉老的显卡并将新的显卡插入到正确的 PCI-E x16 插槽中,风扇朝着下方。如果这个位置已经没有空间让风扇通风。那作为代替,如果可以的话就把显卡面朝上放置。成功安装新的显卡之后,关闭你的机箱,插入 PSU ,然后打开计算机,它应该会成功启动。 - -**注意:** 要禁用此安装中使用的 NVIDIA 驱动仓库,或者要禁用所有的 Fedora 工作站仓库,请参考这个 Fedora Wiki 页面。 +**注意:** 要禁用此安装中使用的 NVIDIA 驱动仓库,或者要禁用所有的 Fedora 工作站仓库,请参考这个 [Fedora Wiki 页面][6]。 ### 验证 -1\. 如果你新安装的显卡已连接到你的显示器并显示正确,则表明你的 NVIDIA 驱动程序已成功和显卡建立连接。 +1、 如果你新安装的 NVIDIA 显卡已连接到你的显示器并显示正确,则表明你的 NVIDIA 驱动程序已成功和显卡建立连接。 -如果你想去查看你的设置,或者验证驱动是否在正常工作(如果机箱的主板里安装了两块显卡),再次打开 NVIDIA X 服务器设置应用程序。这次,你应该不会被提示一个错误信息,并且系统会给出有关 X 的设置文件和你的 NVIDIA 显卡的信息。(请参考下面的屏幕截图) +如果你想去查看你的设置,或者验证驱动是否在正常工作(这里,主板上安装了两块显卡),再次打开 “NVIDIA X 服务器设置应用程序”。这次,你应该不会得到错误信息提示,并且系统会给出有关 X 的设置文件和你的 NVIDIA 显卡的信息。(请参考下面的屏幕截图) ![NVIDIA X Server Settings][7] 通过这个应用程序,你可以根据你的需要需改 X 配置文件,并可以监控显卡的性能,时钟速度和温度信息。 -2\. 为确保新显卡以满功率运行,一次显卡性能测试是非常必要的。GL Mark 2,是一个提供后台处理、构建、照明、纹理等等有关信息的标准工具。它提供了一个优秀的解决方案。GL Mark 2 记录了各种各样的图形测试的帧速率,然后输出一个总体的性能评分(这被称为 glmark2 分数)。 +2、 为确保新显卡以满功率运行,显卡性能测试是非常必要的。GL Mark 2,是一个提供后台处理、构建、照明、纹理等等有关信息的标准工具。它提供了一个优秀的解决方案。GL Mark 2 记录了各种各样的图形测试的帧速率,然后输出一个总体的性能评分(这被称为 glmark2 分数)。 **注意:** glxgears 只会测试你的屏幕或显示器的性能,不会测试显卡本身,请使用 GL Mark 2。 -要运行 GLMark2: +要运行 GLMark2: 1. 打开终端并关闭其他所有的应用程序 - 2. 运行 sudo dnf install glmark2 命令 - 3. 运行 glmark2 命令 + 2. 运行 `sudo dnf install glmark2` 命令 + 3. 运行 `glmark2` 命令 4. 允许运行完整的测试来得到最好的结果。检查帧速率是否符合你对这块显卡的预期。如果你想要额外的验证,你可以查阅网站来确认是否已有你这块显卡的 glmark2 测试评分被公布到网上,你可以比较这个分数来评估你这块显卡的性能。 5. 如果你的帧速率或者 glmark2 评分低于预期,请思考潜在的因素。CPU 造成的瓶颈?其他问题导致? 如果诊断的结果很好,就开始享受你的新显卡吧。 +### 参考链接 + +- [How to benchmark your GPU on Linux][9] +- [How to install a graphics card][10] +- [The Fedora Wiki Page][6] +- [The Bottlenecker][4] +- [What Is Unified Extensible Firmware Interface (UEFI)][1] -------------------------------------------------------------------------------- @@ -140,7 +130,7 @@ via: https://fedoramagazine.org/install-nvidia-gpu/ 作者:[Justice del Castillo][a] 选题:[lujun9972](https://github.com/lujun9972) 译者:[hopefully2333](https://github.com/hopefully2333) -校对:[校对者ID](https://github.com/校对者ID) +校对:[wxy](https://github.com/wxy) 本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 @@ -152,3 +142,6 @@ via: https://fedoramagazine.org/install-nvidia-gpu/ [5]:https://bytebucket.org/kenneym/fedora-28-nvidia-gpu-installation/raw/7bee7dc6effe191f1f54b0589fa818960a8fa18b/nvidia_xserver_error.jpg?token=c6a7effe35f1c592a155a4a46a068a19fd060a91 (NVIDIA X Sever Prompt) [6]:https://fedoraproject.org/wiki/Workstation/Third_Party_Software_Repositories [7]:https://bytebucket.org/kenneym/fedora-28-nvidia-gpu-installation/raw/7bee7dc6effe191f1f54b0589fa818960a8fa18b/NVIDIA_XCONFIG.png?token=64e1a7be21e5e9ba157f029b65e24e4eef54d88f (NVIDIA X Server Settings) +[8]:https://rpmfusion.org/Howto/NVIDIA?highlight=%28CategoryHowto%29 +[9]: https://www.howtoforge.com/tutorial/linux-gpu-benchmark/ +[10]: https://www.pcworld.com/article/2913370/components-graphics/how-to-install-a-graphics-card.html \ No newline at end of file From 887d5c7a682a1fa75535ff7e42db275c3716a6fb Mon Sep 17 00:00:00 2001 From: "Xingyu.Wang" Date: Mon, 16 Jul 2018 18:32:01 +0800 Subject: [PATCH 2/5] PUB:20180704 Install an NVIDIA GPU on almost any machine.md @hopefully2333 https://linux.cn/article-9841-1.html --- .../20180704 Install an NVIDIA GPU on almost any machine.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {translated/tech => published}/20180704 Install an NVIDIA GPU on almost any machine.md (100%) diff --git a/translated/tech/20180704 Install an NVIDIA GPU on almost any machine.md b/published/20180704 Install an NVIDIA GPU on almost any machine.md similarity index 100% rename from translated/tech/20180704 Install an NVIDIA GPU on almost any machine.md rename to published/20180704 Install an NVIDIA GPU on almost any machine.md From 435a11f86cd2bf6d8528d149e69d0810e8a378b6 Mon Sep 17 00:00:00 2001 From: Ezio Date: Tue, 17 Jul 2018 10:03:31 +0800 Subject: [PATCH 3/5] =?UTF-8?q?20180717-1=20=E9=80=89=E9=A2=98=20-=20BriFu?= =?UTF-8?q?ture=20=E7=94=B3=E9=A2=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @BriFuture --- ...nsive Guide to Creating Streams in RxJS.md | 1031 +++++++++++++++++ 1 file changed, 1031 insertions(+) create mode 100644 sources/tech/20170709 The Extensive Guide to Creating Streams in RxJS.md diff --git a/sources/tech/20170709 The Extensive Guide to Creating Streams in RxJS.md b/sources/tech/20170709 The Extensive Guide to Creating Streams in RxJS.md new file mode 100644 index 0000000000..04a25a5cc1 --- /dev/null +++ b/sources/tech/20170709 The Extensive Guide to Creating Streams in RxJS.md @@ -0,0 +1,1031 @@ +BriFuture is translating + +The Extensive Guide to Creating Streams in RxJS +============================================================ + +![](https://cdn-images-1.medium.com/max/900/1*hj8mGnl5tM_lAlx5_vqS-Q.jpeg) + +For most developers the first contact with RxJS is established by libraries, like Angular. Some functions return streams and to make use of them the focus naturally is on operators. + +At some point mixing reactive and some of the non-reactive code seems practical. Then people get interested in creating streams themselves. Whenever you are dealing with asynchronous code or data processing, chances are that streams are a good option. + +RxJS offers numerous ways to create streams. Whatever situation you are facing, there is one perfect way for you to create a stream. You may not need them all, but knowing them can save you time and some code. + +I have put all possible options into four categories, based on their main purpose: + +* Stream existing data + +* Generate data + +* Interoperate with existing APIs + +* Combine and select from existing streams + +Note: The examples use RxJS 6 and can be different from older versions. Something that’s different for sure is the way you import the functions. + +RxJS 6 + +``` +import {of, from} from 'rxjs'; +``` + +``` +of(...); +from(...); +``` + +RxJS < 6 + +``` +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/observable/of'; +import 'rxjs/add/observable/from'; +``` + +``` +Observable.of(...); +Observable.from(...); +``` + +``` +//or +``` + +``` +import { of } from 'rxjs/observable/of'; +import { from } from 'rxjs/observable/from'; +``` + +``` +of(...); +from(...); +``` + +A note on the stream diagrams: + +* | means the stream completes + +* X means the stream terminates with an error + +* … means the stream goes on indefinitely + +* * * + +### Stream Existing Data + +You have some data and want to feed them into a stream. There are three flavors, all of which also allow you to provide a scheduler as the last argument (If you want to know more about schedulers you can take a look at my [previous article][5]). All resulting streams will be cold. + +#### of + +Use  _of_  if you have only one element or a few separate ones. + +``` +of(1,2,3) + .subscribe(); +``` + +``` +// Produces +// 1 2 3 | +``` + +#### from + +Use  _from_  if you have an array or  _Iterable_  and want all elements in it emitted to the stream. You can also use it to convert a promise to an observable. + +``` +const foo = [1,2,3]; +``` + +``` +from(foo) + .subscribe(); +``` + +``` +// Produces +// 1 2 3 | +``` + +#### pairs + +Streams key/value pairs of an object. Particularly useful if the object represents a dictionary. + +``` +const foo = { a: 1, b: 2}; +``` + +``` +pairs(foo) + .subscribe(); +``` + +``` +// Produces +// [a,1] [b,2] | +``` + +#### What about other data structures? + +Maybe your data is stored in a custom structure that does not implement the  _Iterable_  protocol or you have a recursive, tree-like structure. In those cases one of following options might be suitable: + +* Extract data to an array first + +* Use the  _generate_  function from the next section to iterate over the data + +* Create a custom stream (see that section) + +* Create an iterator + +Options 2 and 3 are explained later, so I focus on creating an iterator here. We can create a stream from an  _iterable_  by calling  _from_ . An  _iterable_  is an object that can deliver an iterator (see [this mdn article][6] if you are interested in the details). + +One simple way to create an iterator is a [generator function][7]. When you invoke a generator function, it returns an object that conforms to both the  _iterable_ protocol and the  _iterator_  protocol. + +``` +//Our custom data structure +class List { + add(element) ... + get(index) ... + get size() ... + ... +} +``` + +``` +function* listIterator(list) { + for (let i = 0; i console.log("foo"); +//prints foo after 5 seconds +``` + +Most of the time interval will be used to process data periodically: + +``` +interval(10000).pipe( + flatMap(i => fetch("https://server/stockTicker") +).subscribe(updateChart) +``` + +This will get new data every 10 seconds and update the screen. + +#### generate + +A more complex function that allows you to emit a sequence of any type. It has some overloads and I show you the most interesting one(s): + +``` +generate( + 0, // start with this value + x => x < 10, // condition: emit as long as a value is less than 10 + x => x*2 // iteration: double the previous value +).subscribe(); +``` + +``` +// Produces +// 1 2 4 8 | +``` + +You can also use it to iterate over values, if a structure does not implement the  _Iterable_  interface. Let’s try that with our list example from before: + +``` +const myList = new List(); +myList.add(1); +myList.add(3); +``` + +``` +generate( + 0, // start with this value + i => i < list.size, // condition: emit until we have processed the whole list + i => ++i, // iteration: get next index + i => list.get(i) // selection: get value from list +).subscribe(); +``` + +``` +// Produces +// 1 3 | +``` + +As you can see I have added another argument: The selector. It works like the  _map_  operator and converts the generated value to something more useful. + +* * * + +### Empty Streams + +Sometimes you need to pass or return a stream that does not emit any data. There are three functions, one for every possible situation. You can pass a scheduler to all functions.  _empty_  and  _throwError_  accept a scheduler as argument. + +#### empty + +Creates a stream that completes without emitting a value. + +``` +empty() + .subscribe(); +``` + +``` +// Produces +// | +``` + +#### never + +Creates a stream that never completes, but also never emits anything. + +``` +never() + .subscribe(); +``` + +``` +// Produces +// ... +``` + +#### throwError + +Creates a stream that fails without emitting a value. + +``` +throwError('error') + .subscribe(); +``` + +``` +// Produces +// X +``` + +* * * + +### Hook into existing APIs + +Not all libraries and all of your legacy code use or support streams. Luckily RxJS provides functions to bridge non-reactive and reactive code. This section discusses only patterns provided by RxJS for exactly that purpose. + +You may also be interested in this [extensive article][8] from [Ben Lesh][9] covering probably every possible way to interoperate with promises. + +#### from + +We already had that and I list it here too because it can be used to wrap a promise into an observable. + +``` +from(new Promise(resolve => resolve(1))) + .subscribe(); +``` + +``` +// Produces +// 1 | +``` + +#### fromEvent + +Adds an event listener to a DOM element and I am pretty sure you know that. What you may not know is that you can also use it with other types, e.g. a jQuery object. + +``` +const element = $('#fooButton'); // creates a jQuery object for a DOM element +``` + +``` +from(element, 'click') + .subscribe(); +``` + +``` +// Produces +// clickEvent ... +``` + +#### fromEventPattern + +In order to understand why we need this one if we already have fromEvent, we need to understand how fromEvent works. Take this code: + +``` +from(document, 'click') + .subscribe(); +``` + +It tells RxJS that we want to listen to click events from the document. During subscription RxJS finds out that document is an  _EventTarget_  type, hence it can call  _addEventListener_  on it. If we pass a jQuery object instead of document, then RxJS knows that it has to call  _on_  instead. + +This example using  _fromEventPattern_  basically does the same as  _fromEvent_ : + +``` +function addClickHandler(handler) { + document.addEventListener('click', handler); +} +``` + +``` +function removeClickHandler(handler) { + document.removeEventListener('click', handler); +} +``` + +``` +fromEventPattern( + addClickHandler, + removeClickHandler, +) +.subscribe(console.log); +``` + +``` +//is equivalent to +fromEvent(document, 'click') +``` + +RxJS itself creates the actual listener ( _handler_ ) and your job is to add and remove it. The purpose of  _fromEventPattern_  is basically to tell RxJS how to register and remove event listeners. + +Now imagine you use a library where you have to call a method named  _registerListener_ . We no longer can use  _fromEvent_  because it doesn’t know how to deal with it. + +``` +const listeners = []; +``` + +``` +class Foo { + registerListener(listener) { + listeners.push(listener); + } +``` + +``` + emit(value) { + listeners.forEach(listener => listener(value)); + } +} +``` + +``` +const foo = new Foo(); +``` + +``` +fromEventPattern(listener => foo.registerListener(listener)) + .subscribe(); +``` + +``` +foo.emit(1); +``` + +``` +// Produces +// 1 ... +``` + +When we call foo.emit(1) the listener from RxJS is called and it can emit the value to the stream. + +You could also use it to listen to more than one event type or connect with any API that communicates via callbacks, e.g. the WebWorker API: + +``` +const myWorker = new Worker('worker.js'); +``` + +``` +fromEventPattern( + handler => { myWorker.onmessage = handler }, + handler => { myWorker.onmessage = undefined } +) +.subscribe(); +``` + +``` +// Produces +// workerMessage ... +``` + +#### bindCallback + +This is similar to fromEventPattern, but it’s only meant for single values. That is the stream completes after the callback has been invoked . The usage is different as well – You wrap the function with bindCallback, then it magically returns a stream when it‘s called: + +``` +function foo(value, callback) { + callback(value); +} +``` + +``` +// without streams +foo(1, console.log); //prints 1 in the console +``` + +``` +// with streams +const reactiveFoo = bindCallback(foo); +//when we call reactiveFoo it returns an observable +``` + +``` +reactiveFoo(1) + .subscribe(console.log); //prints 1 in the console +``` + +``` +// Produces +// 1 | +``` + +#### websocket + +Yes, you can actually create a websocket connection and expose it as stream: + +``` +import { webSocket } from 'rxjs/webSocket'; +``` + +``` +let socket$ = webSocket('ws://localhost:8081'); +``` + +``` +//receive messages +socket$.subscribe( + (msg) => console.log('message received: ' + msg), + (err) => console.log(err), + () => console.log('complete') * ); +``` + +``` +//send message +socket$.next(JSON.stringify({ op: 'hello' })); +``` + +It’s really that easy to add websocket support to your application.  _websocket_ creates a subject. That means you can both subscribe to it in order to receive messages and send messages through it by calling  _next_ . + +#### ajax + +Just so you know it: Similar to websocket and offers support for AJAX requests. You probably use a library or framework with built-in AJAX support anyway. And if you don’t then I recommend using fetch (and a polyfill if necessary) instead and wrap the returned promise into an observable (see also the  _defer_  function below). + +* * * + +### Custom Streams + +Sometimes the already presented functions are not flexible enough. Or you need more control over subscriptions. + +#### Subject + +A subject is a special object that allows you to emit data to the stream and control it. The subject itself is also an observable, but if you want to expose the stream to other code it’s recommended to use the  _asObservable_  method. That way you cannot accidentally call the source methods. + +``` +const subject = new Subject(); +const observable = subject.asObservable(); +``` + +``` +observable.subscribe(); +``` + +``` +subject.next(1); +subject.next(2); +subject.complete(); +``` + +``` +// Produces +// 1 2 | +``` + +Note that values emitted before subscriptions are “lost”: + +``` +const subject = new Subject(); +const observable = subject.asObservable(); +``` + +``` +subject.next(1); +``` + +``` +observable.subscribe(console.log); +``` + +``` +subject.next(2); +subject.complete(); +``` + +``` +// Prints +// 2 +``` + +In addition to the regular subject RxJS provides three specialized versions. + +The  _AsyncSubject_  emits only the last value after completion. + +``` +const subject = new AsyncSubject(); +const observable = subject.asObservable(); +``` + +``` +observable.subscribe(console.log); +``` + +``` +subject.next(1); +subject.next(2); +subject.complete(); +``` + +``` +// Prints +// 2 +``` + +The  _BehaviorSubject_  allows you to provide a (default) value that will be emitted to every subscriber if no other value has been emitted so far. Otherwise subscribers receive the last emitted value. + +``` +const subject = new BehaviorSubject(1); +const observable = subject.asObservable(); +``` + +``` +const subscription1 = observable.subscribe(console.log); +``` + +``` +subject.next(2); +subscription1.unsubscribe(); +``` + +``` +// Prints +// 1 +// 2 +``` + +``` +const subscription2 = observable.subscribe(console.log); +``` + +``` +// Prints +// 2 +``` + +The  _ReplaySubject_  stores all emitted values up to a certain number, time or infinitely. All new subscribers will then get all stored values. + +``` +const subject = new ReplaySubject(); +const observable = subject.asObservable(); +``` + +``` +subject.next(1); +``` + +``` +observable.subscribe(console.log); +``` + +``` +subject.next(2); +subject.complete(); +``` + +``` +// Prints +// 1 +// 2 +``` + +You can find more information on subjects in the [ReactiveX documentation][10](that also offers additional links). [Ben Lesh][11] offers some insights on subjects in [On The Subject Of Subjects][12], as does [Nicholas Jamieson][13] [in RxJS: Understanding Subjects][14]. + +#### Observable + +You can create an observable by simply using the the new operator. With the function you pass in you can control the stream. That function is called whenever someone subscribe and it receives an observer that you can use like a subject, i.e. call next, complete and error. + +Let’s revisit our list example: + +``` +const myList = new List(); +myList.add(1); +myList.add(3); +``` + +``` +new Observable(observer => { + for (let i = 0; i { + //stream it, baby! +``` + +``` + return () => { + //clean up + }; +}) +.subscribe(); +``` + +#### Subclass Observable + +Before the advent of lettable operators this was a way to implement custom operators. RxJS extends  _Observable_  internally. One example is  _Subject_ , another is the  _publish_  operator. It returns a  _ConnectableObservable_  that provides the additional method  _connect_ . + +#### Implement Subscribable + +Sometimes you already have an object that holds state and can emit values. You can turn it into an observable if you implement the Subscribable interface that consists of only a subscribe method. + +``` +interface Subscribable { subscribe(observerOrNext?: PartialObserver | ((value: T) => void), error?: (error: any) => void, complete?: () => void): Unsubscribable} +``` + +* * * + +### Combine and Select Existing Streams + +Knowing how to create individual streams is not enough. Sometimes you are confronted with several streams but you only need one. Some of the functions are also available as operators, that’s why I won’t go too deep here. I can recommend an [article][15] from [Max NgWizard K][16] that even contains some fancy animations. + +One more recommendation: You can interactively play with combination operators on [RxMarbles][17] by dragging around elements. + +#### The ObservableInput type + +Operators and functions that expect a stream (or an array of streams) usually do not only work with observables. Instead they actually expect the argument to be of the type ObservableInput that is defined as follows: + +``` +type ObservableInput = SubscribableOrPromise | ArrayLike | Iterable; +``` + +That means you can e.g. pass promises or arrays without needing to convert them to observables first! + +#### defer + +The main purpose is to defer the creation of an observable to the time when someone wants to subscribe. This is useful if + +* the creation of the observable is computationally expensive + +* you want a new observable for each subscriber + +* you want to choose between different observables at subscription time + +* some code must not be executed before subscription + +The last point includes one not so obvious use case: Promises (defer can also return a promise). Take this example using the fetch API: + +``` +function getUser(id) { + console.log("fetching data"); + return fetch(`https://server/user/${id}`); +} +``` + +``` +const userPromise = getUser(1); +console.log("I don't want that request now"); +``` + +``` +//somewhere else +userPromise.then(response => console.log("done"); +``` + +``` +// Prints +// fetching data +// I don't want that request now +// done +``` + +Promises are executed immediately, whereas streams are executed when you subscribe. The very moment we call getUser, a request is sent even if we did not want that at that point. Sure, we can use from to convert a promise to an observable, but the promise we pass has already been created / executed. defer allows us to wait until subscription: + +``` +const user$ = defer(() => getUser(1)); +``` + +``` +console.log("I don't want that request now"); +``` + +``` +//somewhere else +user$.subscribe(response => console.log("done"); +``` + +``` +// Prints +// I don't want that request now +// fetching data +// done +``` + +#### iif + + _iif_  covers a special use case of  _defer_ : Deciding between two streams at subscription time: + +``` +iif( + () => new Date().getHours() < 12, + of("AM"), + of("PM") +) +.subscribe(); +``` + +``` +// Produces +// AM before noon, PM afterwards +``` + +To quote the documentation: + +> Actually `[iif][3]` can be easily implemented with `[defer][4]`and exists only for convenience and readability reasons. + +#### onErrorResumeNext + +Starts the first stream and if it fails continues with the next stream. The error is ignored. + +``` +const stream1$ = of(1, 2).pipe( + tap(i => { if(i>1) throw 'error'}) //fail after first element +); +``` + +``` +const stream2$ = of(3,4); +``` + +``` +onErrorResumeNext(stream1$, stream2$) + .subscribe(console.log); +``` + +``` +// Produces +// 1 3 4 | +``` + +This can be useful if you have more than one web service. In case the main one fails the backup service can be called automatically. + +#### forkJoin + +Lets streams run concurrently and emits their last values in an array when they are completed. Since only the last values of each streams are emitted it’s typically used for streams that only emit a single element, like HTTP requests. You want the requests run in parallel and do something when all have responses. + +``` +function handleResponses([user, account]) { + // do something +} +``` + +``` +forkJoin( + fetch("https://server/user/1"), + fetch("https://server/account/1") +) +.subscribe(handleResponses); +``` + +#### merge / concat + +Emits every value that is emitted by one of the source observables. + + _merge_  supports a parameter that let’s you define how many source streams are subscribed to concurrently. The default is unlimited. A value of 1 would mean listen to one source stream and when it’s completed subscribe to the next one. Since that is a very common scenario you RxJS provides an explicit function:  _concat_ . + +``` +merge( + interval(1000).pipe(mapTo("Stream 1"), take(2)), + interval(1200).pipe(mapTo("Stream 2"), take(2)), + timer(0, 1000).pipe(mapTo("Stream 3"), take(2)), + 2 //two concurrent streams +) +.subscribe(); +``` + +``` +// Subscribes to stream 1 and 2 only +``` + +``` +// prints +// Stream 1 -> after 1000ms +// Stream 2 -> after 1200ms +// Stream 1 -> after 2000ms +``` + +``` +// Stream 1 has completed, now subscribe to stream 3 +``` + +``` +// prints +// Stream 3 -> after 0 ms +// Stream 2 -> after 400 ms (2400ms from beginning) +// Stream 3 -> after 1000ms +``` + +``` + +merge( + interval(1000).pipe(mapTo("Stream 1"), take(2)), + interval(1200).pipe(mapTo("Stream 2"), take(2)) + 1 +) +// is equal to +concat( + interval(1000).pipe(mapTo("Stream 1"), take(2)), + interval(1200).pipe(mapTo("Stream 2"), take(2)) +) +``` + +``` +// prints +// Stream 1 -> after 1000ms +// Stream 1 -> after 2000ms +// Stream 2 -> after 3200ms +// Stream 2 -> after 4400ms +``` + +#### zip / combineLatest + +While  _merge_  and  _concat_  emit all values from the source streams individually, zip and combineLatest combine one value of each source stream and emit them together.  _zip_  combines the first values emitted by all(!) source streams, the second values and so on. This is useful if the contents of the streams are related. + +``` +zip( + interval(1000), + interval(1200), +) +.subscribe(); +``` + +``` +// Produces +// [0, 0] [1, 1] [2, 2] ... +``` + + _combineLatest_  is similar but combines the latest values emitted by the source streams. Nothing happens until all source streams have emitted at least one value. From then on every time a source stream emits a value, it is combined with the last values of the other streams. + +``` +combineLatest( + interval(1000), + interval(1200), +) +.subscribe(); +``` + +``` +// Produces +// [0, 0] [1, 0] [1, 1] [2, 1] ... +``` + +Both functions allow you to pass a selector function that can combine the elements to something else than an array: + +``` +zip( + interval(1000), + interval(1200), + (e1, e2) -> e1 + e2 +) +.subscribe(); +``` + +``` +// Produces +// 0 2 4 6 ... +``` + +#### race + +The first stream that emits a value is selected. So the resulting stream is essentially the fastest stream. + +``` +race( + interval(1000), + of("foo") +) +.subscribe(); +``` + +``` +// Produces +// foo | +``` + +Since  _of_  produces a value immediately it’s the faster stream and the stream that gets selected. + +* * * + +### Conclusion + +That have been a lot of ways to create observables. Knowing them is essential if you want to create reactive APIs or want to combine legacy APIs with reactive ones. + +I have presented you all options but much more could be said about all of them. If you want to dive deeper I highly recommend consulting the [documentation][20] or reading the suggested articles. + +Another interesting way to get insight is [RxViz][21]. You write RxJS code and the resulting streams are then displayed graphically and animated. + +-------------------------------------------------------------------------------- + +via: https://blog.angularindepth.com/the-extensive-guide-to-creating-streams-in-rxjs-aaa02baaff9a + +作者:[Oliver Flaggl][a] +译者:[译者ID](https://github.com/译者ID) +校对:[校对者ID](https://github.com/校对者ID) + +本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 + +[a]:https://blog.angularindepth.com/@abetteroliver +[1]:https://rxjs-dev.firebaseapp.com/api/index/Subscribable +[2]:https://rxjs-dev.firebaseapp.com/api/index/Subscribable#subscribe +[3]:https://rxjs-dev.firebaseapp.com/api/index/iif +[4]:https://rxjs-dev.firebaseapp.com/api/index/defer +[5]:https://itnext.io/concurrency-and-asynchronous-behavior-with-rxjs-11b0c4b22597 +[6]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols +[7]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function* +[8]:https://medium.com/@benlesh/rxjs-observable-interop-with-promises-and-async-await-bebb05306875 +[9]:https://medium.com/@benlesh +[10]:http://reactivex.io/documentation/subject.html +[11]:https://medium.com/@benlesh +[12]:https://medium.com/@benlesh/on-the-subject-of-subjects-in-rxjs-2b08b7198b93 +[13]:https://medium.com/@cartant +[14]:https://blog.angularindepth.com/rxjs-understanding-subjects-5c585188c3e1 +[15]:https://blog.angularindepth.com/learn-to-combine-rxjs-sequences-with-super-intuitive-interactive-diagrams-20fce8e6511 +[16]:https://medium.com/@maximus.koretskyi +[17]:http://rxmarbles.com/#merge +[18]:https://rxjs-dev.firebaseapp.com/api/index/ObservableInput +[19]:https://rxjs-dev.firebaseapp.com/api/index/SubscribableOrPromise +[20]:http://reactivex.io/documentation/operators.html#creating +[21]:https://rxviz.com/ From 657cb64cebee0c5417efca99a08fa620251165af Mon Sep 17 00:00:00 2001 From: Ezio Date: Tue, 17 Jul 2018 10:05:25 +0800 Subject: [PATCH 4/5] =?UTF-8?q?20180717-2=20=E9=80=89=E9=A2=98=20-=20MjSev?= =?UTF-8?q?en=20=E7=94=B3=E9=A2=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @MjSeven --- .../20180710 Python Sets What Why and How.md | 394 ++++++++++++++++++ 1 file changed, 394 insertions(+) create mode 100644 sources/tech/20180710 Python Sets What Why and How.md diff --git a/sources/tech/20180710 Python Sets What Why and How.md b/sources/tech/20180710 Python Sets What Why and How.md new file mode 100644 index 0000000000..32e0f6eda8 --- /dev/null +++ b/sources/tech/20180710 Python Sets What Why and How.md @@ -0,0 +1,394 @@ +MjSeven is translating + + +Python Sets: What, Why and How +============================================================ + +posted on 07/10/2018 by [wilfredinni][5] + +![Python Sets: What, Why and How](https://raw.githubusercontent.com/wilfredinni/pysheetComments/master/2018-july/python_sets/sets.png) + +Python comes equipped with several built-in data types to help us organize our data. These structures include lists, dictionaries, tuples and sets. + +From the Python 3 documentation: + +> A set is an  _unordered collection_  with no  _duplicate elements_ . Basic uses include  _membership testing_  and  _eliminating duplicate entries_ . Set objects also support mathematical operations like  _union_ ,  _intersection_ ,  _difference_ , and  _symmetric difference_ . + +In this article, we are going to review and see examples of every one of the elements listed in the above definition. Let's start right away and see how we can create them. + +### Initializing a Set + +There are two ways to create a set: one is to provide the built-in function `set()` with a list of elements, and the other is to use the curly braces `{}`. + +Initializing a set using the `set()` built-in function: + +``` +>>> s1 = set([1, 2, 3]) +>>> s1 +{1, 2, 3} +>>> type(s1) + + +``` + +Initializing a set using curly braces `{}` + +``` +>>> s2 = {3, 4, 5} +>>> s2 +{3, 4, 5} +>>> type(s2) + +>>> + +``` + +As you can see, both options are valid. The problem comes when what we want is an empty one: + +``` +>>> s = {} +>>> type(s) + + +``` + +That's right, we will get a dictionary instead of a set if we use empty curly braces =) + +It's a good moment to mention that for the sake of simplicity, all the examples provided in this article will use single digit integers, but sets can have all the [hashable][6] data types that Python support. In other words, integers, strings and tuples, but not  _mutable_  items like  _lists_  or  _dictionaries_ : + +``` +>>> s = {1, 'coffee', [4, 'python']} +Traceback (most recent call last): + File "", line 1, in +TypeError: unhashable type: 'list' + +``` + +Now that you know how to create a set and what type of elements it can contain, let's continue and see  _why_  we should always have them in our toolkit. + +### Why You Should Use Them + +When writing code, you can do it in more than a single way. Some are considered to be pretty bad, and others,  _clear, concise and maintainable_ . Or " [_pythonic_][7] ". + +From the [The Hitchhiker’s Guide to Python][8]: + +> When a veteran Python developer (a Pythonista) calls portions of code not “Pythonic”, they usually mean that these lines of code do not follow the common guidelines and fail to express its intent in what is considered the best (hear: most readable) way. + +Let's start exploring the way that Python sets can help us not just with readability, but also speeding up our programs execution time. + +### Unordered Collection of Elements + +First things first: you can't access a set element using indexes. + +``` +>>> s = {1, 2, 3} +>>> s[0] +Traceback (most recent call last): + File "", line 1, in +TypeError: 'set' object does not support indexing + +``` + +Or modify them with slices: + +``` +>>> s[0:2] +Traceback (most recent call last): + File "", line 1, in +TypeError: 'set' object is not subscriptable + +``` + +BUT, if what we need is to remove duplicates, or do mathematical operations like combining lists (unions), we can, and  _SHOULD_  always use Sets. + +I have to mention that when iterating over, sets are outperformed by lists, so prefer them if that is what you need. Why? well, this article does not intend to explain the inner workings of sets, but if you are interested, here are a couple of links where you can read about it: + +* [TimeComplexity][1] + +* [How is set() implemented?][2] + +* [Python Sets vs Lists][3] + +* [Is there any advantage or disadvantage to using sets over list comps to ensure a list of unique entries?][4] + +### No Duplicate Items + +While writing this I cannot stop thinking in all the times I used the  _for_  loop and the  _if_  statement to check and remove duplicate elements in a list. My face turns red remembering that, more than once, I wrote something like this: + +``` +>>> my_list = [1, 2, 3, 2, 3, 4] +>>> no_duplicate_list = [] +>>> for item in my_list: +... if item not in no_duplicate_list: +... no_duplicate_list.append(item) +... +>>> no_duplicate_list +[1, 2, 3, 4] + +``` + +Or used a list comprehension: + +``` +>>> my_list = [1, 2, 3, 2, 3, 4] +>>> no_duplicate_list = [] +>>> [no_duplicate_list.append(item) for item in my_list if item not in no_duplicate_list] +[None, None, None, None] +>>> no_duplicate_list +[1, 2, 3, 4] + +``` + +But it's ok, nothing of that matters anymore because we now have the sets in our arsenal: + +``` +>>> my_list = [1, 2, 3, 2, 3, 4] +>>> no_duplicate_list = list(set(my_list)) +>>> no_duplicate_list +[1, 2, 3, 4] +>>> + +``` + +Now let's use the  _timeit_  module and see the excecution time of lists and sets when removing duplicates: + +``` +>>> from timeit import timeit +>>> def no_duplicates(list): +... no_duplicate_list = [] +... [no_duplicate_list.append(item) for item in list if item not in no_duplicate_list] +... return no_duplicate_list +... +>>> # first, let's see how the list perform: +>>> print(timeit('no_duplicates([1, 2, 3, 1, 7])', globals=globals(), number=1000)) +0.0018683355819786227 + +``` + +``` +>>> from timeit import timeit +>>> # and the set: +>>> print(timeit('list(set([1, 2, 3, 1, 2, 3, 4]))', number=1000)) +0.0010220493243764395 +>>> # faster and cleaner =) + +``` + +Not only we write  _fewer lines_  with sets than with lists comprehensions, we also obtain more  _readable_  and  _performant_  code. + +Note: remember that sets are unordered, so there is no guarantee that when converting them back to a list the order of the elements is going to be preserved. + +From the [Zen of Python][9]: + +> Beautiful is better than ugly.  +> Explicit is better than implicit. +> Simple is better than complex. +> Flat is better than nested. + +Aren't sets just Beautiful, Explicit, Simple and Flat? =) + +### Membership Tests + +Every time we use an  _if_  statement to check if an element is, for example, in a list, you are doing a membership test: + +``` +my_list = [1, 2, 3] +>>> if 2 in my_list: +... print('Yes, this is a membership test!') +... +Yes, this is a membership test! + +``` + +And sets are more performant than lists when doing them: + +``` +>>> from timeit import timeit +>>> def in_test(iterable): +... for i in range(1000): +... if i in iterable: +... pass +... +>>> timeit('in_test(iterable)', +... setup="from __main__ import in_test; iterable = list(range(1000))", +... number=1000) +12.459663048726043 + +``` + +``` +>>> from timeit import timeit +>>> def in_test(iterable): +... for i in range(1000): +... if i in iterable: +... pass +... +>>> timeit('in_test(iterable)', +... setup="from __main__ import in_test; iterable = set(range(1000))", +... number=1000) +0.12354438152988223 +>>> + +``` + +Note: the above tests come from [this][10] StackOverflow thread. + +So if you are doing comparisons like this in huge lists, it should speed you a good bit if you convert that list into a set. + +### How to Use Them + +Now that you know what a set is and why you should use them, let's do a quick tour and see how can we modify and operate with them. + +### Adding Elements + +Depending on the number of elements to add, we will have to choose between the `add()` and `update()` methods. + +`add()` will add a single element: + +``` +>>> s = {1, 2, 3} +>>> s.add(4) +>>> s +{1, 2, 3, 4} + +``` + +And `update()` multiple ones: + +``` +>>> s = {1, 2, 3} +>>> s.update([2, 3, 4, 5, 6]) +>>> s +{1, 2, 3, 4, 5, 6} + +``` + +Remember, sets remove duplicates. + +### Removing Elements + +If you want to be alerted when your code tries to remove an element that is not in the set, use `remove()`. Otherwise, `discard()` provides a good alternative: + +``` +>>> s = {1, 2, 3} +>>> s.remove(3) +>>> s +{1, 2} +>>> s.remove(3) +Traceback (most recent call last): + File "", line 1, in +KeyError: 3 + +``` + +`discard()` won't raise any errors: + +``` +>>> s = {1, 2, 3} +>>> s.discard(3) +>>> s +{1, 2} +>>> s.discard(3) +>>> # nothing happens! + +``` + +We can also use `pop()` to randomly discard an element: + +``` +>>> s = {1, 2, 3, 4, 5} +>>> s.pop() # removes an arbitrary element +1 +>>> s +{2, 3, 4, 5} + +``` + +Or `clear()` to remove all the values from a set: + +``` +>>> s = {1, 2, 3, 4, 5} +>>> s.clear() # discard all the items +>>> s +set() + +``` + +### union() + +`union()` or `|` will create a new set that contains all the elements from the sets we provide: + +``` +>>> s1 = {1, 2, 3} +>>> s2 = {3, 4, 5} +>>> s1.union(s2) # or 's1 | s2' +{1, 2, 3, 4, 5} + +``` + +### intersection() + +`intersection` or `&` will return a set containing only the elements that are common in all of them: + +``` +>>> s1 = {1, 2, 3} +>>> s2 = {2, 3, 4} +>>> s3 = {3, 4, 5} +>>> s1.intersection(s2, s3) # or 's1 & s2 & s3' +{3} + +``` + +### difference() + +Using `diference()` or `-`, creates a new set with the values that are in "s1" but not in "s2": + +``` +>>> s1 = {1, 2, 3} +>>> s2 = {2, 3, 4} +>>> s1.difference(s2) # or 's1 - s2' +{1} + +``` + +### symmetric_diference() + +`symetric_difference` or `^` will return all the values that are not common between the sets. + +``` +>>> s1 = {1, 2, 3} +>>> s2 = {2, 3, 4} +>>> s1.symmetric_difference(s2) # or 's1 ^ s2' +{1, 4} + +``` + +### Conclusions + +I hope that after reading this article you know what a set is, how to manipulate their elements and the operations they can perform. Knowing when to use a set will definitely help you write cleaner code and speed up your programs. + +If you have any doubts, please leave a comment and I will gladly try to answer them. Also, don´t forget that if you already understand sets, they have their own [place][11] in the [Python Cheatsheet][12], where you can have a quick reference and refresh what you already know. + +-------------------------------------------------------------------------------- + +via: https://www.pythoncheatsheet.org/blog/python-sets-what-why-how + +作者:[wilfredinni][a] +译者:[译者ID](https://github.com/译者ID) +校对:[校对者ID](https://github.com/校对者ID) + +本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 + +[a]:https://www.pythoncheatsheet.org/author/wilfredinni +[1]:https://wiki.python.org/moin/TimeComplexity +[2]:https://stackoverflow.com/questions/3949310/how-is-set-implemented +[3]:https://stackoverflow.com/questions/2831212/python-sets-vs-lists +[4]:https://mail.python.org/pipermail/python-list/2011-June/606738.html +[5]:https://www.pythoncheatsheet.org/author/wilfredinni +[6]:https://docs.python.org/3/glossary.html#term-hashable +[7]:http://docs.python-guide.org/en/latest/writing/style/ +[8]:http://docs.python-guide.org/en/latest/ +[9]:https://www.python.org/dev/peps/pep-0020/ +[10]:https://stackoverflow.com/questions/2831212/python-sets-vs-lists +[11]:https://www.pythoncheatsheet.org/#sets +[12]:https://www.pythoncheatsheet.org/ From b047bb27ed5d734bb96fda096dc0f72560f24ac9 Mon Sep 17 00:00:00 2001 From: Ezio Date: Tue, 17 Jul 2018 10:07:53 +0800 Subject: [PATCH 5/5] =?UTF-8?q?20180717-3=20=E9=80=89=E9=A2=98=20-=20MjSev?= =?UTF-8?q?en=20=E7=94=B3=E9=A2=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @MjSeven --- ...derstanding Python Dataclasses — Part 1.md | 614 ++++++++++++++++++ 1 file changed, 614 insertions(+) create mode 100644 sources/tech/20180703 Understanding Python Dataclasses — Part 1.md diff --git a/sources/tech/20180703 Understanding Python Dataclasses — Part 1.md b/sources/tech/20180703 Understanding Python Dataclasses — Part 1.md new file mode 100644 index 0000000000..b8f9ece782 --- /dev/null +++ b/sources/tech/20180703 Understanding Python Dataclasses — Part 1.md @@ -0,0 +1,614 @@ +MjSeven is translating + +Understanding Python Dataclasses — Part 1 +============================================================ + +![](https://cdn-images-1.medium.com/max/900/1*7pr8EL8EDsP296pxL7Wz_g.png) + +If you’re reading this, then you are already aware of Python 3.7 and the new features that come packed with it. Personally, I am most excited about `Dataclasses`. I have been waiting for them to arrive for a while. + +This is a two part post: +1\. Dataclass features overview in this post +2\. Dataclass `fields` overview in the [next post][1] + +### Introduction + +`Dataclasses` are python classes but are suited for storing data objects. What are data objects, you ask? Here is a non-exhaustive list of features that define data objects: + +* They store data and represent a certain data type. Ex: A number. For people familiar with ORMs, a model instance is a data object. It represents a specific kind of entity. It holds attributes that define or represent the entity. + +* They can be compared to other objects of the same type. Ex: A number can be `greater than`, `less than`, or `equal to` another number + +There are certainly more features, but this list is sufficient to help you understand the crux. + +To understand `Dataclasses`, we shall be implementing a simple class that holds a number, and allows us to perform the above mentioned operations. +First, we shall be using normal classes, and then we shall use `Dataclasses` to achieve the same result. + +But before we begin, a word on the usage of `Dataclasses` + +Python 3.7 provides a decorator [dataclass][2] that is used to convert a class into a dataclass. + +All you have to do is wrap the class in the decorator: + +``` +from dataclasses import dataclass +``` + +``` +@dataclass +class A: + … +``` + +Now, lets dive into the usage of how and what `dataclass` changes for us. + +### Initialization + +Usual + +``` +class Number: +``` + +``` + __init__(self, val): + self.val = val + +>>> one = Number(1) +>>> one.val +>>> 1 +``` + +With `dataclass` + +``` +@dataclass +class Number: + val:int + +>>> one = Number(1) +>>> one.val +>>> 1 +``` + +Here’s what’s changed with the dataclass decorator: + +1\. No need of defining `__init__`and then assigning values to `self`, `d` takes care of it +2\. We defined the member attributes in advance in a much more readable fashion, along with [type hinting][3]. We now know instantly that `val` is of type `int`. This is definitely more readable than the usual way of defining class members. + +> Zen of Python: Readability counts + +It is also possible to define default values: + +``` +@dataclass +class Number: + val:int = 0 +``` + +### Representation + +Object representation is a meaningful string representation of the object that is very useful in debugging. + +Default python objects representation is not very meaningful: + +``` +class Number: + def __init__(self, val = 0): + self.val = val + +>>> a = Number(1) +>>> a +>>> <__main__.Number object at 0x7ff395b2ccc0> +``` + +This gives us no insight as to the utility of the object, and will result in horrible a debugging experience. + +A meaningful representation could be implemented by defining a `__repr__`method in the class definition. + +``` +def __repr__(self): + return self.val +``` + +Now we get a meaningful representation of the object: + +``` +>>> a = Number(1) +>>> a +>>> 1 +``` + +`dataclass` automatically add a `__repr__ `function, so that we don’t have to manually implement it. + +``` +@dataclass +class Number: + val: int = 0 +``` + +``` +>>> a = Number(1) +>>> a +>>> Number(val = 1) +``` + +### Data Comparison + +Generally, data objects come with a need to be compared with each other. + +Comparison between two objects `a` and `b` generally consists of the following operations: + +* a < b + +* a > b + +* a == b + +* a >= b + +* a <= b + +In python, it is possible to define [methods][4] in classes that can do the above operations. For the sake of simplicity and to not let this post run amuck, I shall be only demonstrating implementation of `==` and `<`. + +Usual + +``` +class Number: + def __init__( self, val = 0): + self.val = val + + def __eq__(self, other): + return self.val == other.val + + def __lt__(self, other): + return self.val < other.val +``` + +With `dataclass` + +``` +@dataclass(order = True) +class Number: + val: int = 0 +``` + +Yup, that’s it. + +We dont need to define the `__eq__`and `__lt__` methods, because `dataclass`decorator automatically adds them to the class definition for us when called with `order = True` + +Well, how does it do that? + +When you use `dataclass,` it adds a functions `__eq__` and `__lt__` to the class definition. We already know that. So, how do these functions know how to check equality and do comparison? + +A dataclass generated `__eq__` function will compare a tuple of its attributes with a tuple of attributes of the other instance of the same class. In our case here’s what the `automatically` generated `__eq__` function would be equivalent to: + +``` +def __eq__(self, other): + return (self.val,) == (other.val,) +``` + +Let’s look at a more elaborate example: + +We shall write a dataclass `Person `to hold their `name` and `age`. + +``` +@dataclass(order = True) +class Person: + name: str + age:int = 0 +``` + +The automatically generated `__eq__` method will be equivalent of: + +``` +def __eq__(self, other): + return (self.name, self.age) == ( other.name, other.age) +``` + +Pay attention to the order of the attributes. They will always be generated in the order you defined them in the dataclass definition. + +Similarly, the equivalent `__le__` function would be akin to: + +``` +def __le__(self, other): + return (self.name, self.age) <= (other.name, other.age) +``` + +A need for defining a function like `__le__` generally arises, when you have to sort a list of your data objects. Python’s built-in [sorted][5] function relies on comparing two objects. + +``` + +>>> import random +``` + +``` +>>> a = [Number(random.randint(1,10)) for _ in range(10)] #generate list of random numbers +``` + +``` +>>> a +``` + +``` +>>> [Number(val=2), Number(val=7), Number(val=6), Number(val=5), Number(val=10), Number(val=9), Number(val=1), Number(val=10), Number(val=1), Number(val=7)] +``` + +``` +>>> sorted_a = sorted(a) #Sort Numbers in ascending order +``` + +``` +>>> [Number(val=1), Number(val=1), Number(val=2), Number(val=5), Number(val=6), Number(val=7), Number(val=7), Number(val=9), Number(val=10), Number(val=10)] +``` + +``` +>>> reverse_sorted_a = sorted(a, reverse = True) #Sort Numbers in descending order +``` + +``` +>>> reverse_sorted_a +``` + +``` +>>> [Number(val=10), Number(val=10), Number(val=9), Number(val=7), Number(val=7), Number(val=6), Number(val=5), Number(val=2), Number(val=1), Number(val=1)] + +``` + +### `dataclass` as a callable decorator + +It is not always desirable to have all the `dunder` methods defined. Your use case might only consist of storing the values and checking equality. Thus, you only need the `__init__` and `__eq__` methods defined. If we could tell the decorator to not generate the other methods, it would reduce some overhead and we shall have correct operations available on the data object. + +Fortunately, this can be achieved by using `dataclass` decorator as a callable. + +From the official [docs][6], the decorator can be used as a callable with the following arguments: + +``` +@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False) +class C: + … +``` + +1. `init` : By default an `__init__` method will be generated. If passed as `False`, the class will not have an `__init__` method. + +2. `repr` : `__repr__` method is generated by default. If passed as `False`, the class will not have an `__repr__` method. + +3. `eq`: By default the `__eq__` method will be generated. If passed as `False`, the `__eq__` method will not be added by `dataclass`, but will default to the `object.__eq__`. + +4. `order` : By default `__gt__` , `__ge__`, `__lt__`, `__le__` methods will be generated. If passed as `False`, they are omitted. + +We shall discuss `frozen` in a while. The `unsafe_hash` argument deserves a separate post because of its complicated use cases. + +Now, back to our use case, here’s what we need: + +1. `__init__` +2. `__eq__` + +These functions are generated by default, so what we need is to not have the other functions generated. How do we do that? Simply pass the relevant arguments as false to the generator. + +``` +@dataclass(repr = False) # order, unsafe_hash and frozen are False +class Number: + val: int = 0 +``` + +``` +>>> a = Number(1) +``` + +``` +>>> a +``` + +``` +>>> <__main__.Number object at 0x7ff395afe898> +``` + +``` +>>> b = Number(2) +``` + +``` +>>> c = Number(1) +``` + +``` +>>> a == b +``` + +``` +>>> False +``` + +``` +>>> a < b +``` + +``` +>>> Traceback (most recent call last): + File “”, line 1, in +TypeError: ‘<’ not supported between instances of ‘Number’ and ‘Number’ +``` + +### Frozen Instances + +Frozen Instances are objects whose attributes cannot be modified after the object has been initialized. + +> It is not possible to create truly immutable Python objects + +To create immutable attributes on an object in Python is an arduous task, and something that I won’t dive into in this post. + +Here’s what we expect from an immutable object: + +``` +>>> a = Number(10) #Assuming Number class is immutable +``` + +``` +>>> a.val = 10 # Raises Error +``` + +With Dataclasses it is possible to define a frozen object by using `dataclass`decorator as a callable with argument `frozen=True` . + +When a frozen dataclass object is instantiated, any attempt to modify the attributes of the object raises `FrozenInstanceError`. + +``` +@dataclass(frozen = True) +class Number: + val: int = 0 +``` + +``` +>>> a = Number(1) +``` + +``` +>>> a.val +``` + +``` +>>> 1 +``` + +``` +>>> a.val = 2 +``` + +``` +>>> Traceback (most recent call last): + File “”, line 1, in + File “”, line 3, in __setattr__ +dataclasses.FrozenInstanceError: cannot assign to field ‘val’ +``` + +So a frozen instance is a great way of storing + +* constants + +* settings + +These generally do not change over the lifetime of the application and any attempt to modify them should generally be warded off. + +### Post init processing + +With Dataclasses the requirement of defining an `__init__` method to assign variables to `self` has been taken care of. But now we lose the flexibility of making function-calls/processing that might be required immediately after the variables have been assigned. + +Let us discuss a use case where we define a class `Float` to contain float numbers, and we calculate the integer and decimal parts immediately after initialization. + +Usual + +``` +import math +``` + +``` +class Float: + def __init__(self, val = 0): + self.val = val + self.process() + + def process(self): + self.decimal, self.integer = math.modf(self.val) + +>>> a = Float( 2.2) +``` + +``` +>>> a.decimal +``` + +``` +>>> 0.2000 +``` + +``` +>>> a.integer +``` + +``` +>>> 2.0 +``` + +Fortunately, post initialization processing is already taken care of with [__post_init__][9] method. + +The generated `__init__` method calls the `__post_init__` method before returning. So, any processing can be made in this functions. + +``` +import math +``` + +``` +@dataclass +class FloatNumber: + val: float = 0.0 + + def __post_init__(self): + self.decimal, self.integer = math.modf(self.val) + +>>> a = Number(2.2) +``` + +``` +>>> a.val +``` + +``` +>>> 2.2 +``` + +``` +>>> a.integer +``` + +``` +>>> 2.0 +``` + +``` +>>> a.decimal +``` + +``` +>>> 0.2 +``` + +Neat! + + +### Inheritance + +`Dataclasses` support inheritance like normal python classes. + +So, the attributes defined in the parent class will be available in the child class. + +``` +@dataclass +class Person: + age: int = 0 + name: str +``` + +``` +@dataclass +class Student(Person): + grade: int +``` + +``` +>>> s = Student(20, "John Doe", 12) +``` + +``` +>>> s.age +``` + +``` +>>> 20 +``` + +``` +>>> s.name +``` + +``` +>>> "John Doe" +``` + +``` +>>> s.grade +``` + +``` +>>> 12 +``` + +Pay attention to the fact that the arguments to `Student` are in the order of fields defined in the class definition. + +What about the behavior of `__post_init__` during inheritance? + +Since `__post_init__` is just another function, it has to be invoked in the conventional form: + +``` +@dataclass +class A: + a: int + + def __post_init__(self): + print("A") +``` + +``` +@dataclass +class B(A): + b: int + + def __post_init__(self): + print("B") +``` + +``` +>>> a = B(1,2) +``` + +``` +>>> B +``` + +In the above example, only `B's` `__post_init__` is called. How do we invoke `A's` `__post_init__` ? + +Since it is a function of the parent class, it can be invoked using `super.` + +``` +@dataclass +class B(A): + b: int + + def __post_init__(self): + super().__post_init__() #Call post init of A + print("B") +``` + +``` +>>> a = B(1,2) +``` + +``` +>>> A + B +``` + +### Conclusion + +So, above are a few ways in which Dataclasses make life easier for Python developers. +I have tried to be thorough and cover most of the use cases, yet, no man is perfect. Reach out if you find mistakes, or want me to pay attention to relevant use cases. + +I shall cover [dataclasses.field][10] and `unsafe_hash` in different posts. + +Follow me on [Github][11], [Twitter][12]. + +Update: Post for `dataclasses.field` can be found [here][13]. + +-------------------------------------------------------------------------------- + +via: https://medium.com/mindorks/understanding-python-dataclasses-part-1-c3ccd4355c34 + +作者:[Shikhar Chauhan][a] +译者:[译者ID](https://github.com/译者ID) +校对:[校对者ID](https://github.com/校对者ID) + +本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 + +[a]:https://medium.com/@xsschauhan?source=post_header_lockup +[1]:https://medium.com/@xsschauhan/understanding-python-dataclasses-part-2-660ecc11c9b8 +[2]:https://docs.python.org/3.7/library/dataclasses.html#dataclasses.dataclass +[3]:https://stackoverflow.com/q/32557920/4333721 +[4]:https://docs.python.org/3/reference/datamodel.html#object.__lt__ +[5]:https://docs.python.org/3.7/library/functions.html#sorted +[6]:https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass +[7]:http://twitter.com/dataclass +[8]:http://twitter.com/dataclass +[9]:https://docs.python.org/3/library/dataclasses.html#post-init-processing +[10]:https://docs.python.org/3/library/dataclasses.html#dataclasses.field +[11]:http://github.com/xssChauhan/ +[12]:https://twitter.com/xssChauhan +[13]:https://medium.com/@xsschauhan/understanding-python-dataclasses-part-2-660ecc11c9b8