mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-03-24 02:20:09 +08:00
commit
f514c4049e
published
sources
news
tech
20210915 Raspberry Pi Zero vs Zero W- What-s the Difference.md20210915 Screen Recording in Linux With OBS and Wayland.md20210916 Crunch numbers in Python with NumPy.md20210916 Debugging by starting a REPL at a breakpoint is fun.md20210916 How I patched Python to include this great Ruby feature.md20210916 Watch commands and tasks with the Linux watch command.md20210917 How to Install Kali Linux in VMware.md
translated/tech
@ -3,18 +3,18 @@
|
||||
[#]: author: "Nived V https://opensource.com/users/nivedv"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "wxy"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: reviewer: "turbokernel"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-13792-1.html"
|
||||
|
||||
容器的四大基础技术
|
||||
======
|
||||
|
||||
> 命名空间、控制组、seccomp 和 SELinux 构成了在你的系统上构建和运行一个容器进程的 Linux 技术基础。
|
||||
> 命名空间、控制组、seccomp 和 SELinux 构成了在系统上构建和运行一个容器进程的 Linux 技术基础。
|
||||
|
||||
![企鹅驾驶一辆黄色背景的汽车][1]
|
||||

|
||||
|
||||
在以前的文章中,我介绍过 [容器镜像][2] 及其 [运行时][3]。在这篇文章中,我研究了容器是如何在一些特殊的 Linux 技术基础上实现的,这些技术包括命名空间和控制组。
|
||||
在以前的文章中,我介绍过 [容器镜像][2] 及其 [运行时][3]。在本文中,我研究了容器是如何在一些特殊的 Linux 技术基础上实现的,这其中包括命名空间和控制组。
|
||||
|
||||
![容器技术的层次][4]
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
|
||||
### 命名空间
|
||||
|
||||
<ruby>命名空间<rt>namespace</rt></ruby> 为容器提供了一个隔离层,给容器提供了一个看起来是它自己的 Linux 文件系统的视图。这就限制了进程所能看到的东西,从而限制了它所能获得的资源。
|
||||
<ruby>命名空间<rt>namespace</rt></ruby> 为容器提供了一个隔离层,给容器提供了一个看起来是独占的 Linux 文件系统的视图。这就限制了进程能访问的内容,从而限制了它所能获得的资源。
|
||||
|
||||
在创建容器时,Docker 或 Podman 和其他容器技术使用了 Linux 内核中的几个命名空间:
|
||||
|
||||
@ -48,15 +48,15 @@
|
||||
```
|
||||
#### 用户
|
||||
|
||||
用户(`user`)命名空间将用户和组隔离在一个容器内。这是通过允许容器与宿主系统有不同的 UID 和 GID 范围来实现的。用户命名空间使软件能够以 root 用户的身份在容器内运行。如果入侵者攻击容器,然后逃逸到宿主机上,他们就受限于只能以非 root身份出现了。
|
||||
用户(`user`)命名空间将用户和组隔离在一个容器内。这是通过分配给容器与宿主系统有不同的 UID 和 GID 范围来实现的。用户命名空间使软件能够以 root 用户的身份在容器内运行。如果入侵者攻击容器,然后逃逸到宿主机上,他们就只能以受限的非 root 身份运行了。
|
||||
|
||||
#### 挂载
|
||||
|
||||
挂载(`mnt`)命名空间允许容器对系统的文件系统层次结构有自己的视图。你可以在 Linux 系统中的 `/proc/<PID>/mounts` 位置找到每个容器进程的挂载点。
|
||||
挂载(`mnt`)命名空间允许容器有自己的文件系统层次结构视图。你可以在 Linux 系统中的 `/proc/<PID>/mounts` 位置找到每个容器进程的挂载点。
|
||||
|
||||
#### UTS
|
||||
|
||||
<ruby>Unix 分时系统<rt>Unix Timeharing System</rt></ruby>(UTS)命名空间允许容器有一个唯一的主机名和域名。当你运行一个容器时,即使使用 `- name` 标签,也会使用一个随机的 ID 作为主机名。你可以使用 [unshare 命令][6] 来了解一下这个工作原理。
|
||||
<ruby>Unix 分时系统<rt>Unix Timeharing System</rt></ruby>(UTS)命名空间允许容器拥有一个唯一主机名和域名。当你运行一个容器时,即使使用 `- name` 标签,也会使用一个随机的 ID 作为主机名。你可以使用 [unshare 命令][6] 来了解一下这个工作原理。
|
||||
|
||||
```
|
||||
nivedv@homelab ~]$ docker container run -it --name nived alpine sh
|
||||
@ -76,7 +76,7 @@ homelab.redhat.com
|
||||
|
||||
#### IPC
|
||||
|
||||
<ruby>进程间通信<rt>Inter-Process Communication</rt></ruby>(IPC)命名空间允许不同的容器进程通过访问共享内存或使用共享消息队列来进行通信。
|
||||
<ruby>进程间通信<rt>Inter-Process Communication</rt></ruby>(IPC)命名空间允许不同的容器进程之间,通过访问共享内存或使用共享消息队列来进行通信。
|
||||
|
||||
```
|
||||
[root@demo /]# ipcmk -M 10M
|
||||
@ -97,11 +97,11 @@ key semid owner perms nsems
|
||||
|
||||
#### PID
|
||||
|
||||
<ruby>进程 ID<rt>Process ID</rt></ruby>(PID)命名空间确保在容器内运行的进程与外部世界隔离。当你在容器内运行 `ps` 命令时,由于这个命名空间的存在,你只能看到在容器内运行的进程,而不是在宿主机上。
|
||||
<ruby>进程 ID<rt>Process ID</rt></ruby>(PID)命名空间确保运行在容器内的进程与外部隔离。当你在容器内运行 `ps` 命令时,由于这个命名空间隔离的存在,你只能看到在容器内运行的进程,而不是在宿主机上。
|
||||
|
||||
#### 网络
|
||||
|
||||
网络(`net`)命名空间允许容器对网络接口、IP 地址、路由表、端口号等有自己的视图。容器如何能够与外部世界沟通?你创建的所有容器都会被附加到一个特殊的虚拟网络接口上进行通信。
|
||||
网络(`net`)命名空间允许容器有自己网络接口、IP 地址、路由表、端口号等视图。容器如何能够与外部通信?你创建的所有容器都会被附加到一个特殊的虚拟网络接口上进行通信。
|
||||
|
||||
```
|
||||
[nivedv@homelab ~]$ docker container run --rm -it alpine sh
|
||||
@ -117,7 +117,7 @@ master docker0 state UP mode DEFAULT group default
|
||||
|
||||
### 控制组
|
||||
|
||||
控制组(`cgroup`)是制作一个容器的基本模块。控制组会分配和限制资源,如 CPU、内存、网络 I/O 等,这些资源被容器所使用。容器引擎会自动创建每种类型的控制组文件系统,并在容器运行时为每个容器设置值。
|
||||
控制组(`cgroup`)是组成一个容器的基本模块。控制组会分配和限制容器所使用的资源,如 CPU、内存、网络 I/O 等。容器引擎会自动创建每种类型的控制组文件系统,并在容器运行时为每个容器设置配额。
|
||||
|
||||
```
|
||||
[root@homelab ~]# lscgroup | grep docker
|
||||
@ -133,7 +133,7 @@ blkio:/docker
|
||||
pids:/docker
|
||||
```
|
||||
|
||||
容器运行时为每个容器设置了控制组值,所有信息都存储在 `/sys/fs/cgroup/*/docker`。下面的命令将确保容器可以使用 50000 微秒的 CPU 时间,并将内存的软、硬限制分别设置为 500M 和 1G。
|
||||
容器运行时为每个容器设置了控制组值,所有信息都存储在 `/sys/fs/cgroup/*/docker`。下面的命令将确保容器可以使用 50000 微秒的 CPU 时间片,并将内存的软、硬限制分别设置为 500M 和 1G。
|
||||
|
||||
```
|
||||
[root@homelab ~]# docker container run -d --name test-cgroups --cpus 0.5 --memory 1G --memory-reservation 500M httpd
|
||||
@ -154,13 +154,13 @@ memory:/docker/c3503ac704dafea3522d3bb82c77faff840018e857a2a7f669065f05c8b2cc84
|
||||
|
||||
### SECCOMP
|
||||
|
||||
Seccomp 意思是“<ruby>安全计算<rt>secure computing</rt></ruby>”。它是一项 Linux 功能,用于限制应用程序允许进行的系统调用的集合。例如,Docker 的默认 seccomp 配置文件禁用了大约 44 个系统调用(总计超过 300 个)。
|
||||
Seccomp 意思是“<ruby>安全计算<rt>secure computing</rt></ruby>”。它是一项 Linux 功能,用于限制应用程序进行的系统调用的集合。例如,Docker 的默认 seccomp 配置文件禁用了大约 44 个系统调用(总计超过 300 个)。
|
||||
|
||||
这里的思路是让容器只访问容器可能需要的那些资源。例如,如果你不需要容器改变主机上的时钟时间,你可能不会使用 `clock_adjtime` 和 `clock_settime` 系统调用,屏蔽它们是合理的。同样地,你不希望容器改变内核模块,所以没有必要让它们进行 `create_module`、 `delete_module` 系统调用。
|
||||
这里的思路是让容器只访问所必须的资源。例如,如果你不需要容器改变主机上的时钟时间,你可能不会使用 `clock_adjtime` 和 `clock_settime` 系统调用,屏蔽它们是合理的。同样地,你不希望容器改变内核模块,所以没有必要让它们使用 `create_module`、 `delete_module` 系统调用。
|
||||
|
||||
### SELinux
|
||||
|
||||
SELinux 是“<ruby>安全增强的 Linux<rt>security-enhanced Linux</rt></ruby>”的缩写。如果你在你的宿主机上运行的是 Red Hat 发行版,那么 SELinux 是默认启用的。SELinux 可以让你限制一个应用程序只能访问它自己的文件,并阻止任何其他进程访问它们。因此,如果一个应用程序被破坏了,它将限制该应用程序可以影响或控制的文件数量。它通过为文件和进程设置上下文环境以及定义策略来实现这一目的,这些策略将强制执行一个进程可以看到和改变的内容。
|
||||
SELinux 是“<ruby>安全增强的 Linux<rt>security-enhanced Linux</rt></ruby>”的缩写。如果你在你的宿主机上运行的是 Red Hat 发行版,那么 SELinux 是默认启用的。SELinux 可以让你限制一个应用程序只能访问它自己的文件,并阻止任何其他进程访问。因此,如果一个应用程序被破坏了,它将限制该应用程序可以影响或控制的文件数量。通过为文件和进程设置上下文环境以及定义策略来实现,这些策略将限制一个进程可以访问和更改的内容。
|
||||
|
||||
容器的 SELinux 策略是由 `container-selinux` 包定义的。默认情况下,容器以 `container_t` 标签运行,允许在 `/usr` 目录下读取(`r`)和执行(`x`),并从 `/etc` 目录下读取大部分内容。标签`container_var_lib_t` 是与容器有关的文件的通用标签。
|
||||
|
||||
@ -177,15 +177,15 @@ via: https://opensource.com/article/21/8/container-linux-technology
|
||||
作者:[Nived V][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[turbokernel](https://github.com/turbokernel)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/nivedv
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/car-penguin-drive-linux-yellow.png?itok=twWGlYAc (Penguin driving a car with a yellow background)
|
||||
[2]: https://opensource.com/article/21/8/container-fundamentals-2
|
||||
[3]: https://opensource.com/article/21/8/deep-dive-container-runtimes
|
||||
[2]: https://linux.cn/article-13766-1.html
|
||||
[3]: https://linux.cn/article-13772-1.html
|
||||
[4]: https://opensource.com/sites/default/files/1linuxtechs.png (layers of linux technologies)
|
||||
[5]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[6]: https://opensource.com/article/19/10/namespaces-and-containers-linux
|
@ -0,0 +1,115 @@
|
||||
[#]: subject: "Kali Linux 2021.3 Brings in Kali Live VM Support, New Tools, and Other Improvements"
|
||||
[#]: via: "https://news.itsfoss.com/kali-linux-2021-3-release/"
|
||||
[#]: author: "Omar Maarof https://news.itsfoss.com/author/omar/"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Kali Linux 2021.3 Brings in Kali Live VM Support, New Tools, and Other Improvements
|
||||
======
|
||||
|
||||
Kali Linux is one of the [best Linux distributions for penetration testing][1]. It is based on Debian, but it may not be a suitable replacement for your full-fledged desktop operating system.
|
||||
|
||||
The latest 2021.3 release brings some significant feature additions and improvements onboard. Let us check them out.
|
||||
|
||||
### What’s New?
|
||||
|
||||
![][2]
|
||||
|
||||
#### OpenSSL Compatibility
|
||||
|
||||
[OpenSSL][3] has been **reconfigured to expand the services networked to Kali**. As a result, legacy protocols such as TLS 1.0 and TLS 1.1 and older ciphers are allowed by default. That is to say; it will grant Kali the capability of connecting to more out-of-date servers. However, you can alter this option if you do not need it.
|
||||
|
||||
#### Virtualization Improvements
|
||||
|
||||
Kali is known to work flawlessly as a virtual machine. Firstly, actions like drag and drop, copy and paste between host and guest systems are smoother than ever, whether your guest machine is running under VirtualBox, VMware, Hyper-V, or QEMU+Spice.
|
||||
|
||||
Secondly, it is easier to configure Kali for Hyper-V Enhanced Session Mode, a virtualization hypervisor, using Kali-Tweaks.
|
||||
|
||||
In short, Kali Linux 2021.3 has made the experience even more seamless when setting up a virtual environment.
|
||||
|
||||
#### Kali Tools
|
||||
|
||||
It is taken for granted that every release of Kali contains new tools. Likewise, this release is no exception. The tools that Kali added to its fleet are:
|
||||
|
||||
* [Berate_ap][4] – Orchestrating MANA rogue Wi-Fi Access Points
|
||||
* [CALDERA][5] – Scalable automated adversary emulation platform
|
||||
* [EAPHammer][6] – Targeted evil twin attacks against WPA2-Enterprise Wi-Fi networks
|
||||
* [HostHunter][7] – Recon tool for discovering hostnames using OSINT techniques
|
||||
* [RouterKeygenPC][8] – Generate default WPA/WEP Wi-Fi keys
|
||||
* [Subjack][9] – Subdomain takeover
|
||||
* [WPA_Sycophant][10] – Evil client portion of EAP relay attack
|
||||
|
||||
|
||||
|
||||
##### Kali ARM Updates and Kali-Tools
|
||||
|
||||
With Kali 2021.3, ARM devices are getting more ameliorations. The ones I found eye-catching are:
|
||||
|
||||
* en_US.UTF-8 is the default locale on all images.
|
||||
* The Kali ARM build scripts are rebuilt to better support some devices.
|
||||
* Raspberry Pi images can now use a wpa_supplicant.conf file on the /boot partition.
|
||||
|
||||
|
||||
|
||||
Moreover, Kali has refreshed its information domain **Kali-Tools**, to provide a concise overview of tools, a neat and clean interface, and a fast system.
|
||||
|
||||
### Other Changes
|
||||
|
||||
![Kali Linux 2021.3][11]
|
||||
|
||||
Kali has seen other neat improvements as well that includes:
|
||||
|
||||
* Improvement to its layout for its Xfce and Gnome editions. Kali did not forget about KDE, as it is one of its favorite desktop environments. For instance, KDE 5.21 is the new version available baked in.
|
||||
* Some of the important pages in their documentation site has received major updates.
|
||||
* Partnered with Ampere to have its ARM package building machines running on Ampere’s hardware. As a consequence, Kali benefited from a burst in speed.
|
||||
|
||||
|
||||
|
||||
Kali’s mobile penetration testing platform for Android devices has seen an enhancement. In other words, you can now install Kali NetHunter on Android 11 devices without the need for a fully working [TWRP][12] (Team Win Recovery Project). Above all, this update is promising due to its convenient installation procedure.
|
||||
|
||||
In addition to this release, they also announced their first NetHunter smartwatch, **TicHunter Pro**. But, it is still in its very first stages of development.
|
||||
|
||||
To learn more about all the technical changes with this upgrade, refer to [the official announcement][13].
|
||||
|
||||
### Summing Up
|
||||
|
||||
Overall, this is a significant release with valuable improvements and exciting new tools. Get started by downloading it from its official site.
|
||||
|
||||
[Download Kali Linux 2021.3][14]
|
||||
|
||||
#### Big Tech Websites Get Millions in Revenue, It's FOSS Got You!
|
||||
|
||||
If you like what we do here at It's FOSS, please consider making a donation to support our independent publication. Your support will help us keep publishing content focusing on desktop Linux and open source software.
|
||||
|
||||
I'm not interested
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/kali-linux-2021-3-release/
|
||||
|
||||
作者:[Omar Maarof][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://news.itsfoss.com/author/omar/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/linux-hacking-penetration-testing/
|
||||
[2]: data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjQzOSIgd2lkdGg9Ijc4MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiLz4=
|
||||
[3]: https://www.openssl.org/
|
||||
[4]: https://pkg.kali.org/pkg/berate-ap
|
||||
[5]: https://pkg.kali.org/pkg/caldera
|
||||
[6]: https://pkg.kali.org/pkg/eaphammer
|
||||
[7]: https://pkg.kali.org/pkg/hosthunter
|
||||
[8]: https://pkg.kali.org/pkg/routerkeygenpc
|
||||
[9]: https://pkg.kali.org/pkg/subjack
|
||||
[10]: https://pkg.kali.org/pkg/wpa-sycophant
|
||||
[11]: data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjQwOCIgd2lkdGg9Ijc4MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiLz4=
|
||||
[12]: http://twrp.me/
|
||||
[13]: https://www.kali.org/blog/kali-linux-2021-3-release/
|
||||
[14]: https://www.kali.org/get-kali/
|
@ -1,110 +0,0 @@
|
||||
[#]: subject: "Raspberry Pi Zero vs Zero W: What’s the Difference?"
|
||||
[#]: via: "https://itsfoss.com/raspberry-pi-zero-vs-zero-w/"
|
||||
[#]: author: "Ankush Das https://itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "anine09"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Raspberry Pi Zero vs Zero W: What’s the Difference?
|
||||
======
|
||||
|
||||
Raspberry Pi created a revolution when it launched the $25 mini computer ten years ago. Over the time, several variants of Raspberry Pi have been launched. Some upgrade a previous model and some are crafted for specific purposes.
|
||||
|
||||
Of all the Raspberry models, Pi Zero and Pi Zero W are the cheapest ones aimed for small scale and IoT projects. Both devices are almost similar to each other but with a subtle and important difference.
|
||||
|
||||
**So, what is the difference between Raspberry Pi Zero and Zero W? The W in Zero W stands for Wireless and it depicts its wireless capability over the Pi Zero model. That’s the single biggest difference between the two similar models.**
|
||||
|
||||
Let’s take a look at a bit more in detail.
|
||||
|
||||
### Key Difference Between Pi Zero and Pi Zero W
|
||||
|
||||
![][1]
|
||||
|
||||
While Raspberry Pi Zero was built with a goal that provides more utility with half of the size of the A+ board.
|
||||
|
||||
And, Raspberry Pi Zero W was introduced later to include wireless connectivity built-in without needing a separate accessory/module to enable Bluetooth and Wi-Fi.
|
||||
|
||||
This is the key difference between the two with the rest of the specifications remaining identical.
|
||||
|
||||
So, if you want the support for:
|
||||
|
||||
* 802.11 b/g/n wireless LAN
|
||||
* Bluetooth 4.1
|
||||
* Bluetooth Low Energy (BLE)
|
||||
|
||||
|
||||
|
||||
Raspberry Pi Zero W will be the definite choice to go with.
|
||||
|
||||
Also, Raspberry Pi Zero W offers a variant with header pins included which is “Raspberry Pi Zero WH”.
|
||||
|
||||
Preview | Product | Price |
|
||||
---|---|---|---
|
||||
[![CanaKit Raspberry Pi Zero W \(Wireless\) Complete Starter Kit - 16 GB Edition][2]][3] | [CanaKit Raspberry Pi Zero W (Wireless) Complete Starter Kit - 16 GB Edition][3] | $32.99[][4] | [Buy on Amazon][5]
|
||||
|
||||
### Raspberry Pi Zero and Raspberry Pi Zero W Specifications
|
||||
|
||||
![Raspberry Pi Zero W][6]
|
||||
|
||||
The [specifications for Raspberry Pi Zero W][7] and Zero are almost identical.
|
||||
|
||||
You get a 1 GHz single-core CPU coupled with 512 MB RAM. For connectivity, you get a mini HDMI port, micro USB OTG support, micro USB power, and a CSI Camera connector (to plug in a camera module).
|
||||
|
||||
These boards also feature a [HAT][8] (Hardware Attached on Top)-compatible 40 pin header, but generally, without the pins that let you easily plug the interfaces.
|
||||
|
||||
You can choose to explore the capabilities using [various Raspberry Pi OS][9] available. In either case, just stick to the Raspberry Pi OS.
|
||||
|
||||
### Raspberry Pi Zero series: Is it worth It?
|
||||
|
||||
![Raspberry Pi Zero][10]
|
||||
|
||||
Raspberry Pi Zero is a single-board computer that is popular for its form factor. Even though you have plenty of [Raspberry Pi zero alternatives][11], Raspberry Pi Zero is the recommended choice for all the good reasons.
|
||||
|
||||
Of course, unless you have specific requirements.
|
||||
|
||||
In addition to the size of the board, the pricing, power requirement, and processing power are some of the key highlights of this board under **$20**.
|
||||
|
||||
So, if you are looking for the essential features under a budget, the Raspberry Zero series should work for you.
|
||||
|
||||
**Recommended Read:**
|
||||
|
||||
![][12]
|
||||
|
||||
#### [27 Super Cool Raspberry Pi Zero W Projects for DIY Enthusiasts][13]
|
||||
|
||||
The small form factor of the Raspberry Pi Zero W enables a new range of projects. Here are some cool projects you can build with your tiny Raspberry Pi Zero W.
|
||||
|
||||
### Is Raspberry Pi Zero series affordable?
|
||||
|
||||
Raspberry Pi Zero costs **$5** and the Raspberry Pi Zero W would cost you around **$10**. ****Of course, depending on its availability and region, the cost will differ. If you want the Raspberry Pi Zero W with header pins, it should cost you around **$14**.
|
||||
|
||||
There are other devices that can be used as an [alternative to Raspberry Pi Zero][11] and they have similar price tag.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/raspberry-pi-zero-vs-zero-w/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[anine09](https://github.com/anine09)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/raspberry-pi-zero-vs-zero-w.png?resize=800%2C450&ssl=1
|
||||
[2]: https://i1.wp.com/m.media-amazon.com/images/I/517BwcAPmTL._SL160_.jpg?ssl=1
|
||||
[3]: https://www.amazon.com/dp/B072N3X39J?tag=chmod7mediate-20&linkCode=osi&th=1&psc=1 (CanaKit Raspberry Pi Zero W (Wireless) Complete Starter Kit - 16 GB Edition)
|
||||
[4]: https://www.amazon.com/gp/prime/?tag=chmod7mediate-20 (Amazon Prime)
|
||||
[5]: https://www.amazon.com/dp/B072N3X39J?tag=chmod7mediate-20&linkCode=osi&th=1&psc=1 (Buy on Amazon)
|
||||
[6]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/raspberry-pi-zero-w.png?resize=600%2C400&ssl=1
|
||||
[7]: https://itsfoss.com/raspberry-pi-zero-w/
|
||||
[8]: https://github.com/raspberrypi/hats
|
||||
[9]: https://itsfoss.com/raspberry-pi-os/
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/raspberry-pi-zero-1.png?resize=600%2C400&ssl=1
|
||||
[11]: https://itsfoss.com/raspberry-pi-zero-alternatives/
|
||||
[12]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/10/raspberry-pi-zero-w-projects.png?fit=800%2C450&ssl=1
|
||||
[13]: https://itsfoss.com/raspberry-pi-zero-projects/
|
@ -1,125 +0,0 @@
|
||||
[#]: subject: "Screen Recording in Linux With OBS and Wayland"
|
||||
[#]: via: "https://itsfoss.com/screen-record-obs-wayland/"
|
||||
[#]: author: "Abhishek Prakash https://itsfoss.com/author/abhishek/"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Screen Recording in Linux With OBS and Wayland
|
||||
======
|
||||
|
||||
There are [tons of screen recorders available for Linux][1]. But when it comes to supporting [Wayland][2], almost all of them do not work.
|
||||
|
||||
This is problematic because many new distribution releases are switching to Wayland display manager by default once again. And if something as basic as a screen recorder does not work, it leaves a bad experience.
|
||||
|
||||
[GNOME’s built-in screen recorder][3] works but it is hidden, has no GUI and no way to configure and control the recordings. There is another tool called [Kooha][4] but it keeps on displaying a timer on the screen.
|
||||
|
||||
[Switching between Xorg and Wayland][5] just for screen recording is not very convenient.
|
||||
|
||||
Amidst all this, I was happy to learn that Wayland support landed in OBS Studio with version 27 release thanks to Pipewire. But even there, it’s not straightforward and hence I am going to show you the steps for screen recording on Wayland using [OBS Studio][6].
|
||||
|
||||
### Using OBS to screen record on Wayland
|
||||
|
||||
![][7]
|
||||
|
||||
Let’s see how it is done.
|
||||
|
||||
#### Step 1: Install OBS Studio
|
||||
|
||||
You should install OBS Studio version 27 first. It is already included in Ubuntu 21.10 which I am suing in this tutorial.
|
||||
|
||||
To install OBS Studio 27 on Ubuntu 18.04, 20.04, Linux Mint 20 etc, use the [official OBS Studio][8] [][8][PPA][8].
|
||||
|
||||
Open a terminal and use the following commands one by one:
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:obsproject/obs-studio
|
||||
sudo apt update
|
||||
sudo apt install obs-studio
|
||||
```
|
||||
|
||||
If there is an older version of OBS Studio installed already, it will be upgraded to the newer version.
|
||||
|
||||
For Fedora, Arch and other distributions, please check your package manager or unofficial repositories for installing the latest version of OBS Studio.
|
||||
|
||||
#### Step 2: Check if Wayland capture is working
|
||||
|
||||
Please make sure that you are using Wayland. Now start OBS Studio and go through all the stuff it shows on the first run. I am not going to show that.
|
||||
|
||||
The main step is to add Pipewire as a screen capture source. Click on the + symbol under the Sources list.
|
||||
|
||||
![Add screen capture source in OBS Studio][9]
|
||||
|
||||
Do you see anything that reads Screen Capture (PipeWire)?
|
||||
|
||||
![Do you see PipeWire option in the screen sources?][10]
|
||||
|
||||
**If the answer is no, quit OBS Studio**. This is normal. OBS Studio does not switch to use Wayland automatically in Ubuntu at least. There is a fix for that.
|
||||
|
||||
Open a terminal and use the following command:
|
||||
|
||||
```
|
||||
export QT_QPA_PLATFORM=wayland
|
||||
```
|
||||
|
||||
In the same terminal, run the following command to start OBS Studio:
|
||||
|
||||
```
|
||||
obs
|
||||
```
|
||||
|
||||
It will show some message on the terminal. Ignore them. Your focus should be on the OBS Studio GUI. Try to add screen capture once again. You should see the PipeWire option now.
|
||||
|
||||
![][10]
|
||||
|
||||
You explicitly asked OBS Studio to use Wayland this time with the QT_QPA_PLATFORM variable.
|
||||
|
||||
Select PipeWire as the source and then it asks you to choose a display screen. Select it and click on the Share button.
|
||||
|
||||
![][11]
|
||||
|
||||
Now it should show your screen recursively infinite number of times. If you see that, you could start recording the screen in Wayland now.
|
||||
|
||||
![][12]
|
||||
|
||||
#### Step 3: Make changes permanent
|
||||
|
||||
That was good. You just verified that you can record your screen on Wayland. But setting the environment variable and starting OBS from the terminal each time is not convenient.
|
||||
|
||||
What you can do is to **export the variable to your ~/.bash_profile (for you) or /etc/profile (for all users on the system).**
|
||||
|
||||
```
|
||||
export QT_QPA_PLATFORM=wayland
|
||||
```
|
||||
|
||||
Log out and log back in. Now OBS will automatically start using this parameter and you can use it to record your screen in Wayland.
|
||||
|
||||
I hope you find this quick tip helpful. If you still have questions or suggestions, please let me know in the comment section.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/screen-record-obs-wayland/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/best-linux-screen-recorders/
|
||||
[2]: https://wayland.freedesktop.org/
|
||||
[3]: https://itsfoss.com/gnome-screen-recorder/
|
||||
[4]: https://itsfoss.com/kooha-screen-recorder/
|
||||
[5]: https://itsfoss.com/switch-xorg-wayland/
|
||||
[6]: https://obsproject.com/
|
||||
[7]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/obs-screen-record-wayland.webp?resize=800%2C450&ssl=1
|
||||
[8]: https://launchpad.net/~obsproject/+archive/ubuntu/obs-studio
|
||||
[9]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/09/obs-studio-add-screen-capture-source.png?resize=800%2C537&ssl=1
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/obs-studio-wayland-support.png?resize=800%2C538&ssl=1
|
||||
[11]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/09/obs-studio-screen.png?resize=800%2C578&ssl=1
|
||||
[12]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/09/start-screen-recording-obs-wayland.jpg?resize=800%2C537&ssl=1
|
460
sources/tech/20210916 Crunch numbers in Python with NumPy.md
Normal file
460
sources/tech/20210916 Crunch numbers in Python with NumPy.md
Normal file
@ -0,0 +1,460 @@
|
||||
[#]: subject: "Crunch numbers in Python with NumPy"
|
||||
[#]: via: "https://opensource.com/article/21/9/python-numpy"
|
||||
[#]: author: "Ayush Sharma https://opensource.com/users/ayushsharma"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Crunch numbers in Python with NumPy
|
||||
======
|
||||
This article discusses installing NumPy, and then creating, reading, and
|
||||
sorting NumPy arrays.
|
||||
![old school calculator][1]
|
||||
|
||||
NumPy, or **Num**erical **Py**thon, is a library that makes it easy to do statistical and set operations on linear series and matrices in Python. It is orders of magnitude faster than Python lists, [which I covered in my notes on Python Data Types][2]. NumPy is used quite frequently in data analysis and scientific calculations.
|
||||
|
||||
I'm going to go over installing NumPy, and then creating, reading, and sorting NumPy arrays. NumPy arrays are also called _ndarrays_, short for **n-dimensional arrays**.
|
||||
|
||||
### Installing NumPy
|
||||
|
||||
Installing the NumPy package is really simple using `pip`, and it can be installed just like you would install any other package.
|
||||
|
||||
|
||||
```
|
||||
pip install numpy
|
||||
```
|
||||
|
||||
With the NumPy package installed, just import it into your Python file.
|
||||
|
||||
|
||||
```
|
||||
import numpy as np
|
||||
```
|
||||
|
||||
Importing `numpy` as `np` is a standard convention, but instead of using `np` you can use any other alias that you want.
|
||||
|
||||
### Why use NumPy? Because it is orders of magnitude faster than Python lists.
|
||||
|
||||
NumPy is orders of magnitude faster than normal Python lists when it comes to handling a large number of values. To see exactly how fast it is, I'm going to first measure the time it takes for `min()` and `max()` operations on a normal Python list.
|
||||
|
||||
I will first create a Python list with 999,999,999 items.
|
||||
|
||||
|
||||
```
|
||||
>>> my_list = range(1, 1000000000)
|
||||
>>> len(my_list)
|
||||
999999999
|
||||
```
|
||||
|
||||
Now I'll measure the time for finding the minimum value in this list.
|
||||
|
||||
|
||||
```
|
||||
>>> start = time.time()
|
||||
>>> min(my_list)
|
||||
1
|
||||
>>> print('Time elapsed in milliseconds: ' + str((time.time() - start) * 1000))
|
||||
Time elapsed in milliseconds: 27007.00879096985
|
||||
```
|
||||
|
||||
That took about 27,007 milliseconds or about **27 seconds**. That’s a long time. Now I'll try to find the time for finding the maximum value.
|
||||
|
||||
|
||||
```
|
||||
>>> start = time.time()
|
||||
>>> max(my_list)
|
||||
999999999
|
||||
>>> print('Time elapsed in milliseconds: ' + str((time.time() - start) * 1000))
|
||||
Time elapsed in milliseconds: 28111.071348190308
|
||||
```
|
||||
|
||||
That took about 28,111 milliseconds, which is about **28 seconds**.
|
||||
|
||||
Now I'll try to find the time to find the minimum and maximum value using NumPy.
|
||||
|
||||
|
||||
```
|
||||
>>> my_list = np.arange(1, 1000000000)
|
||||
>>> len(my_list)
|
||||
999999999
|
||||
>>> start = time.time()
|
||||
>>> my_list.min()
|
||||
1
|
||||
>>> print('Time elapsed in milliseconds: ' + str((time.time() - start) * 1000))
|
||||
Time elapsed in milliseconds: 1151.1778831481934
|
||||
>>>
|
||||
>>> start = time.time()
|
||||
>>> my_list.max()
|
||||
999999999
|
||||
>>> print('Time elapsed in milliseconds: ' + str((time.time() - start) * 1000))
|
||||
Time elapsed in milliseconds: 1114.8970127105713
|
||||
```
|
||||
|
||||
That took about 1151 milliseconds for finding the minimum value, and 1114 milliseconds for finding the maximum value. These are around **1 second**.
|
||||
|
||||
As you can see, using NumPy reduces the time to find the minimum and maximum of a list of around a billion values **from around 28 seconds to 1 second**. This is the power of NumPy.
|
||||
|
||||
### Creating ndarrays using Python lists
|
||||
|
||||
There are several ways to create an ndarray in NumPy.
|
||||
|
||||
You can create an ndarray by using a list of elements.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.array([1, 2, 3, 4, 5])
|
||||
>>> print(my_ndarray)
|
||||
[1 2 3 4 5]
|
||||
```
|
||||
|
||||
With the above ndarray defined, I'll check out a few things. First, the type of the variable defined above is `numpy.ndarray`. This is the type of all NumPy ndarrays.
|
||||
|
||||
|
||||
```
|
||||
>>> type(my_ndarray)
|
||||
<class 'numpy.ndarray'>
|
||||
```
|
||||
|
||||
Another thing to note here would be _shape_. The shape of an ndarray is the length of each dimension of the ndarray. As you can see, the shape of `my_ndarray` is `(5,)`. This means that `my_ndarray` contains one dimension with 5 elements.
|
||||
|
||||
|
||||
```
|
||||
>>> np.shape(my_ndarray)
|
||||
(5,)
|
||||
```
|
||||
|
||||
The number of dimensions in the array is called its _rank_. So the above ndarray has a rank of 1.
|
||||
|
||||
I'll define another ndarray `my_ndarray2` as a multi-dimensional ndarray. What will its shape be then? See below.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray2 = np.array([(1, 2, 3), (4, 5, 6)])
|
||||
>>> np.shape(my_ndarray2)
|
||||
(2, 3)
|
||||
```
|
||||
|
||||
This is a rank 2 ndarray. Another attribute to check is the `dtype`, which is the data type. Checking the `dtype` for our ndarray gives us the following:
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray.dtype
|
||||
dtype('int64')
|
||||
```
|
||||
|
||||
The `int64` means that our ndarray is made up of 64-bit integers. NumPy cannot create an ndarray of mixed types, and must contain only one type of element. If you define an ndarray containing a mix of element types, NumPy will automatically typecast all the elements to the highest element type available that can contain all the elements.
|
||||
|
||||
For example, creating a mix of `int`s and `float`s will create a `float64` ndarray.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray2 = np.array([1, 2.0, 3])
|
||||
>>> print(my_ndarray2)
|
||||
[1. 2. 3.]
|
||||
>>> my_ndarray2.dtype
|
||||
dtype('float64')
|
||||
```
|
||||
|
||||
Also, setting one of the elements as `string` will create string ndarray of `dtype` equal to `<U21`, meaning our ndarray contains unicode strings.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray2 = np.array([1, '2', 3])
|
||||
>>> print(my_ndarray2)
|
||||
['1' '2' '3']
|
||||
>>> my_ndarray2.dtype
|
||||
dtype('<U21')
|
||||
```
|
||||
|
||||
The `size` attribute will show the total number of elements that are present in our ndarray.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.array([1, 2, 3, 4, 5])
|
||||
>>> my_ndarray.size
|
||||
5
|
||||
```
|
||||
|
||||
### Creating ndarrays using NumPy methods
|
||||
|
||||
There are several NumPy methods available for creating ndarrays in case you don’t want to create them directly using a list.
|
||||
|
||||
You can use `np.zeros()` to create an ndarray full of zeroes. It takes a shape as a parameter, which is a list containing the number of rows and columns. It can also take an optional `dtype` parameter which is the data type of the ndarray.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.zeros([2,3], dtype=int)
|
||||
>>> print(my_ndarray)
|
||||
[[0 0 0]
|
||||
[0 0 0]]
|
||||
```
|
||||
|
||||
You can use `np.ones()` to create an ndarray full of ones.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.ones([2,3], dtype=int)
|
||||
>>> print(my_ndarray)
|
||||
[[1 1 1]
|
||||
[1 1 1]]
|
||||
```
|
||||
|
||||
You can use `np.full()` to fill an ndarray with a specific value.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.full([2,3], 10, dtype=int)
|
||||
>>> print(my_ndarray)
|
||||
[[10 10 10]
|
||||
[10 10 10]]
|
||||
```
|
||||
|
||||
You can use `np.eye()` to create an identity matrix/ndarray, which is a square matrix with ones all along the main diagonal. A square matrix is a matrix with the same number of rows and columns.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.eye(3, dtype=int)
|
||||
>>> print(my_ndarray)
|
||||
[[1 0 0]
|
||||
[0 1 0]
|
||||
[0 0 1]]
|
||||
```
|
||||
|
||||
You can use `np.diag()` to create a matrix with the specified values along the diagonal, and zeroes in the rest of the matrix.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.diag([10, 20, 30, 40, 50])
|
||||
>>> print(my_ndarray)
|
||||
[[10 0 0 0 0]
|
||||
[ 0 20 0 0 0]
|
||||
[ 0 0 30 0 0]
|
||||
[ 0 0 0 40 0]
|
||||
[ 0 0 0 0 50]]
|
||||
```
|
||||
|
||||
You can use `np.arange()` to create an ndarray with a specific range of values. It is used by specifying a start and end (exclusive) range of integers and a step size.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.arange(1, 20, 3)
|
||||
>>> print(my_ndarray)
|
||||
[ 1 4 7 10 13 16 19]
|
||||
```
|
||||
|
||||
### Reading ndarrays
|
||||
|
||||
The values of an ndarray can be read using indexing, slicing, or boolean indexing.
|
||||
|
||||
#### Reading ndarrays using indexing
|
||||
|
||||
In indexing, you can read the values using the integer indices of the elements of the ndarray, much like you would read a Python list. Just like Python lists, the indices start from zero.
|
||||
|
||||
For example, in the ndarray defined as below:
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.arange(1, 20, 3)
|
||||
```
|
||||
|
||||
The fourth value will be `my_ndarray[3]`, or `10`. The last value will be `my_ndarray[-1]`, or `19`.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.arange(1, 20, 3)
|
||||
>>> print(my_ndarray[0])
|
||||
1
|
||||
>>> print(my_ndarray[3])
|
||||
10
|
||||
>>> print(my_ndarray[-1])
|
||||
19
|
||||
>>> print(my_ndarray[5])
|
||||
16
|
||||
>>> print(my_ndarray[6])
|
||||
19
|
||||
```
|
||||
|
||||
#### Reading ndarrays using slicing
|
||||
|
||||
You can also use slicing to read chunks of the ndarray. Slicing works by specifying a start index and an end index using a colon (`:`) operator. Python will then fetch the slice of the ndarray between that start and end index.
|
||||
|
||||
|
||||
```
|
||||
>>> print(my_ndarray[:])
|
||||
[ 1 4 7 10 13 16 19]
|
||||
>>> print(my_ndarray[2:4])
|
||||
[ 7 10]
|
||||
>>> print(my_ndarray[5:6])
|
||||
[16]
|
||||
>>> print(my_ndarray[6:7])
|
||||
[19]
|
||||
>>> print(my_ndarray[:-1])
|
||||
[ 1 4 7 10 13 16]
|
||||
>>> print(my_ndarray[-1:])
|
||||
[19]
|
||||
```
|
||||
|
||||
Slicing creates a reference, or view, of an ndarray. This means that modifying the values in a slice will also change the values of the original ndarray.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray[-1:] = 100
|
||||
>>> print(my_ndarray)
|
||||
[ 1 4 7 10 13 16 100]
|
||||
```
|
||||
|
||||
For slicing ndarrays with rank more than 1, the `[row-start-index:row-end-index, column-start-index:column-end-index]` syntax can be used.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray2 = np.array([(1, 2, 3), (4, 5, 6)])
|
||||
>>> print(my_ndarray2)
|
||||
[[1 2 3]
|
||||
[4 5 6]]
|
||||
>>> print(my_ndarray2[0:2,1:3])
|
||||
[[2 3]
|
||||
[5 6]]
|
||||
```
|
||||
|
||||
#### Reading ndarrays using boolean indexing
|
||||
|
||||
Another way to read ndarrays is using boolean indexing. In this method, you specify a filtering condition within square brackets and a section of the ndarray that matches that criteria is returned.
|
||||
|
||||
For example, to get all the values in an ndarray greater than 5, you might specify a boolean indexing operation as `my_ndarray[my_ndarray > 5]`. This operation will return an ndarray that contains all values greater than 5.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
||||
>>> my_ndarray2 = my_ndarray[my_ndarray > 5]
|
||||
>>> print(my_ndarray2)
|
||||
[ 6 7 8 9 10]
|
||||
```
|
||||
|
||||
For example, to get all the even values in an ndarray, you might use a boolean indexing operation as follows:
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray2 = my_ndarray[my_ndarray % 2 == 0]
|
||||
>>> print(my_ndarray2)
|
||||
[ 2 4 6 8 10]
|
||||
```
|
||||
|
||||
And to get all the odd values, you might use this:
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray2 = my_ndarray[my_ndarray % 2 == 1]
|
||||
>>> print(my_ndarray2)
|
||||
[1 3 5 7 9]
|
||||
```
|
||||
|
||||
### Vector and scalar arithmetic with ndarrays
|
||||
|
||||
NumPy ndarrays allow vector and scalar arithmetic operations. In vector arithmetic, an element-wise arithmetic operation is performed between two ndarrays. In scalar arithmetic, an arithmetic operation is performed between an ndarray and a constant scalar value.
|
||||
|
||||
Consider the two ndarrays below.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.array([1, 2, 3, 4, 5])
|
||||
>>> my_ndarray2 = np.array([6, 7, 8, 9, 10])
|
||||
```
|
||||
|
||||
If you add the above two ndarrays, it would produce a new ndarray where each element of the two ndarrays would be added. For example, the first element of the resultant ndarray would be the result of adding the first elements of the original ndarrays, and so on.
|
||||
|
||||
|
||||
```
|
||||
>>> print(my_ndarray2 + my_ndarray)
|
||||
[ 7 9 11 13 15]
|
||||
```
|
||||
|
||||
Here, `7` is the sum of `1` and `6`, which are the first two elements of the ndarrays I've added together. Similarly, `15` is the sum of `5` and `10`, which are the last elements.
|
||||
|
||||
Consider the following arithmetic operations:
|
||||
|
||||
|
||||
```
|
||||
>>> print(my_ndarray2 - my_ndarray)
|
||||
[5 5 5 5 5]
|
||||
>>>
|
||||
>>> print(my_ndarray2 * my_ndarray)
|
||||
[ 6 14 24 36 50]
|
||||
>>>
|
||||
>>> print(my_ndarray2 / my_ndarray)
|
||||
[6. 3.5 2.66666667 2.25 2. ]
|
||||
```
|
||||
|
||||
Adding a scalar value to an ndarray has a similar effect—the scalar value is added to all the elements of the ndarray. This is called _broadcasting_.
|
||||
|
||||
|
||||
```
|
||||
>>> print(my_ndarray + 10)
|
||||
[11 12 13 14 15]
|
||||
>>>
|
||||
>>> print(my_ndarray - 10)
|
||||
[-9 -8 -7 -6 -5]
|
||||
>>>
|
||||
>>> print(my_ndarray * 10)
|
||||
[10 20 30 40 50]
|
||||
>>>
|
||||
>>> print(my_ndarray / 10)
|
||||
[0.1 0.2 0.3 0.4 0.5]
|
||||
```
|
||||
|
||||
### Sorting ndarrays
|
||||
|
||||
There are two ways available to sort ndarrays—in-place or out-of-place. In-place sorting sorts and modifies the original ndarray, and out-of-place sorting will return the sorted ndarray but not modify the original one. I'll try out both examples.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.array([3, 1, 2, 5, 4])
|
||||
>>> my_ndarray.sort()
|
||||
>>> print(my_ndarray)
|
||||
[1 2 3 4 5]
|
||||
```
|
||||
|
||||
As you can see, the `sort()` method sorts the ndarray in-place and modifies the original array.
|
||||
|
||||
There is another method called `np.sort()` which sorts the array out of place.
|
||||
|
||||
|
||||
```
|
||||
>>> my_ndarray = np.array([3, 1, 2, 5, 4])
|
||||
>>> print(np.sort(my_ndarray))
|
||||
[1 2 3 4 5]
|
||||
>>> print(my_ndarray)
|
||||
[3 1 2 5 4]
|
||||
```
|
||||
|
||||
As you can see, the `np.sort()` method returns a sorted ndarray but does not modify it.
|
||||
|
||||
### Conclusion
|
||||
|
||||
I've covered quite a bit about NumPy and ndarrays. I talked about creating ndarrays, the different ways of reading them, basic vector and scalar arithmetic, and sorting. There is a lot more to explore with NumPy, including set operations like `union()` and `intersection()`, statistical operations like `min()` and `max()`, etc.
|
||||
|
||||
I hope the examples I demonstrated above were useful. Have fun exploring NumPy.
|
||||
|
||||
* * *
|
||||
|
||||
_This article was originally published on the [author's personal blog][3] and has been adapted with permission._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/9/python-numpy
|
||||
|
||||
作者:[Ayush Sharma][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ayushsharma
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/math_money_financial_calculator_colors.jpg?itok=_yEVTST1 (old school calculator)
|
||||
[2]: https://notes.ayushsharma.in/2018/09/data-types-in-python
|
||||
[3]: https://notes.ayushsharma.in/2018/10/working-with-numpy-in-python
|
@ -0,0 +1,188 @@
|
||||
[#]: subject: "Debugging by starting a REPL at a breakpoint is fun"
|
||||
[#]: via: "https://jvns.ca/blog/2021/09/16/debugging-in-a-repl-is-fun/"
|
||||
[#]: author: "Julia Evans https://jvns.ca/"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Debugging by starting a REPL at a breakpoint is fun
|
||||
======
|
||||
|
||||
Hello! I was talking to a Python programmer friend yesterday about debugging, and I mentioned that I really like debugging using a REPL. He said he’d never tried it and that it sounded fun, so I thought I’d write a quick post about it.
|
||||
|
||||
This debugging method doesn’t work in a lot of languages, but it does work in Python and Ruby and kiiiiiind of in C (via gdb).
|
||||
|
||||
### what’s a REPL?
|
||||
|
||||
REPL stands for “read eval print loop”. A REPL is a program that:
|
||||
|
||||
1. reads some input from you like `print(f"2 + 2 = {2+2}")` (**read**)
|
||||
2. evaluates the input (**eval**)
|
||||
3. print out the result (**print**)
|
||||
4. and then goes back to step 1 (**loop**)
|
||||
|
||||
|
||||
|
||||
Here’s an example of me using the IPython REPL to run a print statement. (also it demonstrates f-strings, my favourite Python 3 feature)
|
||||
|
||||
```
|
||||
$ ipython3
|
||||
Python 3.9.5 (default, May 24 2021, 12:50:35)
|
||||
Type 'copyright', 'credits' or 'license' for more information
|
||||
IPython 7.24.1 -- An enhanced Interactive Python. Type '?' for help.
|
||||
|
||||
In [1]: print(f"2 + 2 = {2+2}")
|
||||
2 + 2 = 4
|
||||
|
||||
In [2]:
|
||||
```
|
||||
|
||||
### you can start a REPL at a breakpoint
|
||||
|
||||
There are 2 ways to use a REPL when debugging.
|
||||
|
||||
**Way 1**: Open an empty REPL (like IPython, pry, or a browser Javascript console) to test out something.
|
||||
|
||||
This is great but it’s not what I’m talking about in this post.
|
||||
|
||||
**Way 2**: Set a breakpoint in your program, and start a REPL at that breakpoint.
|
||||
|
||||
This is the one we’re going to be talking about. I like doing this because it gives me both:
|
||||
|
||||
1. all the variables in scope at the breakpoint, so I can print them out interactively
|
||||
2. easy access to all the functions in my program, so I can call them to try to find issues
|
||||
|
||||
|
||||
|
||||
### how to get a REPL in Python: `ipdb.set_trace()`
|
||||
|
||||
Here’s a program called `test.py` that sets a breakpoint on line 5 using `import ipdb; ipdb.set_trace()`.
|
||||
|
||||
```
|
||||
import requests
|
||||
|
||||
def make_request():
|
||||
result = requests.get("https://google.com")
|
||||
import ipdb; ipdb.set_trace()
|
||||
|
||||
make_request()
|
||||
```
|
||||
|
||||
And here’s what it looks like when you run it: you get a REPL where you can inspect the `result` variable or do anything else you want.
|
||||
|
||||
```
|
||||
python3 test.py
|
||||
--Return--
|
||||
None
|
||||
> /home/bork/work/homepage/test.py(5)make_request()
|
||||
4 result = requests.get("https://google.com")
|
||||
----> 5 import ipdb; ipdb.set_trace()
|
||||
6
|
||||
|
||||
ipdb> result.headers
|
||||
{'Date': 'Thu, 16 Sep 2021 13:11:19 GMT', 'Expires': '-1', 'Cache-Control': 'private, max-age=0', 'Content-Type': 'text/html; charset=ISO-8859-1', 'P3P': 'CP="This is not a P3P policy! See g.co/p3phelp for more info."', 'Content-Encoding': 'gzip', 'Server': 'gws', 'X-XSS-Protection': '0', 'X-Frame-Options': 'SAMEORIGIN', 'Set-Cookie': '1P_JAR=2021-09-16-13; expires=Sat, 16-Oct-2021 13:11:19 GMT; path=/; domain=.google.com; Secure, NID=223=FXhKNT7mgxX7Fjhh6Z6uej9z13xYKdm9ZuAU540WDoIwYMj9AZzWTgjsVX-KJF6GErxfMijl-uudmjrJH1wgH3c1JjudPcmDMJovNuuAiJqukh1dAao_vUiqL8ge8pSIXRx89vAyYy3BDRrpJHbEF33Hbgt2ce4_yCZPtDyokMk; expires=Fri, 18-Mar-2022 13:11:19 GMT; path=/; domain=.google.com; HttpOnly', 'Alt-Svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"', 'Transfer-Encoding': 'chunked'}
|
||||
```
|
||||
|
||||
You have to install `ipdb` to make this work, but I think it’s worth it – `import pdb; pdb.set_trace()` will work too (and is built into Python) but `ipdb` is much nicer. I just learned that you can also use `breakpoint()` in Python 3 to get a breakpoint, but that puts you in `pdb` too which I don’t like.
|
||||
|
||||
### how to get a REPL in Ruby: `binding.pry`
|
||||
|
||||
Here’s the same thing in Ruby – I wrote a `test.rb` program:
|
||||
|
||||
```
|
||||
require 'net/http'
|
||||
require 'pry'
|
||||
|
||||
def make_request()
|
||||
result = Net::HTTP.get_response('example.com', '/')
|
||||
binding.pry
|
||||
end
|
||||
|
||||
make_request()
|
||||
```
|
||||
|
||||
and here’s what it looks like when I run it:
|
||||
|
||||
```
|
||||
$ ruby test.rb
|
||||
From: /home/bork/work/homepage/test.rb:6 Object#make_request:
|
||||
|
||||
4: def make_request()
|
||||
5: result = Net::HTTP.get_response('example.com', '/')
|
||||
=> 6: binding.pry
|
||||
7: end
|
||||
|
||||
[1] pry(main)> result.code
|
||||
=> "200"
|
||||
```
|
||||
|
||||
### you can also do get a REPL in the middle of an HTTP request
|
||||
|
||||
Rails also lets you start a REPL in the middle of a HTTP request and poke around and see what’s happening. I assume you can do this in Flask and Django too – I’ve only really done this in Sinatra (in Ruby).
|
||||
|
||||
### GDB is sort of like a REPL for C
|
||||
|
||||
I was talking to another friend about REPLs, and we agreed that GDB is a little bit like a REPL for C.
|
||||
|
||||
Now, obviously this is sort of not true – C is a compiled language, and you can’t just type in arbitrary C expressions in GDB and have them work.
|
||||
|
||||
But you can do a surprising number of things like:
|
||||
|
||||
* call functions
|
||||
* inspect structs if your program has debugging symbols (`p var->field->subfield`)
|
||||
|
||||
|
||||
|
||||
This stuff only works in gdb because the gdb developers put in a lot of work doing Very Weird Things to make it easier to get a REPL-like experience. I wrote a blog post a few years called [how does gdb call functions?][1] about how surprising it is that gdb can call functions, and how it does that.
|
||||
|
||||
This is the only way I use `gdb` when looking at C programs – I never set watchpoints or do anything fancy, I just set a couple of breakpoints in the program and then poke around at those points.
|
||||
|
||||
### where this method works
|
||||
|
||||
languages where this works:
|
||||
|
||||
* Python
|
||||
* Ruby
|
||||
* probably PHP, but I don’t know
|
||||
* C, sort of, in a weird way (though you might disagree :))
|
||||
|
||||
|
||||
|
||||
languages where this doesn’t work:
|
||||
|
||||
* most compiled languages
|
||||
* in Javascript, I think even though you can get a REPL with `node inspect` and `debugger`, the REPL doesn’t integrate well with async functions which makes it less useful. I don’t really understand this yet though. (python’s REPL also doesn’t let you use `await`, but it’s not as big of a deal because async programming in Python isn’t as core a part of the language as in JS)
|
||||
|
||||
|
||||
|
||||
### REPL debugging is easy for me to remember how to do
|
||||
|
||||
There are (at least) 4 different ways of debugging:
|
||||
|
||||
1. Lots of print statements
|
||||
2. a debugger
|
||||
3. getting a REPL at a breakpoint
|
||||
4. inspect your program with external tools like strace
|
||||
|
||||
|
||||
|
||||
I think part of the reason I like this type of REPL debugging more than using a more traditional debugger is – it’s so easy to remember how to do it! I can just set a breakpoint, and then run code to try to figure out what’s wrong.
|
||||
|
||||
With debuggers, I always forget how to use the debugger (probably partly because I switch programming languages a lot) and I get confused about what features it has and how they work, so I never use it.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2021/09/16/debugging-in-a-repl-is-fun/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://jvns.ca/blog/2018/01/04/how-does-gdb-call-functions/
|
@ -0,0 +1,865 @@
|
||||
[#]: subject: "How I patched Python to include this great Ruby feature"
|
||||
[#]: via: "https://opensource.com/article/21/9/python-else-less"
|
||||
[#]: author: "Miguel Brito https://opensource.com/users/miguendes"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
How I patched Python to include this great Ruby feature
|
||||
======
|
||||
What I learned from adding "else-less" functionality to Python, as
|
||||
inspired by Ruby.
|
||||
![Python programming language logo with question marks][1]
|
||||
|
||||
Ruby, [unlike Python][2], makes lots of things implicit, and there's a special kind of _if_ expression that demonstrates this well. It's often referred to as an "inline-if" or "conditional modifier", and this special syntax is able to return one value when a condition is true, but another value (`nil`, specifically) when a condition is false. Here's an example:
|
||||
|
||||
|
||||
```
|
||||
$ irb
|
||||
irb(main):> RUBY_VERSION
|
||||
=> "2.7.1"
|
||||
irb(main):> a = 42 if true
|
||||
=> 42
|
||||
irb(main):> b = 21 if false
|
||||
=> nil
|
||||
irb(main):> b
|
||||
=> nil
|
||||
irb(main):> a
|
||||
=> 42
|
||||
```
|
||||
|
||||
In Python, you can't do that without explicitly adding an `else` clause to the expression. In fact, as of [this PR][3], the interpreter tells you immediately that `else` is mandatory:
|
||||
|
||||
|
||||
```
|
||||
$ python
|
||||
Python 3.11.0a0
|
||||
>>> a = 42 if True
|
||||
File "<stdin>", line 1
|
||||
;a = 42 if True
|
||||
^^^^^^^^^^
|
||||
SyntaxError: expected 'else' after 'if' expression
|
||||
```
|
||||
|
||||
However, I find Ruby's `if` actually very convenient.
|
||||
|
||||
![return if python][4]
|
||||
|
||||
Python accepts else-less if statements, similar to Ruby.
|
||||
|
||||
This convenience became more evident when I had to go back to Python and write things like this:
|
||||
|
||||
|
||||
```
|
||||
`>>> my_var = 42 if some_cond else None`
|
||||
```
|
||||
|
||||
So I thought to myself, what would it be like if Python had a similar feature? Could I do it myself? How hard would that be?
|
||||
|
||||
### Looking into Python's source code
|
||||
|
||||
Digging into CPython's code and changing the language's syntax sounded not trivial to me. Luckily, during the same week, I found out on Twitter that [Anthony Shaw][5] had just written a [book on CPython Internals][6] and it was available for pre-release. I didn't think twice and bought the book. I've got to be honest, I'm the kind of person who buys things and doesn't use them immediately. As I had other plans in mind, I let it "gather dust" in my home folder until I had to work with that Ruby service again. It reminded me of the CPython Internals book and how challenging hacking the guts of Python would be.
|
||||
|
||||
The first thing was to go through the book from the very start and try to follow each step. The book focuses on Python 3.9, so in order to follow it, one needs to check out the 3.9 tag, and that's what I did. I learned about how the code is structured and then how to compile it. The next chapters show how to extend the grammar and add new things, such as a new operator.
|
||||
|
||||
As I got familiar with the code base and how to tweak the grammar, I decided to give it a spin and make my own changes to it.
|
||||
|
||||
### The first (failed) attempt
|
||||
|
||||
As I started finding my way around CPython's code from the latest main branch, I noticed that lots of things had changed since Python 3.9, yet some fundamental concepts didn't.
|
||||
|
||||
My first attempt was to dig into the grammar definition and find the if expression rule. The file is currently named `Grammar/python.gram`. Locating it was not difficult. An ordinary **CTRL+F** for the `else` keyword was enough.
|
||||
|
||||
|
||||
```
|
||||
file: Grammar/python.gram
|
||||
...
|
||||
expression[expr_ty] (memo):
|
||||
| invalid_expression
|
||||
| a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }
|
||||
| disjunction
|
||||
| lambdef
|
||||
....
|
||||
```
|
||||
|
||||
Now with the rule in hand, my idea was to add one more option to the current `if` expression where it would match `a=disjunction 'if' b=disjunction` and the `c` expression would be `NULL`.
|
||||
|
||||
This new rule should be placed immediately after the complete one, otherwise, the parser would match `a=disjunction 'if' b=disjunction` always, returning a `SyntaxError`.
|
||||
|
||||
|
||||
```
|
||||
...
|
||||
expression[expr_ty] (memo):
|
||||
| invalid_expression
|
||||
| a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }
|
||||
| a=disjunction 'if' b=disjunction { _PyAST_IfExp(b, a, NULL, EXTRA) }
|
||||
| disjunction
|
||||
| lambdef
|
||||
....
|
||||
```
|
||||
|
||||
### Regenerating the parser and compiling Python from source
|
||||
|
||||
CPython comes with a `Makefile` containing lots of useful commands. One of them is the [`regen-pegen` command][7] which converts `Grammar/python.gram` into `Parser/parser.c`.
|
||||
|
||||
Besides changing the grammar, I had to modify the AST for the _if_ expression. AST stands for Abstract Syntax Tree, and it is a way of representing the syntactic structure of the grammar as a tree. For more information about ASTs, I highly recommend the [Crafting Interpreters book][8] by [Robert Nystrom][9].
|
||||
|
||||
Moving on, if you observe the rule for the _if_ expression, it goes like this:
|
||||
|
||||
|
||||
```
|
||||
` | a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }`
|
||||
```
|
||||
|
||||
The means when the parser finds this rule, it calls the `_PyAST_IfExp`, which gives back a `expr_ty` data structure. So this gave me a clue that to implement the new rule's behavior, I'd need to change `_PyAST_IfExp`.
|
||||
|
||||
To find where it is located, I used my `rip-grep` skills and searched for it inside the source root:
|
||||
|
||||
|
||||
```
|
||||
$ rg _PyAST_IfExp -C2 .
|
||||
|
||||
[OMITTED]
|
||||
Python/Python-ast.c
|
||||
2686-
|
||||
2687-expr_ty
|
||||
2688:_PyAST_IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, int
|
||||
2689- col_offset, int end_lineno, int end_col_offset, PyArena *arena)
|
||||
2690-{
|
||||
[OMITTED]
|
||||
```
|
||||
|
||||
The implementation goes like this:
|
||||
|
||||
|
||||
```
|
||||
expr_ty
|
||||
_PyAST_IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, int
|
||||
col_offset, int end_lineno, int end_col_offset, PyArena *arena)
|
||||
{
|
||||
expr_ty p;
|
||||
if (!test) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"field 'test' is required for IfExp");
|
||||
return NULL;
|
||||
}
|
||||
if (!body) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"field 'body' is required for IfExp");
|
||||
return NULL;
|
||||
}
|
||||
if (!orelse) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"field 'orelse' is required for IfExp");
|
||||
return NULL;
|
||||
}
|
||||
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
|
||||
if (!p)
|
||||
return NULL;
|
||||
p->kind = IfExp_kind;
|
||||
p->v.IfExp.test = test;
|
||||
p->v.IfExp.body = body;
|
||||
p->v.IfExp.orelse = orelse;
|
||||
p->lineno = lineno;
|
||||
p->col_offset = col_offset;
|
||||
p->end_lineno = end_lineno;
|
||||
p->end_col_offset = end_col_offset;
|
||||
return p;
|
||||
}
|
||||
```
|
||||
|
||||
Since I passed **orelse**NULL, I thought it was just a matter of changing the body of `if (!orelse)`None to `orelse`. It would look like this:
|
||||
|
||||
|
||||
```
|
||||
if (!orelse) {
|
||||
\- PyErr_SetString(PyExc_ValueError,
|
||||
\- "field 'orelse' is required for IfExp");
|
||||
\- return NULL;
|
||||
\+ orelse = Py_None;
|
||||
}
|
||||
```
|
||||
|
||||
Now it was time to test it. I compiled the code with `make -j8 -s` and fired up the interpreter:
|
||||
|
||||
|
||||
```
|
||||
$ make -j8 -s
|
||||
|
||||
Python/Python-ast.c: In function ‘_PyAST_IfExp’:
|
||||
Python/Python-ast.c:2703:16: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
|
||||
orelse = Py_None;
|
||||
```
|
||||
|
||||
Despite the glaring obvious warnings, I decided to ignore it just to see what would happen.
|
||||
|
||||
|
||||
```
|
||||
$ ./python
|
||||
Python 3.11.0a0 (heads/ruby-if-new-dirty:f92b9133ef, Aug 2 2021, 09:13:02) [GCC 7.5.0] on linux
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> a = 42 if True
|
||||
>>> a
|
||||
42
|
||||
>>> b = 21 if False
|
||||
[1] 16805 segmentation fault (core dumped) ./python
|
||||
```
|
||||
|
||||
Ouch! It worked for the `if True` case, but assigning `Py_None` to `expr_ty orelse` caused a `segfault`.
|
||||
|
||||
Time to go back to see what went wrong.
|
||||
|
||||
### The second attempt
|
||||
|
||||
It wasn't too difficult to figure out where I messed up. `orelse` is an `expr_ty`, and I assigned to it a `Py_None` which is a `PyObject *`. Again, thanks to `rip-grep`, I found its definition:
|
||||
|
||||
|
||||
```
|
||||
$ rg constant -tc -C2
|
||||
|
||||
Include/internal/pycore_asdl.h
|
||||
14-typedef PyObject * string;
|
||||
15-typedef PyObject * object;
|
||||
16:typedef PyObject * constant;
|
||||
```
|
||||
|
||||
Now, how did I find out `Py_None` was a constant?
|
||||
|
||||
While reviewing the `Grammar/python.gram` file, I found that one of the rules for the new pattern matching syntax is defined like this:
|
||||
|
||||
|
||||
```
|
||||
# Literal patterns are used for equality and identity constraints
|
||||
literal_pattern[pattern_ty]:
|
||||
| value=signed_number !('+' | '-') { _PyAST_MatchValue(value, EXTRA) }
|
||||
| value=complex_number { _PyAST_MatchValue(value, EXTRA) }
|
||||
| value=strings { _PyAST_MatchValue(value, EXTRA) }
|
||||
| 'None' { _PyAST_MatchSingleton(Py_None, EXTRA) }
|
||||
```
|
||||
|
||||
However, this rule is a `pattern_ty`, not an `expr_ty`. But that's fine. What really matters is to understand what `_PyAST_MatchSingleton` actually is. Then, I searched for it in `Python/Python-ast.c:`
|
||||
|
||||
|
||||
```
|
||||
file: Python/Python-ast.c
|
||||
...
|
||||
pattern_ty
|
||||
_PyAST_MatchSingleton(constant value, int lineno, int col_offset, int
|
||||
end_lineno, int end_col_offset, PyArena *arena)
|
||||
...
|
||||
```
|
||||
|
||||
I looked for the definition of a `None` node in the grammar. To my great relief, I found it!
|
||||
|
||||
|
||||
```
|
||||
atom[expr_ty]:
|
||||
| NAME
|
||||
| 'True' { _PyAST_Constant(Py_True, NULL, EXTRA) }
|
||||
| 'False' { _PyAST_Constant(Py_False, NULL, EXTRA) }
|
||||
| 'None' { _PyAST_Constant(Py_None, NULL, EXTRA) }
|
||||
....
|
||||
```
|
||||
|
||||
At this point, I had all the information I needed. To return an `expr_ty` representing `None`, I needed to create a node in the AST which is constant by using the `_PyAST_Constant` function.
|
||||
|
||||
|
||||
```
|
||||
| a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }
|
||||
\- | a=disjunction 'if' b=disjunction { _PyAST_IfExp(b, a, NULL, EXTRA) }
|
||||
\+ | a=disjunction 'if' b=disjunction { _PyAST_IfExp(b, a, _PyAST_Constant(Py_None, NULL, EXTRA), EXTRA) }
|
||||
| disjunction
|
||||
```
|
||||
|
||||
Next, I must revert `Python/Python-ast.c` as well. Since I'm feeding it a valid `expr_ty`, it will never be `NULL`.
|
||||
|
||||
|
||||
```
|
||||
file: Python/Python-ast.c
|
||||
...
|
||||
if (!orelse) {
|
||||
\- orelse = Py_None;
|
||||
\+ PyErr_SetString(PyExc_ValueError,
|
||||
\+ "field 'orelse' is required for IfExp");
|
||||
\+ return NULL;
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
I compiled it again:
|
||||
|
||||
|
||||
```
|
||||
$ make -j8 -s && ./python
|
||||
Python 3.11.0a0 (heads/ruby-if-new-dirty:25c439ebef, Aug 2 2021, 09:25:18) [GCC 7.5.0] on linux
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> c = 42 if True
|
||||
>>> c
|
||||
42
|
||||
>>> b = 21 if False
|
||||
>>> type(b)
|
||||
<class 'NoneType'>
|
||||
>>>
|
||||
```
|
||||
|
||||
It works!
|
||||
|
||||
Now, I needed to do one more test. Ruby functions allow returning a value if a condition matches, and if not, the rest of the function body gets executed. Like this:
|
||||
|
||||
|
||||
```
|
||||
> irb
|
||||
irb(main):> def f(test)
|
||||
irb(main):> return 42 if test
|
||||
irb(main):> puts 'missed return'
|
||||
irb(main):> return 21
|
||||
irb(main):> end
|
||||
=> :f
|
||||
irb(main):> f(false)
|
||||
missed return
|
||||
=> 21
|
||||
irb(main):> f(true)
|
||||
=> 42
|
||||
```
|
||||
|
||||
At this point, I wondered if that would work with my modified Python. I rushed to the interpreter again and wrote the same function:
|
||||
|
||||
|
||||
```
|
||||
>>> def f(test):
|
||||
... return 42 if test
|
||||
... print('missed return')
|
||||
... return 21
|
||||
...
|
||||
>>> f(False)
|
||||
>>> f(True)
|
||||
42
|
||||
>>>
|
||||
```
|
||||
|
||||
The function returns `None` if _test_ is `False`... To help me debug this, I summoned the [ast module][10]. The official docs define it like so:
|
||||
|
||||
> The ast module helps Python applications to process trees of the Python abstract syntax grammar. The abstract syntax itself might change with each Python release; this module helps to find out programmatically what the current grammar looks like.
|
||||
|
||||
I printed the AST for this function:
|
||||
|
||||
|
||||
```
|
||||
>>> fc = '''
|
||||
... def f(test):
|
||||
... return 42 if test
|
||||
... print('missed return')
|
||||
... return 21
|
||||
... '''
|
||||
>>> print(ast.dump(ast.parse(fc), indent=4))
|
||||
Module(
|
||||
body=[
|
||||
FunctionDef(
|
||||
name='f',
|
||||
args=arguments(
|
||||
posonlyargs=[],
|
||||
args=[
|
||||
arg(arg='test')],
|
||||
kwonlyargs=[],
|
||||
kw_defaults=[],
|
||||
defaults=[]),
|
||||
body=[
|
||||
Return(
|
||||
value=IfExp(
|
||||
test=Name(id='test', ctx=Load()),
|
||||
;body=Constant(value=42),
|
||||
orelse=Constant(value=None))),
|
||||
Expr(
|
||||
value=Call(
|
||||
func=Name(id='print', ctx=Load()),
|
||||
args=[
|
||||
Constant(value='missed return')],
|
||||
keywords=[])),
|
||||
Return(
|
||||
value=Constant(value=21))],
|
||||
decorator_list=[])],
|
||||
type_ignores=[])
|
||||
```
|
||||
|
||||
Now things made more sense. My change to the grammar was just "syntax sugar". It turns an expression like this: `a if b` into this: `a if b else None`. The problem here is that Python returns no matter what, so the rest of the function is ignored.
|
||||
|
||||
You can look at the [bytecode][11] generated to understand what exactly is executed by the interpreter. And for that, you can use the [`dis` module][12]. According to the docs:
|
||||
|
||||
> The dis module supports the analysis of CPython bytecode by disassembling it.
|
||||
|
||||
|
||||
```
|
||||
>>> import dis
|
||||
>>> dis.dis(f)
|
||||
2 0 LOAD_FAST 0 (test)
|
||||
2 POP_JUMP_IF_FALSE 4 (to 8)
|
||||
4 LOAD_CONST 1 (42)
|
||||
6 RETURN_VALUE
|
||||
>> 8 LOAD_CONST 0 (None)
|
||||
10 RETURN_VALUE
|
||||
```
|
||||
|
||||
What this basically means is that in case the _test_ is false, the execution jumps to 8, which loads the `None` into the top of the stack and returns it.
|
||||
|
||||
### Supporting "return-if"
|
||||
|
||||
To support the same Ruby feature, I need to turn the expression `return 42 if test` into a regular `if` statement that returns if `test` is true.
|
||||
|
||||
To do that, I needed to add one more rule. This time, it would be a rule that matches the `return <value> if <test>` piece of code. Not only that, I needed a `_PyAST_` function that creates the node for me. I'll then call it `_PyAST_ReturnIfExpr:`
|
||||
|
||||
|
||||
```
|
||||
file: Grammar/python.gram
|
||||
|
||||
return_stmt[stmt_ty]:
|
||||
\+ | 'return' a=star_expressions 'if' b=disjunction { _PyAST_ReturnIfExpr(a, b, EXTRA) }
|
||||
| 'return' a=[star_expressions] { _PyAST_Return(a, EXTRA) }
|
||||
```
|
||||
|
||||
As mentioned previously, the implementation for all these functions resides in `Python/Python-ast.c`, and their definition is in `Include/internal/pycore_ast.h`, so I put `_PyAST_ReturnIfExpr` there:
|
||||
|
||||
|
||||
```
|
||||
file: Include/internal/pycore_ast.h
|
||||
|
||||
stmt_ty _PyAST_Return(expr_ty value, int lineno, int col_offset, int
|
||||
end_lineno, int end_col_offset, PyArena *arena);
|
||||
+stmt_ty _PyAST_ReturnIfExpr(expr_ty value, expr_ty test, int lineno, int col_of
|
||||
fset, int
|
||||
\+ end_lineno, int end_col_offset, PyArena *arena);
|
||||
stmt_ty _PyAST_Delete(asdl_expr_seq * targets, int lineno, int col_offset, int
|
||||
end_lineno, int end_col_offset, PyArena *arena);
|
||||
|
||||
[/code] [code]
|
||||
|
||||
file: Python/Python-ast.c
|
||||
|
||||
+stmt_ty
|
||||
+_PyAST_ReturnIfExpr(expr_ty value, expr_ty test, int lineno, int col_offset, int end_lineno, int
|
||||
\+ end_col_offset, PyArena *arena)
|
||||
+{
|
||||
\+ stmt_ty ret, p;
|
||||
\+ ret = _PyAST_Return(value, lineno, col_offset, end_lineno, end_col_offset, arena);
|
||||
+
|
||||
\+ asdl_stmt_seq *body;
|
||||
\+ body = _Py_asdl_stmt_seq_new(1, arena);
|
||||
\+ asdl_seq_SET(body, 0, ret);
|
||||
+
|
||||
\+ p = _PyAST_If(test, body, NULL, lineno, col_offset, end_lineno, end_col_offset, arena);
|
||||
+
|
||||
\+ return p;
|
||||
+}
|
||||
+
|
||||
stmt_ty
|
||||
```
|
||||
|
||||
I examined the implementation of `_PyAST_ReturnIfExpr`. I wanted to turn `return <value> if <test>` into `if <test>: return <value>`.
|
||||
|
||||
Both `return` and the regular `if` are statements, so in CPython, they're represented as `stmt_ty`. The `_PyAST_If` expectes a `expr_ty test` and a body, which is a sequence of statements. In this case, the `body` is `asdl_stmt_seq *body`.
|
||||
|
||||
As a result, what I really wanted here was an `if` statement with a body where the only statement is a `return <value>` one.
|
||||
|
||||
CPython disposes of some convenient functions to build `asdl_stmt_seq *`, and one of them is `_Py_asdl_stmt_seq_new`. So I used it to create the body and added the return statement I created a few lines before with `_PyAST_Return`.
|
||||
|
||||
Once that was done, the last step was to pass the `test` as well as the `body` to `_PyAST_If`.
|
||||
|
||||
And before I forget, you may be wondering what on earth is the `PyArena *arena`. **Arena** is a CPython abstraction used for memory allocation. It allows efficient memory usage by using memory mapping [mmap()][13] and placing it in contiguous [chunks of memory][6].
|
||||
|
||||
Time to regenerate the parser and test it one more time:
|
||||
|
||||
|
||||
```
|
||||
>>> def f(test):
|
||||
... return 42 if test
|
||||
... print('missed return')
|
||||
... return 21
|
||||
...
|
||||
>>> import dis
|
||||
>>> f(False)
|
||||
>>> f(True)
|
||||
42
|
||||
```
|
||||
|
||||
It doesn't work. Check the bytecodes:
|
||||
|
||||
|
||||
```
|
||||
>>> dis.dis(f)
|
||||
2 0 LOAD_FAST 0 (test)
|
||||
2 POP_JUMP_IF_FALSE 4 (to 8)
|
||||
4 LOAD_CONST 1 (42)
|
||||
6 RETURN_VALUE
|
||||
>> 8 LOAD_CONST 0 (None)
|
||||
10 RETURN_VALUE
|
||||
>>>
|
||||
```
|
||||
|
||||
It's the same bytecode instructions again!
|
||||
|
||||
### Going back to the compilers class
|
||||
|
||||
At that point, I was clueless. I had no idea what was going on until I decided to go down the rabbit hole of expanding the grammar rules.
|
||||
|
||||
The new rule I added went like this: `'return' a=star_expressions 'if' b=disjunction { _PyAST_ReturnIfExpr(a, b, EXTRA) }`.
|
||||
|
||||
My only hypothesis was that `a=star_expressions 'if' b=disjunction` was being resolved to the else-less rule I added in the beginning.
|
||||
|
||||
By going over the grammar one more time, I figured that my theory held. `star_expressions` would match `a=disjunction 'if' b=disjunction { _PyAST_IfExp(b, a, NULL, EXTRA) }`.
|
||||
|
||||
The only way to fix this was by getting rid of the `star_expressions`. So I changed the rule to:
|
||||
|
||||
|
||||
```
|
||||
return_stmt[stmt_ty]:
|
||||
\- | 'return' a=star_expressions 'if' b=disjunction { _PyAST_ReturnIfExpr(a, b, EXTRA) }
|
||||
\+ | 'return' a=disjunction guard=guard !'else' { _PyAST_ReturnIfExpr(a, guard, EXTRA) }
|
||||
| 'return' a=[star_expressions] { _PyAST_Return(a, EXTRA) }
|
||||
```
|
||||
|
||||
You might be wondering, what are `guard,` `!else`, and `star_expressions`?
|
||||
|
||||
This `guard` is a rule that is part of the pattern matching rules. The new pattern matching feature added in Python 3.10 allows things like this:
|
||||
|
||||
|
||||
```
|
||||
match point:
|
||||
case Point(x, y) if x == y:
|
||||
print(f"Y=X at {x}")
|
||||
case Point(x, y):
|
||||
print(f"Not on the diagonal")
|
||||
```
|
||||
|
||||
And the rule goes by this:
|
||||
|
||||
|
||||
```
|
||||
`guard[expr_ty]: 'if' guard=named_expression { guard }`
|
||||
```
|
||||
|
||||
With that, I added one more check. To avoid it failing with `SyntaxError`, I needed to make sure the rule matched only code like this: `return value if cond`. Thus, to prevent code such as `return an if cond else b` being matched prematurely, I added a `!' else` to the rule.
|
||||
|
||||
Last but not least, the `star_expressions` allow me to return destructured iterables. For example:
|
||||
|
||||
|
||||
```
|
||||
>>> def f():
|
||||
...: a = [1, 2]
|
||||
...: return 0, *a
|
||||
...:&
|
||||
|
||||
>>> f()
|
||||
(0, 1, 2)
|
||||
```
|
||||
|
||||
In this case, `0, * a` is a tuple, which falls under the category of `star_expressions`. The regular if-expression doesn't allow using `star_expressions` with it, AFAIK, so changing the new `return` rule won't be an issue.
|
||||
|
||||
### Does it work yet?
|
||||
|
||||
After fixing the return rule, I regenerated the grammar one more time and compiled it:
|
||||
|
||||
|
||||
```
|
||||
>>> def f(test):
|
||||
... return 42 if test
|
||||
... print('missed return')
|
||||
... return 21
|
||||
...
|
||||
>>> f(False)
|
||||
missed return
|
||||
21
|
||||
>>> f(True)
|
||||
42
|
||||
```
|
||||
|
||||
It works!
|
||||
|
||||
Looking at the bytecode:
|
||||
|
||||
|
||||
```
|
||||
>>> import dis
|
||||
>>> dis.dis(f)
|
||||
2 0 LOAD_FAST 0 (test)
|
||||
2 POP_JUMP_IF_FALSE 4 (to 8)
|
||||
4 LOAD_CONST 1 (42)
|
||||
6 RETURN_VALUE
|
||||
|
||||
3 >> 8 LOAD_GLOBAL 0 (print)
|
||||
10 LOAD_CONST 2 ('missed return')
|
||||
12 CALL_FUNCTION 1
|
||||
14 POP_TOP
|
||||
|
||||
4 16 LOAD_CONST 3 (21)
|
||||
18 RETURN_VALUE
|
||||
>>>
|
||||
```
|
||||
|
||||
That's precisely what I wanted. Is the AST is the same as the one with regular `if`?
|
||||
|
||||
|
||||
```
|
||||
>>> import ast
|
||||
>>> print(ast.dump(ast.parse(fc), indent=4))
|
||||
Module(
|
||||
body=[
|
||||
FunctionDef(
|
||||
name='f',
|
||||
args=arguments(
|
||||
posonlyargs=[],
|
||||
args=[
|
||||
arg(arg='test')],
|
||||
kwonlyargs=[],
|
||||
kw_defaults=[],
|
||||
defaults=[]),
|
||||
body=[
|
||||
If(
|
||||
test=Name(id='test', ctx=Load()),
|
||||
body=[
|
||||
Return(
|
||||
value=Constant(value=42))],
|
||||
orelse=[]),
|
||||
Expr(
|
||||
value=Call(
|
||||
func=Name(id='print', ctx=Load()),
|
||||
args=[
|
||||
Constant(value='missed return')],
|
||||
keywords=[])),
|
||||
Return(
|
||||
value=Constant(value=21))],
|
||||
decorator_list=[])],
|
||||
type_ignores=[])
|
||||
>>>
|
||||
```
|
||||
|
||||
Indeed it is!
|
||||
|
||||
|
||||
```
|
||||
If(
|
||||
test=Name(id='test', ctx=Load()),
|
||||
body=[
|
||||
Return(
|
||||
value=Constant(value=42))],
|
||||
orelse=[]),
|
||||
```
|
||||
|
||||
This node is the same as the one that would be generated by:
|
||||
|
||||
|
||||
```
|
||||
`if test: return 42`
|
||||
```
|
||||
|
||||
### If it's not tested, it's broken?
|
||||
|
||||
To conclude this journey, I thought it'd be a good idea to add some unit tests as well. Before writing anything new, I wanted to get an idea of what I had broken.
|
||||
|
||||
With the code tested manually, I ran all tests using the `test` module `python -m test -j8`. The `-j8` means it uses eight processes to run the tests in parallel:
|
||||
|
||||
|
||||
```
|
||||
`$ ./python -m test -j8`
|
||||
```
|
||||
|
||||
To my surprise, only one test failed!
|
||||
|
||||
|
||||
```
|
||||
== Tests result: FAILURE ==
|
||||
406 tests OK.
|
||||
1 test failed:
|
||||
test_grammar
|
||||
```
|
||||
|
||||
Because I ran all tests, it's hard to navigate the output, so I can run only this one again in isolation:
|
||||
|
||||
|
||||
```
|
||||
======================================================================
|
||||
FAIL: test_listcomps (test.test_grammar.GrammarTests)
|
||||
\----------------------------------------------------------------------
|
||||
Traceback (most recent call last):
|
||||
File "/home/miguel/projects/cpython/Lib/test/test_grammar.py", line 1732, in test_listcomps
|
||||
check_syntax_error(self, "[x if y]")
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/miguel/projects/cpython/Lib/test/support/__init__.py", line 497, in check_syntax_error
|
||||
with testcase.assertRaisesRegex(SyntaxError, errtext) as cm:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
AssertionError: SyntaxError not raised
|
||||
\----------------------------------------------------------------------
|
||||
|
||||
Ran 76 tests in 0.038s
|
||||
|
||||
FAILED (failures=1)
|
||||
test test_grammar failed
|
||||
test_grammar failed (1 failure)
|
||||
|
||||
== Tests result: FAILURE ==
|
||||
|
||||
1 test failed:
|
||||
test_grammar
|
||||
|
||||
1 re-run test:
|
||||
test_grammar
|
||||
|
||||
Total duration: 82 ms
|
||||
Tests result: FAILURE
|
||||
```
|
||||
|
||||
And there it is! It expected a syntax error when running a `[x if y]` expression. I can safely remove it and re-run the tests again:
|
||||
|
||||
|
||||
```
|
||||
== Tests result: SUCCESS ==
|
||||
|
||||
1 test OK.
|
||||
|
||||
Total duration: 112 ms
|
||||
Tests result: SUCCESS
|
||||
```
|
||||
|
||||
Now that everything is OK, it's time to add a few more tests. It's important to test not only the new "else-less if" but also the new `return` statement.
|
||||
|
||||
By navigating through the `test_grammar.py` file, I can find a test for pretty much every grammar rule. The first one I look for is `test_if_else_expr`. This test doesn't fail, so it only tests for the happy case. To make it more robust, I needed to add two new tests to check `if True` and `if False` cases:
|
||||
|
||||
|
||||
```
|
||||
self.assertEqual((6 < 4 if 0), None)
|
||||
self.assertEqual((6 < 4 if 1), False)
|
||||
```
|
||||
|
||||
I ran everything again, and all tests passed this time.
|
||||
|
||||
Note: `bool` in Python is a [subclass of integer][14], so you can use `1` to denote `True` and `0` for `False`.
|
||||
|
||||
|
||||
```
|
||||
Ran 76 tests in 0.087s
|
||||
|
||||
OK
|
||||
|
||||
== Tests result: SUCCESS ==
|
||||
|
||||
1 test OK.
|
||||
|
||||
Total duration: 174 ms
|
||||
Tests result: SUCCESS
|
||||
```
|
||||
|
||||
Lastly, I needed the tests for the `return` rule. They're defined in the `test_return` test. Just like the `if` expression one, this test passed with no modification.
|
||||
|
||||
To test this new use case, I created a function that receives a `bool` argument and returns if the argument is true. When it's false, it skips the return, just like the manual tests I had been doing up to this point:
|
||||
|
||||
|
||||
```
|
||||
def g4(test):
|
||||
a = 1
|
||||
return a if test
|
||||
a += 1
|
||||
return a
|
||||
|
||||
self.assertEqual(g4(False), 2)
|
||||
self.assertEqual(g4(True), 1)
|
||||
```
|
||||
|
||||
I saved the file and re-ran `test_grammar` one more time:
|
||||
|
||||
|
||||
```
|
||||
\----------------------------------------------------------------------
|
||||
|
||||
Ran 76 tests in 0.087s
|
||||
|
||||
OK
|
||||
|
||||
== Tests result: SUCCESS ==
|
||||
|
||||
1 test OK.
|
||||
|
||||
Total duration: 174 ms
|
||||
Tests result: SUCCESS
|
||||
```
|
||||
|
||||
Looks good! The `test_grammar` test passed. Just in case, I re-ran the full test suite:
|
||||
|
||||
|
||||
```
|
||||
`$ ./python -m test -j8`
|
||||
```
|
||||
|
||||
After a while, all tests passed, and I'm very happy with the result.
|
||||
|
||||
### Limitations
|
||||
|
||||
If you know Ruby well, by this point, you've probably noticed that what I did here was not 100% the same as a conditional modifier. For example, in Ruby, you can run actual expressions in these modifiers:
|
||||
|
||||
|
||||
```
|
||||
irb(main):002:0> a = 42
|
||||
irb(main):003:0> a += 1 if false
|
||||
=> nil
|
||||
irb(main):004:0> a
|
||||
=> 42
|
||||
irb(main):005:0> a += 1 if true
|
||||
=> 43
|
||||
```
|
||||
|
||||
I cannot do the same with my implementation:
|
||||
|
||||
|
||||
```
|
||||
>>> a = 42
|
||||
>>> a += 1 if False
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType'
|
||||
>>> a += 1 if True
|
||||
>>> a
|
||||
43
|
||||
```
|
||||
|
||||
What this reveals is that the `return` rule I created is just a workaround. If I want to make it as close as possible to Ruby's conditional modifier, I'll need to make it work with other statements as well, not just `return`.
|
||||
|
||||
Nevertheless, this is fine. My goal with this experiment was just to learn more about Python internals and see how I would navigate a little-known code base written in C and make the appropriate changes to it. And I have to admit that I'm pretty happy with the results!
|
||||
|
||||
### Conclusion
|
||||
|
||||
Adding a new syntax inspired by Ruby is a really nice exercise to learn more about the internals of Python. Of course, if I had to convert this as a PR, the core developers would probably find a few shortcomings, as I have already described in the previous section. However, since I did this just for fun, I'm very happy with the results.
|
||||
|
||||
The source code with all my changes is on my CPython fork under the [branch ruby-if-new][15].
|
||||
|
||||
* * *
|
||||
|
||||
_This article was originally published on the [author's personal blog][16] and has been adapted with permission._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/9/python-else-less
|
||||
|
||||
作者:[Miguel Brito][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/miguendes
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/python_programming_question.png?itok=cOeJW-8r (Python programming language logo with question marks)
|
||||
[2]: https://www.python.org/dev/peps/pep-0020/#id2
|
||||
[3]: https://github.com/python/cpython/pull/27506
|
||||
[4]: https://opensource.com/sites/default/files/ihe46r0jv.gif
|
||||
[5]: https://tonybaloney.github.io/
|
||||
[6]: https://realpython.com/products/cpython-internals-book/
|
||||
[7]: https://github.com/python/cpython/blob/3.10/Makefile.pre.in#L850_L856
|
||||
[8]: https://craftinginterpreters.com/
|
||||
[9]: https://journal.stuffwithstuff.com/
|
||||
[10]: https://docs.python.org/3/library/ast.html
|
||||
[11]: https://en.wikipedia.org/wiki/Bytecode
|
||||
[12]: https://docs.python.org/3/library/dis.html
|
||||
[13]: http://man7.org/linux/man-pages/man2/mmap.2.html
|
||||
[14]: https://docs.python.org/3/c-api/bool.html
|
||||
[15]: https://github.com/miguendes/cpython/tree/ruby-if-new
|
||||
[16]: https://miguendes.me/what-if-python-had-this-ruby-feature
|
@ -0,0 +1,124 @@
|
||||
[#]: subject: "Watch commands and tasks with the Linux watch command"
|
||||
[#]: via: "https://opensource.com/article/21/9/linux-watch-command"
|
||||
[#]: author: "Moshe Zadka https://opensource.com/users/moshez"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Watch commands and tasks with the Linux watch command
|
||||
======
|
||||
See how the watch command can let you know when a task has been
|
||||
completed or a command has been executed.
|
||||
![Clock, pen, and notepad on a desk][1]
|
||||
|
||||
There are many times when you need to wait for something to finish, such as:
|
||||
|
||||
* A file download.
|
||||
* Creating or extracting a [tar][2] file.
|
||||
* An [Ansible][3] job.
|
||||
|
||||
|
||||
|
||||
Some of these processes have some sort of progress indication, but sometimes the process is run through a layer of abstraction, and the only way to measure the progress is through its side effects. Some of these might be:
|
||||
|
||||
* A file being downloaded keeps growing.
|
||||
* A directory extracted from a tarball fills up with files.
|
||||
* The Ansible job builds a [container][4].
|
||||
|
||||
|
||||
|
||||
You can query all of these things with commands like these:
|
||||
|
||||
|
||||
```
|
||||
$ ls -l downloaded-file
|
||||
$ find . | wc -l
|
||||
$ podman ps
|
||||
$ docker ps
|
||||
```
|
||||
|
||||
But running these commands over and over, even if it is with the convenience of [Bash history][5] and the **Up Arrow**, is tedious.
|
||||
|
||||
Another approach is to write a little Bash script to automate these commands for you:
|
||||
|
||||
|
||||
```
|
||||
while :
|
||||
do
|
||||
docker ps
|
||||
sleep 2
|
||||
done
|
||||
```
|
||||
|
||||
But such scripts can also become tedious to write. You could write a little generic script and package it, so it's always available to you. Luckily, other open source developers have already been there and done that.
|
||||
|
||||
The result is the command `watch`.
|
||||
|
||||
### Installing watch
|
||||
|
||||
The `watch` command is part of the [`procps-ng` package][6], so if you're on Linux, you already have it installed.
|
||||
|
||||
On macOS, install `watch` using [MacPorts][7] or [Homebrew][8]. On Windows, use [Chocolatey][9].
|
||||
|
||||
### Using watch
|
||||
|
||||
The `watch` command periodically runs a command and shows its output. It has some text-terminal niceties, so only the latest output is on the screen.
|
||||
|
||||
The simplest usage is: `watch <command>`.
|
||||
|
||||
For example, prefixing the `docker ps` command with `watch` works like this:
|
||||
|
||||
|
||||
```
|
||||
`$ watch docker ps`
|
||||
```
|
||||
|
||||
The `watch` command, and a few creative Unix command-line tricks, can generate ad-hoc dashboards. For example, to count audit events:
|
||||
|
||||
|
||||
```
|
||||
`$ watch 'grep audit: /var/log/kern.log |wc -l'`
|
||||
```
|
||||
|
||||
In the last example, it is probably useful if there's a visual indication that the number of audit events changed. If change is expected, but you want something to look "different," `watch --differences` works well. It highlights any differences from the last run. This works especially well if you are grepping in multiple files, so you can easily see which one changed.
|
||||
|
||||
If changes are not expected, you can ask for them to be highlighted "permanently" to know which ones to investigate by using `watch --differences=permanent`. This is often more useful.
|
||||
|
||||
### Controlling frequency
|
||||
|
||||
Finally, sometimes the command might be resource-intensive and should not be run too frequently. The `-n` parameter controls the frequency. Watch uses two seconds by default, but `watch -n 10` might be appropriate for something more resource-intensive, like grepping for a pattern in any file in a subdirectory:
|
||||
|
||||
|
||||
```
|
||||
`$ watch -n 10 'find . -type f | xargs grep suspicious-pattern'`
|
||||
```
|
||||
|
||||
### Watch a command with watch
|
||||
|
||||
The `watch` command is useful for many ad-hoc system administration tasks where you need to wait for some time-consuming step, without a progress bar, before moving on to the next one. Though this is not a great situation to be in, `watch` can make it slightly better—and give you time to start working on those notes for the retrospective! Download the **[cheat sheet][10] **to keep helpful syntax and options close at hand.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/9/linux-watch-command
|
||||
|
||||
作者:[Moshe Zadka][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/moshez
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/desk_clock_job_work.jpg?itok=Nj4fuhl6 (Clock, pen, and notepad on a desk)
|
||||
[2]: https://opensource.com/article/17/7/how-unzip-targz-file
|
||||
[3]: https://opensource.com/resources/what-ansible
|
||||
[4]: https://opensource.com/resources/what-docker
|
||||
[5]: https://opensource.com/article/20/6/bash-history-control
|
||||
[6]: https://opensource.com/article/21/8/linux-procps-ng
|
||||
[7]: https://opensource.com/article/20/11/macports
|
||||
[8]: https://opensource.com/article/20/6/homebrew-mac
|
||||
[9]: https://opensource.com/article/20/3/chocolatey
|
||||
[10]: https://opensource.com/downloads/watch-cheat-sheet
|
190
sources/tech/20210917 How to Install Kali Linux in VMware.md
Normal file
190
sources/tech/20210917 How to Install Kali Linux in VMware.md
Normal file
@ -0,0 +1,190 @@
|
||||
[#]: subject: "How to Install Kali Linux in VMware"
|
||||
[#]: via: "https://itsfoss.com/install-kali-linux-vmware/"
|
||||
[#]: author: "Ankush Das https://itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
How to Install Kali Linux in VMware
|
||||
======
|
||||
|
||||
Kali Linux is the de facto standard of [Linux distributions used for learning and practicin][1][g][1] [hacking and penetration testing][1].
|
||||
|
||||
And, if you’ve been tinkering around with Linux distros long enough, you might have tried it out just out of curiosity.
|
||||
|
||||
However, no matter what you use it for, it is not a replacement for a regular full-fledged desktop Linux operating system. Hence, it is recommended (at least for beginners) to install Kali Linux using a virtual machine program like VMware.
|
||||
|
||||
With a virtual machine, you can use Kali Linux as a regular application in your Windows or Linux system. It’s almost the same as running VLC or Skype in your system.
|
||||
|
||||
There are a few free virtualization tools available for you. You can [install Kali Linux on Oracle VirtualBox][2] or use VMWare Workstation.
|
||||
|
||||
This tutorial focuses on VMWare.
|
||||
|
||||
### Installing Kali Linux on VMware on Windows and Linux
|
||||
|
||||
Non-FOSS alert!
|
||||
|
||||
VM Ware is not open source software.
|
||||
|
||||
For this tutorial, I presume that you are using Windows, considering most VMware users prefer using Windows 10/11.
|
||||
|
||||
However, the _**tutorial is also valid for Linux except the VMWare installation on Windows part**_. You can [easily install VMWare on Ubuntu][3] and other Linux distributions.
|
||||
|
||||
#### Step 1: Install VMWare Workstation Player (on Windows)
|
||||
|
||||
If you already have VMware installed on your system, you can skip the steps to install Kali Linux.
|
||||
|
||||
Head to [VMWare’s official workstation player webpage][4] and then click on the “**Download Free**” button.
|
||||
|
||||
![][5]
|
||||
|
||||
Next, you get to choose the version (if you want something specific or encountering bugs in the latest version) and then click on “**Go to Downloads.**“
|
||||
|
||||
![][6]
|
||||
|
||||
And then you get the download buttons for both Windows and Linux versions. You will have to click on the button for Windows 64-bit because that is what we need here.
|
||||
|
||||
![][7]
|
||||
|
||||
There is no support for 32-bit systems, in case you were wondering.
|
||||
|
||||
Finally, when you get the .exe file downloaded, launch it to start the installation process. You need to hit “Next” to get started installing VMware.
|
||||
|
||||
![][8]
|
||||
|
||||
Next, you will have to agree to the policies and conditions to continue.
|
||||
|
||||
![][9]
|
||||
|
||||
Now, you get to choose the path of your installation. Ideally, keep it at the default settings. But, if you need better keyboard response / in-screen keyboard performance in the virtual machine, you may want to enable the “**Enhanced Keyboard Driver**.”
|
||||
|
||||
![][10]
|
||||
|
||||
Proceeding to the next step, you can choose to disable checking for updates every time you start the program (can be annoying) and disable sending data to VMware as part of its user experience improvement program.
|
||||
|
||||
![][11]
|
||||
|
||||
If you want quick access using desktop and start menu shortcuts, you can check those settings or toggle them off, which I prefer.
|
||||
|
||||
![][12]
|
||||
|
||||
Now, you have to continue to start the installation.
|
||||
|
||||
![][13]
|
||||
|
||||
This may take a while, and when completed, you get greeted with another window that lets you finish the process and gives you the option to enter a license key. If you want to get the commercial license for your use-case, you need the VMware Workstation Pro edition, or else, the player is free for personal use.
|
||||
|
||||
![][14]
|
||||
|
||||
Attention!
|
||||
|
||||
Please make sure that virtualization is enabled in your system. Recent Windows versions require that you enable the virtualization explicitly to use virtual machines.
|
||||
|
||||
#### Step 2: Install Kali Linux on VMware
|
||||
|
||||
To get started, you need to download the image file of Kali Linux. And, when it comes to Kali Linux, they offer a separate ISO file if you plan to use it on a virtual machine.
|
||||
|
||||
![][15]
|
||||
|
||||
Head to its [official download page][16] and download the prebuilt VMware image available.
|
||||
|
||||
![][17]
|
||||
|
||||
You can download the **.7z** file directly or utilize Torrent (which is generally faster). In either case, you can also check the file integrity with the SHA256 value provided.
|
||||
|
||||
Once downloaded, you need to extract the file to any path of your choice.
|
||||
|
||||
![][18]
|
||||
|
||||
Open VMware Workstation Player and then click on “**Open a Virtual Machine**.” Now, look for the folder you extracted. And navigate through it till you find a file with the “**.vmx**” extension.
|
||||
|
||||
For instance: **Kali-Linux-2021.3-vmware-amd64.vmx**
|
||||
|
||||
![][19]
|
||||
|
||||
Select the .vmx file to open the virtual machine. And, it should appear right in your VMware player.
|
||||
|
||||
You can choose to launch the virtual machine with the default settings. Or, if you want to tweak the hardware allocated to the virtual machine, feel free to change the settings before you launch it.
|
||||
|
||||
![][20]
|
||||
|
||||
Depending on your computer hardware, you should allocate more memory and at least half of your processor cores to get a smooth performance.
|
||||
|
||||
In this case, I have 16 Gigs of RAM and a quad-core processor. Hence, it is safe to allocate nearly 7 GB of RAM and two cores for this virtual machine.
|
||||
|
||||
![][21]
|
||||
|
||||
While you can assign more resources, but it might affect the performance of your host operating system when working on a task. So, it is recommended to keep a balance between the two.
|
||||
|
||||
Now, save the settings and hit “**Play virtual machine**” to start Kali Linux on VMware.
|
||||
|
||||
When it starts loading up, you may be prompted with some tips to improve performance by tweaking some virtual machine settings.
|
||||
|
||||
You do not have to do that, but if you notice performance issues, you can disable side-channel mitigations (needed for enhanced security) to uplift the performance of the VM.
|
||||
|
||||
Also, you may be prompted to download and [install VMware tools for Linux][22]; you need to do this to get a good VM experience.
|
||||
|
||||
Once you do that, you will be greeted with Kali Linux’s login screen.
|
||||
|
||||
![][23]
|
||||
|
||||
Considering that you launched a prebuilt VMware folder, you need to enter the default login and password to proceed.
|
||||
|
||||
**Username**: kali
|
||||
**Password:** kali
|
||||
|
||||
![][24]
|
||||
|
||||
That’s it! You’re done installing Kali Linux on VMware. Now, all you have to do is start exploring!
|
||||
|
||||
### Where to go from here?
|
||||
|
||||
Here are a few tips you can utilize:
|
||||
|
||||
* If clipboard sharing and file sharing is not working, [install VMWare tools][22] on the guest system (Kali Linux).
|
||||
* If you are new to it, check out this [list of Kali Linux tools][25].
|
||||
|
||||
|
||||
|
||||
Feel free to share your thoughts if you find this tutorial helpful. Do you prefer to install Kali Linux without using a VMware image ready to go? Let me know in the comments below.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/install-kali-linux-vmware/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/linux-hacking-penetration-testing/
|
||||
[2]: https://itsfoss.com/install-kali-linux-virtualbox/
|
||||
[3]: https://itsfoss.com/install-vmware-player-ubuntu-1310/
|
||||
[4]: https://www.vmware.com/products/workstation-player.html
|
||||
[5]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-player-download.png?resize=732%2C486&ssl=1
|
||||
[6]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-player-download-1.png?resize=800%2C292&ssl=1
|
||||
[7]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-player-download-final.png?resize=800%2C212&ssl=1
|
||||
[8]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-setup-1.png?resize=692%2C465&ssl=1
|
||||
[9]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-setup-license.png?resize=629%2C443&ssl=1
|
||||
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-setup-2.png?resize=638%2C440&ssl=1
|
||||
[11]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-workstation-tracking.png?resize=618%2C473&ssl=1
|
||||
[12]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-workstation-shortcuts.png?resize=595%2C445&ssl=1
|
||||
[13]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-player-install.png?resize=620%2C474&ssl=1
|
||||
[14]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-player-installed.png?resize=589%2C441&ssl=1
|
||||
[15]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-image-kali.png?resize=800%2C488&ssl=1
|
||||
[16]: https://www.kali.org/get-kali/
|
||||
[17]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-kali-linux-image-download.png?resize=800%2C764&ssl=1
|
||||
[18]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/09/extract-vmware-image.png?resize=617%2C359&ssl=1
|
||||
[19]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-kali-linux-image-folder.png?resize=800%2C498&ssl=1
|
||||
[20]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/virtual-machine-settings-kali.png?resize=800%2C652&ssl=1
|
||||
[21]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/09/kali-vm-settings.png?resize=800%2C329&ssl=1
|
||||
[22]: https://itsfoss.com/install-vmware-tools-linux/
|
||||
[23]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/kali-linux-vm-login.png?resize=800%2C540&ssl=1
|
||||
[24]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/09/vmware-kali-linux.png?resize=800%2C537&ssl=1
|
||||
[25]: https://itsfoss.com/best-kali-linux-tools/
|
@ -0,0 +1,103 @@
|
||||
[#]: subject: "Raspberry Pi Zero vs Zero W: What’s the Difference?"
|
||||
[#]: via: "https://itsfoss.com/raspberry-pi-zero-vs-zero-w/"
|
||||
[#]: author: "Ankush Das https://itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "anine09"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
树莓派 Zero 与 Zero W:多方位对比
|
||||
======
|
||||
|
||||
|
||||
|
||||
树莓派十年前凭借 25 美元的迷你电脑掀起了一场革命。在这段时间里,树莓派发布了许多分支系列。也将一些为特定目的而设计的模块进行了一些升级。
|
||||
|
||||
在所有的树莓派模块中,Pi Zero 和 Pi Zero W 是旨在为小规模项目和 IoT 项目设计的最便宜的模块。这两种设备几乎是相同的,但是它们之间有一些微妙而重要的区别。
|
||||
|
||||
|
||||
**那么,树莓派 Zero 和 Zero W 之间的区别是什么?Zero W 中的 W 代表的是无线(Wireless),它表示的是 Zero W 模块拥有无线功能。这是这两个相似模块之间的最大差异**
|
||||
|
||||
让我们更详细地看看其他细节吧。
|
||||
|
||||
### Pi Zero 与 Pi Zero W 之间的主要不同点
|
||||
![][1]
|
||||
|
||||
虽然 树莓派 Zero 是以在只有 A+ 板一半的大小上提供尽可能多的功能为目标。
|
||||
|
||||
而且,树莓派 Zero W 在不需要任何附加的组件和模块的情况下就可以使用蓝牙和 Wifi。
|
||||
|
||||
这是两者之间的区别,其他的部分都是相同的。
|
||||
|
||||
所以,如果你需要以下功能:
|
||||
|
||||
* 802.11 b/g/n 无线网口
|
||||
* 蓝牙 4.1
|
||||
* 低功耗的蓝牙模块(BLE:Bluetooth Low Energy)
|
||||
|
||||
树莓派 Zero W 将是你的不二之选。
|
||||
|
||||
此外,树莓派 Zero W 提供了一种带引脚的版本,叫做 “树莓派 Pi Zero WH”
|
||||
|
||||
### 树莓派 Zero 和 Zero W 的规格
|
||||
|
||||
![Raspberry Pi Zero W][6]
|
||||
|
||||
[树莓派 Zero 和 Zero W 的规格][7]几乎是一样的。
|
||||
|
||||
它们都具有 1 GHz 的单核 CPU 和 512 MB 的 RAM。至于接口方面,一个 mini HDMI 接口,支持 micro USB OTG,micro USB 供电和一个 CSI 摄像头接口(需要插入一个相机模块)。
|
||||
|
||||
这些板子会提供一种叫 [HAT][8](Hardware Attached on Top,顶部附加硬件),兼容 40个引脚,当通常情况下,没有这些引脚你能更容易的使用接口。
|
||||
|
||||
你可以根据自己的功能需要选择使用[各种树莓派兼容的系统][9],但无论哪种情况,我还是推荐你使用 Raspberry Pi OS。
|
||||
|
||||
### 树莓派 Zero 系列值不值得买?
|
||||
|
||||
![Raspberry Pi Zero][10]
|
||||
|
||||
树莓派 Zero 是一种很受人们喜欢的单片机形式,尽管你有很多树莓派 Zero 的替代品,树莓派 Zero 仍然是最推荐的选择。
|
||||
|
||||
当然,除非你有特殊需求。
|
||||
|
||||
In addition to the size of the board, the pricing, power requirement, and processing power are some of the key highlights of this board under **$20**.
|
||||
另外,对于同水平的单片机规模,定价,功率要求,运算能力而言,树莓派 Zero 最亮眼的地方就是它低于 **20 美元**的价格。
|
||||
|
||||
So, if you are looking for the essential features under a budget, the Raspberry Zero series should work for you.
|
||||
因此,如果你正在寻找预算中满足基本功能的单片机,树莓派 Zero 就是专门为你打造的。
|
||||
|
||||
### Is Raspberry Pi Zero series affordable?
|
||||
### 树莓派 Zero 系列价格怎么样?
|
||||
|
||||
Raspberry Pi Zero costs **$5** and the Raspberry Pi Zero W would cost you around **$10**. ****Of course, depending on its availability and region, the cost will differ. If you want the Raspberry Pi Zero W with header pins, it should cost you around **$14**.
|
||||
树莓派 Zero 售价 **5 美元** ,Zero W 售价 **10 美元左右**,当然,在不同的地方,定价规则会不一样,如果你选择树莓派 Zero W 带 引脚的版本,售价大概是 **14 美元**左右。
|
||||
|
||||
There are other devices that can be used as an [alternative to Raspberry Pi Zero][11] and they have similar price tag.
|
||||
还有[其他的设备可以代替树莓派 Zero][11],它们价格也相差不大。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/raspberry-pi-zero-vs-zero-w/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[anine09](https://github.com/anine09)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/raspberry-pi-zero-vs-zero-w.png?resize=800%2C450&ssl=1
|
||||
[2]: https://i1.wp.com/m.media-amazon.com/images/I/517BwcAPmTL._SL160_.jpg?ssl=1
|
||||
[3]: https://www.amazon.com/dp/B072N3X39J?tag=chmod7mediate-20&linkCode=osi&th=1&psc=1 "CanaKit Raspberry Pi Zero W (Wireless) Complete Starter Kit - 16 GB Edition"
|
||||
[4]: https://www.amazon.com/gp/prime/?tag=chmod7mediate-20 "Amazon Prime"
|
||||
[5]: https://www.amazon.com/dp/B072N3X39J?tag=chmod7mediate-20&linkCode=osi&th=1&psc=1 "Buy on Amazon"
|
||||
[6]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/raspberry-pi-zero-w.png?resize=600%2C400&ssl=1
|
||||
[7]: https://itsfoss.com/raspberry-pi-zero-w/
|
||||
[8]: https://github.com/raspberrypi/hats
|
||||
[9]: https://itsfoss.com/raspberry-pi-os/
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/raspberry-pi-zero-1.png?resize=600%2C400&ssl=1
|
||||
[11]: https://itsfoss.com/raspberry-pi-zero-alternatives/
|
||||
[12]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/10/raspberry-pi-zero-w-projects.png?fit=800%2C450&ssl=1
|
||||
[13]: https://itsfoss.com/raspberry-pi-zero-projects/
|
@ -0,0 +1,125 @@
|
||||
[#]: subject: "Screen Recording in Linux With OBS and Wayland"
|
||||
[#]: via: "https://itsfoss.com/screen-record-obs-wayland/"
|
||||
[#]: author: "Abhishek Prakash https://itsfoss.com/author/abhishek/"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
在 Linux 中使用 OBS 和 Wayland 进行屏幕录制
|
||||
======
|
||||
|
||||
有[大量可用于 Linux 的屏幕录像机][1]。但是当涉及到支持 [Wayland][2] 时,几乎所有的都不能用。
|
||||
|
||||
这是个问题,因为许多新发布的版本都再次默认切换到 Wayland 显示管理器。而如果像屏幕录像机这样基本的东西不能工作,就会给人留下不好的体验。
|
||||
|
||||
[GNOME 的内置屏幕录像机][3]可以工作,但它是隐藏的,没有 GUI,也没有办法配置和控制记录内容。还有一个叫 [Kooha][4] 的工具,但它一直在屏幕上显示一个计时器。
|
||||
|
||||
只是为了录制屏幕而[在 Xorg 和 Wayland 之间切换][5],这不是很方便。
|
||||
|
||||
在这一切中,我很高兴地得知,由于 Pipewire 的帮助,在 OBS Studio v27 中支持了 Wayland。但即使是这样,也不是很简单,因此我将向你展示使用 [OBS Studio][6] 在 Wayland 上录制屏幕的步骤。
|
||||
|
||||
### 使用 OBS 在 Wayland 上进行屏幕录制
|
||||
|
||||
![][7]
|
||||
|
||||
让我们来看看它是如何完成的。
|
||||
|
||||
#### 第一步:安装 OBS Studio
|
||||
|
||||
你应该先安装 OBS Studio v27。它已经包含在 Ubuntu 21.10 中,我会在本教程中使用它。
|
||||
|
||||
要在 Ubuntu 18.04、20.04、Linux Mint 20 等系统上安装 OBS Studio 27,请使用[官方的 OBS Studio PPA][8]。
|
||||
|
||||
打开终端,逐一使用以下命令:
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:obsproject/obs-studio
|
||||
sudo apt update
|
||||
sudo apt install obs-studio
|
||||
```
|
||||
|
||||
如果已经安装了 OBS Studio 的旧版本,它将被升级到较新的版本。
|
||||
|
||||
对于 Fedora、Arch 和其他发行版,请检查你的包管理器或非官方仓库以安装最新版本的 OBS Studio。
|
||||
|
||||
#### 第二步:检查 Wayland 捕获是否工作
|
||||
|
||||
请确认你正在使用 Wayland。现在启动 OBS Studio,查看它在第一次运行时显示的所有内容。我不打算展示这些。
|
||||
|
||||
主要步骤是添加 Pipewire 作为屏幕捕捉源。点击 “Sources” 列表下的 “+” 符号。
|
||||
|
||||
![Add screen capture source in OBS Studio][9]
|
||||
|
||||
你有没有看到 “Screen Capture (PipeWire)” 的字样?
|
||||
|
||||
![Do you see PipeWire option in the screen sources?][10]
|
||||
|
||||
**如果答案是否定的,请退出 OBS Studio**。这很正常。至少在 Ubuntu 下,OBS Studio 不会自动切换到使用 Wayland。对此有一个修复方法。
|
||||
|
||||
打开一个终端,使用以下命令:
|
||||
|
||||
```
|
||||
export QT_QPA_PLATFORM=wayland
|
||||
```
|
||||
|
||||
在同一个终端,运行以下命令,启动 OBS Studio:
|
||||
|
||||
```
|
||||
obs
|
||||
```
|
||||
|
||||
它将在终端上显示一些信息。不要理会它们。你的注意力应该放在 OBS Studio GUI 上。再次尝试添加屏幕捕捉。你现在应该看到 PipeWire 选项了。
|
||||
|
||||
![][10]
|
||||
|
||||
你这次用 QT_QPA_PLATFORM 变量明确要求 OBS Studio 使用 Wayland。
|
||||
|
||||
选择 PipeWire 作为源,然后它要求你选择一个显示屏幕。选择它并点击分享按钮。
|
||||
|
||||
![][11]
|
||||
|
||||
现在它应该无限次递归地显示你的屏幕。如果你看到了,你现在就可以开始在 Wayland 中录制屏幕了。
|
||||
|
||||
![][12]
|
||||
|
||||
#### 第三步:让改变成为永久性的
|
||||
|
||||
这很好。你刚刚验证了你可以在 Wayland 上录制屏幕。但每次设置环境变量并从终端启动 OBS 并不方便。
|
||||
|
||||
你可以做的是**把这个变量导出到你的 ~/.bash_profile(对你而言)或 /etc/profile(对系统中的所有用户而言)。**
|
||||
|
||||
```
|
||||
export QT_QPA_PLATFORM=wayland
|
||||
```
|
||||
|
||||
退出并重新登录。现在 OBS 会自动开始使用这个参数,你可以用它来录制 Wayland 的屏幕。
|
||||
|
||||
我希望这个快速技巧对你有帮助。如果你还有问题或建议,请在评论区告诉我。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/screen-record-obs-wayland/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/best-linux-screen-recorders/
|
||||
[2]: https://wayland.freedesktop.org/
|
||||
[3]: https://itsfoss.com/gnome-screen-recorder/
|
||||
[4]: https://itsfoss.com/kooha-screen-recorder/
|
||||
[5]: https://itsfoss.com/switch-xorg-wayland/
|
||||
[6]: https://obsproject.com/
|
||||
[7]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/obs-screen-record-wayland.webp?resize=800%2C450&ssl=1
|
||||
[8]: https://launchpad.net/~obsproject/+archive/ubuntu/obs-studio
|
||||
[9]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/09/obs-studio-add-screen-capture-source.png?resize=800%2C537&ssl=1
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/09/obs-studio-wayland-support.png?resize=800%2C538&ssl=1
|
||||
[11]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/09/obs-studio-screen.png?resize=800%2C578&ssl=1
|
||||
[12]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/09/start-screen-recording-obs-wayland.jpg?resize=800%2C537&ssl=1
|
Loading…
Reference in New Issue
Block a user