2018年7月

大多数教育机构仍在使用 Microsoft 字体, 我不清楚其他国家是什么情况。但在泰米尔纳德邦(印度的一个州), Times New RomanArial 字体主要被用于大学和学校的几乎所有文档工作、项目和作业。不仅是教育机构,而且一些小型组织、办公室和商店仍在使用 MS Windows 字体。以防万一,如果你需要在 Ubuntu 桌面版上使用 Microsoft 字体,请按照以下步骤安装。

免责声明: Microsoft 已免费发布其核心字体。 但请注意 Microsoft 字体是禁止使用在其他操作系统中。在任何 Linux 操作系统中安装 MS 字体之前请仔细阅读 EULA 。我们不负责这种任何种类的盗版行为。

(LCTT 译注:本文只做技术探讨,并不代表作者、译者和本站鼓励任何行为。)

在 Ubuntu 18.04 LTS 桌面版上安装 MS 字体

如下所示安装 MS TrueType 字体:

$ sudo apt update
$ sudo apt install ttf-mscorefonts-installer

然后将会出现 Microsoft 的最终用户协议向导,点击 OK 以继续。

点击 Yes 已接受 Microsoft 的协议:

安装字体之后, 我们需要使用命令行来更新字体缓存:

$ sudo fc-cache -f -v

示例输出:

/usr/share/fonts: caching, new cache contents: 0 fonts, 6 dirs
/usr/share/fonts/X11: caching, new cache contents: 0 fonts, 4 dirs
/usr/share/fonts/X11/Type1: caching, new cache contents: 8 fonts, 0 dirs
/usr/share/fonts/X11/encodings: caching, new cache contents: 0 fonts, 1 dirs
/usr/share/fonts/X11/encodings/large: caching, new cache contents: 0 fonts, 0 dirs
/usr/share/fonts/X11/misc: caching, new cache contents: 89 fonts, 0 dirs
/usr/share/fonts/X11/util: caching, new cache contents: 0 fonts, 0 dirs
/usr/share/fonts/cMap: caching, new cache contents: 0 fonts, 0 dirs
/usr/share/fonts/cmap: caching, new cache contents: 0 fonts, 5 dirs
/usr/share/fonts/cmap/adobe-cns1: caching, new cache contents: 0 fonts, 0 dirs
/usr/share/fonts/cmap/adobe-gb1: caching, new cache contents: 0 fonts, 0 dirs
/usr/share/fonts/cmap/adobe-japan1: caching, new cache contents: 0 fonts, 0 dirs
/usr/share/fonts/cmap/adobe-japan2: caching, new cache contents: 0 fonts, 0 dirs
/usr/share/fonts/cmap/adobe-korea1: caching, new cache contents: 0 fonts, 0 dirs
/usr/share/fonts/opentype: caching, new cache contents: 0 fonts, 2 dirs
/usr/share/fonts/opentype/malayalam: caching, new cache contents: 3 fonts, 0 dirs
/usr/share/fonts/opentype/noto: caching, new cache contents: 24 fonts, 0 dirs
/usr/share/fonts/truetype: caching, new cache contents: 0 fonts, 46 dirs
/usr/share/fonts/truetype/Gargi: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/Gubbi: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/Nakula: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/Navilu: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/Sahadeva: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/Sarai: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/abyssinica: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/dejavu: caching, new cache contents: 6 fonts, 0 dirs
/usr/share/fonts/truetype/droid: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/fonts-beng-extra: caching, new cache contents: 6 fonts, 0 dirs
/usr/share/fonts/truetype/fonts-deva-extra: caching, new cache contents: 3 fonts, 0 dirs
/usr/share/fonts/truetype/fonts-gujr-extra: caching, new cache contents: 5 fonts, 0 dirs
/usr/share/fonts/truetype/fonts-guru-extra: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/fonts-kalapi: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/fonts-orya-extra: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/fonts-telu-extra: caching, new cache contents: 2 fonts, 0 dirs
/usr/share/fonts/truetype/freefont: caching, new cache contents: 12 fonts, 0 dirs
/usr/share/fonts/truetype/kacst: caching, new cache contents: 15 fonts, 0 dirs
/usr/share/fonts/truetype/kacst-one: caching, new cache contents: 2 fonts, 0 dirs
/usr/share/fonts/truetype/lao: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/liberation: caching, new cache contents: 16 fonts, 0 dirs
/usr/share/fonts/truetype/liberation2: caching, new cache contents: 12 fonts, 0 dirs
/usr/share/fonts/truetype/lohit-assamese: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/lohit-bengali: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/lohit-devanagari: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/lohit-gujarati: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/lohit-kannada: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/lohit-malayalam: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/lohit-oriya: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/lohit-punjabi: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/lohit-tamil: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/lohit-tamil-classical: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/lohit-telugu: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/malayalam: caching, new cache contents: 11 fonts, 0 dirs
/usr/share/fonts/truetype/msttcorefonts: caching, new cache contents: 60 fonts, 0 dirs
/usr/share/fonts/truetype/noto: caching, new cache contents: 2 fonts, 0 dirs
/usr/share/fonts/truetype/openoffice: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/padauk: caching, new cache contents: 4 fonts, 0 dirs
/usr/share/fonts/truetype/pagul: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/samyak: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/samyak-fonts: caching, new cache contents: 3 fonts, 0 dirs
/usr/share/fonts/truetype/sinhala: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/tibetan-machine: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/fonts/truetype/tlwg: caching, new cache contents: 58 fonts, 0 dirs
/usr/share/fonts/truetype/ttf-khmeros-core: caching, new cache contents: 2 fonts, 0 dirs
/usr/share/fonts/truetype/ubuntu: caching, new cache contents: 13 fonts, 0 dirs
/usr/share/fonts/type1: caching, new cache contents: 0 fonts, 1 dirs
/usr/share/fonts/type1/gsfonts: caching, new cache contents: 35 fonts, 0 dirs
/usr/local/share/fonts: caching, new cache contents: 0 fonts, 0 dirs
/home/sk/.local/share/fonts: skipping, no such directory
/home/sk/.fonts: skipping, no such directory
/var/cache/fontconfig: cleaning cache directory
/home/sk/.cache/fontconfig: cleaning cache directory
/home/sk/.fontconfig: not cleaning non-existent cache directory
fc-cache: succeeded

在 Linux 和 Windows 双启动的机器上安装 MS 字体

如果你有 Linux 和 Windows 的双启动系统,你可以轻松地从 Windows C 驱动器上安装 MS 字体。 你所要做的就是挂载 Windows 分区(C:/windows)。

我假设你已经在 Linux 中将 C:\Windows 分区挂载在了 /Windowsdrive 目录下。

现在,将字体位置链接到你的 Linux 系统的字体文件夹,如下所示:

ln -s /Windowsdrive/Windows/Fonts /usr/share/fonts/WindowsFonts

链接字体文件之后,使用命令行重新生成 fontconfig 缓存:

fc-cache

或者,将所有的 Windows 字体复制到 /usr/share/fonts 目录下并使用一下命令安装字体:

mkdir /usr/share/fonts/WindowsFonts
cp /Windowsdrive/Windows/Fonts/* /usr/share/fonts/WindowsFonts
chmod 755 /usr/share/fonts/WindowsFonts/*

最后,使用命令行重新生成 fontconfig 缓存:

fc-cache

测试 Windows 字体

安装 MS 字体后打开 LibreOffice 或 GIMP。 现在,你将会看到 Microsoft coretype 字体。

就是这样, 希望这本指南有用。我再次警告你,在其他操作系统中使用 MS 字体是被禁止的。在安装 MS 字体之前请先阅读 Microsoft 许可协议。

如果你觉得我们的指南有用,请在你的社区、专业网络上分享并支持我们。还有更多好东西在等着我们。持续访问!

庆祝吧!!


via: https://www.ostechnix.com/install-microsoft-windows-fonts-ubuntu-16-04/

作者:SK 选题:lujun9972 译者:Auk7F7 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

用这里列出的方便的工具来跟踪你的磁盘利用率。

跟踪磁盘利用率信息是系统管理员(和其他人)的日常待办事项列表之一。Linux 有一些内置的使用程序来帮助提供这些信息。

df

df 命令意思是 “disk-free”,显示 Linux 系统上可用和已使用的磁盘空间。

df -h 以人类可读的格式显示磁盘空间。

df -a 显示文件系统的完整磁盘使用情况,即使 Available(可用) 字段为 0。

df -T 显示磁盘使用情况以及每个块的文件系统类型(例如,xfs、ext2、ext3、btrfs 等)。

df -i 显示已使用和未使用的 inode。

du

du 显示文件,目录等的磁盘使用情况,默认情况下以 kb 为单位显示。

du -h 以人类可读的方式显示所有目录和子目录的磁盘使用情况。

du -a 显示所有文件的磁盘使用情况。

du -s 提供特定文件或目录使用的总磁盘空间。

ls -al

ls -al 列出了特定目录的全部内容及大小。

stat

stat <文件/目录>显示文件/目录或文件系统的大小和其他统计信息。

fdisk -l

fdisk -l 显示磁盘大小以及磁盘分区信息。

这些是用于检查 Linux 文件空间的大多数内置实用程序。有许多类似的工具,如 Disks(GUI 工具),Ncdu 等,它们也显示磁盘空间的利用率。你有你最喜欢的工具而它不在这个列表上吗?请在评论中分享。


via: https://opensource.com/article/18/7/how-check-free-disk-space-linux

作者:Archit Modi 选题:lujun9972 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在本文中,我们的目的是让你了解如何设置属于自己的Git服务器。

Git 是由 Linux Torvalds 开发的一个版本控制系统,现如今正在被全世界大量开发者使用。许多公司喜欢使用基于 Git 版本控制的 GitHub 代码托管。根据报道,GitHub 是现如今全世界最大的代码托管网站。GitHub 宣称已经有 920 万用户和 2180 万个仓库。许多大型公司现如今也将代码迁移到 GitHub 上。甚至于谷歌,一家搜索引擎公司,也正将代码迁移到 GitHub 上

运行你自己的 Git 服务器

GitHub 能提供极佳的服务,但却有一些限制,尤其是你是单人或是一名 coding 爱好者。GitHub 其中之一的限制就是其中免费的服务没有提供代码私有托管业务。你不得不支付每月 7 美金购买 5 个私有仓库,并且想要更多的私有仓库则要交更多的钱。

万一你想要私有仓库或需要更多权限控制,最好的方法就是在你的服务器上运行 Git。不仅你能够省去一笔钱,你还能够在你的服务器有更多的操作。在大多数情况下,大多数高级 Linux 用户已经拥有自己的服务器,并且在这些服务器上方式 Git 就像“啤酒一样免费”(LCTT 译注:指免费软件)。

在这篇教程中,我们主要讲在你的服务器上,使用两种代码管理的方法。一种是运行一个纯 Git 服务器,另一个是使用名为 GitLab 的 GUI 工具。在本教程中,我在 VPS 上运行的操作系统是 Ubuntu 14.04 LTS。

在你的服务器上安装 Git

在本篇教程中,我们考虑一个简单案例,我们有一个远程服务器和一台本地服务器,现在我们需要使用这两台机器来工作。为了简单起见,我们就分别叫它们为远程服务器和本地服务器。

首先,在两边的机器上安装 Git。你可以从依赖包中安装 Git,在本文中,我们将使用更简单的方法:

sudo apt-get install git-core

为 Git 创建一个用户。

sudo useradd git
passwd git

为了容易的访问服务器,我们设置一个免密 ssh 登录。首先在你本地电脑上创建一个 ssh 密钥:

ssh-keygen -t rsa

这时会要求你输入保存密钥的路径,这时只需要点击回车保存在默认路径。第二个问题是输入访问远程服务器所需的密码。它生成两个密钥——公钥和私钥。记下您在下一步中需要使用的公钥的位置。

现在您必须将这些密钥复制到服务器上,以便两台机器可以相互通信。在本地机器上运行以下命令:

cat ~/.ssh/id_rsa.pub | ssh git@remote-server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

现在,用 ssh 登录进服务器并为 Git 创建一个项目路径。你可以为你的仓库设置一个你想要的目录。

现在跳转到该目录中:

cd /home/swapnil/project-1.git

现在新建一个空仓库:

git init --bare
Initialized empty Git repository in /home/swapnil/project-1.git

现在我们需要在本地机器上新建一个基于 Git 版本控制仓库:

mkdir -p /home/swapnil/git/project

进入我们创建仓库的目录:

cd /home/swapnil/git/project

现在在该目录中创建项目所需的文件。留在这个目录并启动 git

git init
Initialized empty Git repository in /home/swapnil/git/project

把所有文件添加到仓库中:

git add .

现在,每次添加文件或进行更改时,都必须运行上面的 add 命令。 您还需要为每个文件更改都写入提交消息。提交消息基本上说明了我们所做的更改。

git commit -m "message" -a
[master (root-commit) 57331ee] message
 2 files changed, 2 insertions(+)
 create mode 100644 GoT.txt
 create mode 100644 writing.txt

在这种情况下,我有一个名为 GoT(《权力的游戏》的点评)的文件,并且我做了一些更改,所以当我运行命令时,它指定对文件进行更改。 在上面的命令中 -a 选项意味着提交仓库中的所有文件。 如果您只更改了一个,则可以指定该文件的名称而不是使用 -a

举一个例子:

git commit -m "message" GoT.txt
[master e517b10] message
 1 file changed, 1 insertion(+)

到现在为止,我们一直在本地服务器上工作。现在我们必须将这些更改推送到远程服务器上,以便通过互联网访问,并且可以与其他团队成员进行协作。

git remote add origin ssh://git@remote-server/repo-<wbr< a="">>path-on-server..git

现在,您可以使用 pullpush 选项在服务器和本地计算机之间推送或拉取:

git push origin master

如果有其他团队成员想要使用该项目,则需要将远程服务器上的仓库克隆到其本地计算机上:

git clone git@remote-server:/home/swapnil/project.git

这里 /home/swapnil/project.git 是远程服务器上的项目路径,在你本机上则会改变。

然后进入本地计算机上的目录(使用服务器上的项目名称):

cd /project

现在他们可以编辑文件,写入提交更改信息,然后将它们推送到服务器:

git commit -m 'corrections in GoT.txt story' -a

然后推送改变:

git push origin master

我认为这足以让一个新用户开始在他们自己的服务器上使用 Git。 如果您正在寻找一些 GUI 工具来管理本地计算机上的更改,则可以使用 GUI 工具,例如 QGit 或 GitK for Linux。

使用 GitLab

这是项目所有者和协作者的纯命令行解决方案。这当然不像使用 GitHub 那么简单。不幸的是,尽管 GitHub 是全球最大的代码托管商,但是它自己的软件别人却无法使用。因为它不是开源的,所以你不能获取源代码并编译你自己的 GitHub。这与 WordPress 或 Drupal 不同,您无法下载 GitHub 并在您自己的服务器上运行它。

像往常一样,在开源世界中,是没有终结的尽头。GitLab 是一个非常优秀的项目。这是一个开源项目,允许用户在自己的服务器上运行类似于 GitHub 的项目管理系统。

您可以使用 GitLab 为团队成员或公司运行类似于 GitHub 的服务。您可以使用 GitLab 在公开发布之前开发私有项目。

GitLab 采用传统的开源商业模式。他们有两种产品:免费的开源软件,用户可以在自己的服务器上安装,以及类似于 GitHub 的托管服务。

可下载版本有两个版本,免费的社区版和付费企业版。企业版基于社区版,但附带针对企业客户的其他功能。它或多或少与 WordPress.org 或 Wordpress.com 提供的服务类似。

社区版具有高度可扩展性,可以在单个服务器或群集上支持 25000 个用户。GitLab 的一些功能包括:Git 仓库管理,代码评论,问题跟踪,活动源和维基。它配备了 GitLab CI,用于持续集成和交付。

Digital Ocean 等许多 VPS 提供商会为用户提供 GitLab 服务。 如果你想在你自己的服务器上运行它,你可以手动安装它。GitLab 为不同的操作系统提供了软件包。 在我们安装 GitLab 之前,您可能需要配置 SMTP 电子邮件服务器,以便 GitLab 可以在需要时随时推送电子邮件。官方推荐使用 Postfix。所以,先在你的服务器上安装 Postfix:

sudo apt-get install postfix

在安装 Postfix 期间,它会问你一些问题,不要跳过它们。 如果你一不小心跳过,你可以使用这个命令来重新配置它:

sudo dpkg-reconfigure postfix

运行此命令时,请选择 “Internet Site”并为使用 Gitlab 的域名提供电子邮件 ID。

我是这样输入的:

[email protected]

用 Tab 键并为 postfix 创建一个用户名。接下来将会要求你输入一个目标邮箱。

在剩下的步骤中,都选择默认选项。当我们安装且配置完成后,我们继续安装 GitLab。

我们使用 wget 来下载软件包(用 最新包 替换下载链接):

wget https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.9.4-omnibus.1-1_amd64.deb

然后安装这个包:

sudo dpkg -i gitlab_7.9.4-omnibus.1-1_amd64.deb

现在是时候配置并启动 GitLab 了。

sudo gitlab-ctl reconfigure

您现在需要在配置文件中配置域名,以便您可以访问 GitLab。打开文件。

nano /etc/gitlab/gitlab.rb

在这个文件中编辑 external_url 并输入服务器域名。保存文件,然后从 Web 浏览器中打开新建的一个 GitLab 站点。

默认情况下,它会以系统管理员的身份创建 root,并使用 5iveL!fe 作为密码。 登录到 GitLab 站点,然后更改密码。

密码更改后,登录该网站并开始管理您的项目。

GitLab 有很多选项和功能。最后,我借用电影“黑客帝国”中的经典台词:“不幸的是,没有人知道 GitLab 可以做什么。你必须亲自尝试一下。”


via: https://www.linux.com/learn/how-run-your-own-git-server

作者:Swapnil Bhartiya 选题:lujun9972 译者:wyxplus 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

用 Perlbrew 在你系统上安装多个版本的 Perl。

有比在系统上安装了 Perl 更好的事情吗?那就是在系统中安装了多个版本的 Perl。使用 Perlbrew 你可以做到这一点。但是为什么呢,除了让你包围在 Perl 下之外,有什么好处吗?

简短的回答是,不同版本的 Perl 是......不同的。程序 A 可能依赖于较新版本中不推荐使用的行为,而程序 B 需要去年无法使用的新功能。如果你安装了多个版本的 Perl,则每个脚本都可以使用最适合它的版本。如果您是开发人员,这也会派上用场,你可以针对多个版本的 Perl 测试你的程序,这样无论你的用户运行什么,你都知道它能否工作。

安装 Perlbrew

另一个好处是 Perlbrew 会安装 Perl 到用户的家目录。这意味着每个用户都可以管理他们的 Perl 版本(以及相关的 CPAN 包),而无需与系统管理员联系。自助服务意味着为用户提供更快的安装,并为系统管理员提供更多时间来解决难题。

第一步是在你的系统上安装 Perlbrew。许多 Linux 发行版已经在包仓库中拥有它,因此你只需要 dnf install perlbrew(或者适用于你的发行版的命令)。你还可以使用 cpan App::perlbrew 从 CPAN 安装 App::perlbrew 模块。或者你可以在 install.perlbrew.pl 下载并运行安装脚本。

要开始使用 Perlbrew,请运行 perlbrew init

安装新的 Perl 版本

假设你想尝试最新的开发版本(撰写本文时为 5.27.11)。首先,你需要安装包:

perlbrew install 5.27.11

切换 Perl 版本

现在你已经安装了新版本,你可以将它用于该 shell:

perlbrew use 5.27.11

或者你可以将其设置为你帐户的默认 Perl 版本(假设你按照 perlbrew init 的输出设置了你的配置文件):

perlbrew switch 5.27.11

运行单个脚本

你也可以用特定版本的 Perl 运行单个命令:

perlberew exec 5.27.11 myscript.pl

或者,你可以针对所有已安装的版本运行命令。如果你想针对各种版本运行测试,这尤其方便。在这种情况下,请指定版本为 perl

plperlbrew exec perl myscriptpl

安装 CPAN 模块

如果你想安装 CPAN 模块,cpanm 包是一个易于使用的界面,可以很好地与 Perlbrew 一起使用。用下面命令安装它:

perlbrew install-cpanm

然后,你可以使用 cpanm 命令安装 CPAN 模块:

cpanm CGI::simple

但是等下,还有更多!

本文介绍了基本的 Perlbrew 用法。还有更多功能和选项可供选择。从查看 perlbrew help 的输出开始,或查看App::perlbrew 文档。你还喜欢 Perlbrew 的其他什么功能?让我们在评论中知道。


via: https://opensource.com/article/18/7/perlbrew

作者:Ben Cotton 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

3 个可以使你的 Python 代码更优雅、可读、直观和易于维护的工具。

Python 提供了一组独特的工具和语言特性来使你的代码更加优雅、可读和直观。为正确的问题选择合适的工具,你的代码将更易于维护。在本文中,我们将研究其中的三个工具:魔术方法、迭代器和生成器,以及方法魔术。

魔术方法

魔术方法可以看作是 Python 的管道。它们被称为“底层”方法,用于某些内置的方法、符号和操作。你可能熟悉的常见魔术方法是 __init__(),当我们想要初始化一个类的新实例时,它会被调用。

你可能已经看过其他常见的魔术方法,如 __str____repr__。Python 中有一整套魔术方法,通过实现其中的一些方法,我们可以修改一个对象的行为,甚至使其行为类似于内置数据类型,例如数字、列表或字典。

让我们创建一个 Money 类来示例:

class Money:

    currency_rates = {
        '$': 1,
        '€': 0.88,
    }

    def __init__(self, symbol, amount):
        self.symbol = symbol
        self.amount = amount

    def __repr__(self):
        return '%s%.2f' % (self.symbol, self.amount)

    def convert(self, other):
        """ Convert other amount to our currency """
        new_amount = (
            other.amount / self.currency_rates[other.symbol]
            * self.currency_rates[self.symbol])

        return Money(self.symbol, new_amount)

该类定义为给定的货币符号和汇率定义了一个货币汇率,指定了一个初始化器(也称为构造函数),并实现 __repr__,因此当我们打印这个类时,我们会看到一个友好的表示,例如 $2.00 ,这是一个带有货币符号和金额的 Money('$', 2.00) 实例。最重要的是,它定义了一种方法,允许你使用不同的汇率在不同的货币之间进行转换。

打开 Python shell,假设我们已经定义了使用两种不同货币的食品的成本,如下所示:

>>> soda_cost = Money('$', 5.25)
>>> soda_cost
    $5.25

>>> pizza_cost = Money('€', 7.99)
>>> pizza_cost
    €7.99

我们可以使用魔术方法使得这个类的实例之间可以相互交互。假设我们希望能够将这个类的两个实例一起加在一起,即使它们是不同的货币。为了实现这一点,我们可以在 Money 类上实现 __add__ 这个魔术方法:

class Money:

    # ... previously defined methods ...

    def __add__(self, other):
        """ Add 2 Money instances using '+' """
        new_amount = self.amount + self.convert(other).amount
        return Money(self.symbol, new_amount)

现在我们可以以非常直观的方式使用这个类:

>>> soda_cost = Money('$', 5.25)
>>> pizza_cost = Money('€', 7.99)
>>> soda_cost + pizza_cost
    $14.33
>>> pizza_cost + soda_cost
    €12.61

当我们将两个实例加在一起时,我们得到以第一个定义的货币符号所表示的结果。所有的转换都是在底层无缝完成的。如果我们想的话,我们也可以为减法实现 __sub__,为乘法实现 __mul__ 等等。阅读模拟数字类型魔术方法指南来获得更多信息。

我们学习到 __add__ 映射到内置运算符 +。其他魔术方法可以映射到像 [] 这样的符号。例如,在字典中通过索引或键来获得一项,其实是使用了 __getitem__ 方法:

>>> d = {'one': 1, 'two': 2}
>>> d['two']
2
>>> d.__getitem__('two')
2

一些魔术方法甚至映射到内置函数,例如 __len__() 映射到 len()

class Alphabet:
    letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

    def __len__(self):
        return len(self.letters)

>>> my_alphabet = Alphabet()
>>> len(my_alphabet)
    26

自定义迭代器

对于新的和经验丰富的 Python 开发者来说,自定义迭代器是一个非常强大的但令人迷惑的主题。

许多内置类型,例如列表、集合和字典,已经实现了允许它们在底层迭代的协议。这使我们可以轻松地遍历它们。

>>> for food in ['Pizza', 'Fries']:

         print(food + '. Yum!')

Pizza. Yum!
Fries. Yum!

我们如何迭代我们自己的自定义类?首先,让我们来澄清一些术语。

  • 要成为一个可迭代对象,一个类需要实现 __iter__()
  • __iter__() 方法需要返回一个迭代器
  • 要成为一个迭代器,一个类需要实现 __next__()(或在 Python 2中是 next()),当没有更多的项要迭代时,必须抛出一个 StopIteration 异常。

呼!这听起来很复杂,但是一旦你记住了这些基本概念,你就可以在任何时候进行迭代。

我们什么时候想使用自定义迭代器?让我们想象一个场景,我们有一个 Server 实例在不同的端口上运行不同的服务,如 httpssh。其中一些服务处于 active 状态,而其他服务则处于 inactive 状态。

class Server:

    services = [
        {'active': False, 'protocol': 'ftp', 'port': 21},
        {'active': True, 'protocol': 'ssh', 'port': 22},
        {'active': True, 'protocol': 'http', 'port': 80},
    ]

当我们遍历 Server 实例时,我们只想遍历那些处于 active 的服务。让我们创建一个 IterableServer 类:

class IterableServer:
    def __init__(self):
        self.current_pos = 0
    def __next__(self):
        pass  # TODO: 实现并记得抛出 StopIteration

首先,我们将当前位置初始化为 0。然后,我们定义一个 __next__() 方法来返回下一项。我们还将确保在没有更多项返回时抛出 StopIteration。到目前为止都很好!现在,让我们实现这个 __next__() 方法。

class IterableServer:
    def __init__(self):
        self.current_pos = 0.  # 我们初始化当前位置为 0
    def __iter__(self):  # 我们可以在这里返回 self,因为实现了 __next__
        return self
    def __next__(self):
        while self.current_pos < len(self.services):
            service = self.services[self.current_pos]
            self.current_pos += 1
            if service['active']:
                return service['protocol'], service['port']
        raise StopIteration
    next = __next__  # 可选的 Python2 兼容性

我们对列表中的服务进行遍历,而当前的位置小于服务的个数,但只有在服务处于活动状态时才返回。一旦我们遍历完服务,就会抛出一个 StopIteration 异常。

因为我们实现了 __next__() 方法,当它耗尽时,它会抛出 StopIteration。我们可以从 __iter__() 返回 self,因为 IterableServer 类遵循 iterable 协议。

现在我们可以遍历一个 IterableServer 实例,这将允许我们查看每个处于活动的服务,如下所示:

>>> for protocol, port in IterableServer():

        print('service %s is running on port %d' % (protocol, port))

service ssh is running on port 22

service http is running on port 21

太棒了,但我们可以做得更好!在这样类似的实例中,我们的迭代器不需要维护大量的状态,我们可以简化代码并使用 generator(生成器) 来代替。

class Server:
    services = [
        {'active': False, 'protocol': 'ftp', 'port': 21},
        {'active': True, 'protocol': 'ssh', 'port': 22},
        {'active': True, 'protocol': 'http', 'port': 21},
    ]
    def __iter__(self):
        for service in self.services:
            if service['active']:
                yield service['protocol'], service['port']

yield 关键字到底是什么?在定义生成器函数时使用 yield。这有点像 return,虽然 return 在返回值后退出函数,但 yield 会暂停执行直到下次调用它。这允许你的生成器的功能在它恢复之前保持状态。查看 yield 的文档以了解更多信息。使用生成器,我们不必通过记住我们的位置来手动维护状态。生成器只知道两件事:它现在需要做什么以及计算下一个项目需要做什么。一旦我们到达执行点,即 yield 不再被调用,我们就知道停止迭代。

这是因为一些内置的 Python 魔法。在 Python 关于 __iter__() 的文档中我们可以看到,如果 __iter__() 是作为一个生成器实现的,它将自动返回一个迭代器对象,该对象提供 __iter__()__next__() 方法。阅读这篇很棒的文章,深入了解迭代器,可迭代对象和生成器

方法魔法

由于其独特的方面,Python 提供了一些有趣的方法魔法作为语言的一部分。

其中一个例子是别名功能。因为函数只是对象,所以我们可以将它们赋值给多个变量。例如:

>>> def foo():
       return 'foo'
>>> foo()
'foo'
>>> bar = foo
>>> bar()
'foo'

我们稍后会看到它的作用。

Python 提供了一个方便的内置函数称为 getattr(),它接受 object, name, default 参数并在 object 上返回属性 name。这种编程方式允许我们访问实例变量和方法。例如:

>>> class Dog:
        sound = 'Bark'
        def speak(self):
            print(self.sound + '!', self.sound + '!')

>>> fido = Dog()

>>> fido.sound
'Bark'
>>> getattr(fido, 'sound')
'Bark'

>>> fido.speak
<bound method Dog.speak of <__main__.Dog object at 0x102db8828>>
>>> getattr(fido, 'speak')
<bound method Dog.speak of <__main__.Dog object at 0x102db8828>>


>>> fido.speak()
Bark! Bark!
>>> speak_method = getattr(fido, 'speak')
>>> speak_method()
Bark! Bark!

这是一个很酷的技巧,但是我们如何在实际中使用 getattr 呢?让我们看一个例子,我们编写一个小型命令行工具来动态处理命令。

class Operations:
    def say_hi(self, name):
        print('Hello,', name)
    def say_bye(self, name):
        print ('Goodbye,', name)
    def default(self, arg):
        print ('This operation is not supported.')

if __name__ == '__main__':
    operations = Operations()
    # 假设我们做了错误处理
    command, argument = input('> ').split()
    func_to_call = getattr(operations, command, operations.default)
    func_to_call(argument)

脚本的输出是:

$ python getattr.py
> say_hi Nina
Hello, Nina
> blah blah
This operation is not supported.

接下来,我们来看看 partial。例如,functool.partial(func, *args, **kwargs) 允许你返回一个新的 partial 对象,它的行为类似 func,参数是 argskwargs。如果传入更多的 args,它们会被附加到 args。如果传入更多的 kwargs,它们会扩展并覆盖 kwargs。让我们通过一个简短的例子来看看:

>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo
<functools.partial object at 0x1085a09f0>
>>> basetwo('10010')
18

# 这等同于
>>> int('10010', base=2)

让我们看看在我喜欢的一个名为 agithub 的库中的一些示例代码中,这个方法魔术是如何结合在一起的,这是一个(名字起得很 low 的) REST API 客户端,它具有透明的语法,允许你以最小的配置快速构建任何 REST API 原型(不仅仅是 GitHub)。我发现这个项目很有趣,因为它非常强大,但只有大约 400 行 Python 代码。你可以在大约 30 行配置代码中添加对任何 REST API 的支持。agithub 知道协议所需的一切(RESTHTTPTCP),但它不考虑上游 API。让我们深入到它的实现中。

以下是我们如何为 GitHub API 和任何其他相关连接属性定义端点 URL 的简化版本。在这里查看完整代码

class GitHub(API):
    def __init__(self, token=None, *args, **kwargs):
        props = ConnectionProperties(api_url = kwargs.pop('api_url', 'api.github.com'))
        self.setClient(Client(*args, **kwargs))
        self.setConnectionProperties(props)

然后,一旦配置了访问令牌,就可以开始使用 GitHub API

>>> gh = GitHub('token')
>>> status, data = gh.user.repos.get(visibility='public', sort='created')
>>> # ^ 映射到 GET /user/repos
>>> data
... ['tweeter', 'snipey', '...']

请注意,你要确保 URL 拼写正确,因为我们没有验证 URL。如果 URL 不存在或出现了其他任何错误,将返回 API 抛出的错误。那么,这一切是如何运作的呢?让我们找出答案。首先,我们将查看一个 API的简化示例:

class API:
    # ... other methods ...
    def __getattr__(self, key):
        return IncompleteRequest(self.client).__getattr__(key)
    __getitem__ = __getattr__

API 类上的每次调用都会调用 IncompleteRequest作为指定的 key

class IncompleteRequest:
    # ... other methods ...
    def __getattr__(self, key):
        if key in self.client.http_methods:
            htmlMethod = getattr(self.client, key)
            return partial(htmlMethod, url=self.url)
        else:
            self.url += '/' + str(key)
            return self
    __getitem__ = __getattr__

class Client:
    http_methods = ('get')  # 还有 post, put, patch 等等。
    def get(self, url, headers={}, **params):
        return self.request('GET', url, None, headers)

如果最后一次调用不是 HTTP 方法(如 getpost 等),则返回带有附加路径的 IncompleteRequest。否则,它从Client获取 HTTP 方法对应的正确函数,并返回 partial

如果我们给出一个不存在的路径会发生什么?

>>> status, data = this.path.doesnt.exist.get()
>>> status
... 404

因为 __getattr__ 别名为 __getitem__

>>> owner, repo = 'nnja', 'tweeter'
>>> status, data = gh.repos[owner][repo].pulls.get()
>>> # ^ Maps to GET /repos/nnja/tweeter/pulls
>>> data
.... # {....}

这真心是一些方法魔术!

了解更多

Python 提供了大量工具,使你的代码更优雅,更易于阅读和理解。挑战在于找到合适的工具来完成工作,但我希望本文为你的工具箱添加了一些新工具。而且,如果你想更进一步,你可以在我的博客 nnja.io 上阅读有关装饰器、上下文管理器、上下文生成器和命名元组的内容。随着你成为一名更好的 Python 开发人员,我鼓励你到那里阅读一些设计良好的项目的源代码。RequestsFlask 是两个很好的起步的代码库。


via: https://opensource.com/article/18/4/elegant-solutions-everyday-python-problems

作者:Nina Zakharenko 选题:lujun9972 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

开源游戏开发插件运行虚幻引擎的用户使用基于 Web 的编程方式创建独特的用户界面元素。

游戏开发引擎在过去几年中变得越来越易于​​使用。像 Unity 这样一直免费使用的引擎,以及最近从基于订阅的服务切换到免费服务的 虚幻引擎 Unreal Engine ,允许独立开发者使用 AAA 发行商相同达到行业标准的工具。虽然这些引擎都不是开源的,但每个引擎都能够促进其周围的开源生态系统的发展。

这些引擎中可以包含插件以允许开发人员通过添加特定程序来增强引擎的基本功能。这些程序的范围可以从简单的资源包到更复杂的事物,如人工智能 (AI) 集成。这些插件来自不同的创作者。有些是由引擎开发工作室和有些是个人提供的。后者中的很多是开源插件。

什么是 BLUI?

作为独立游戏开发工作室的一员,我体验到了在专有游戏引擎上使用开源插件的好处。Aaron Shea 开发的一个开源插件 BLUI 对我们团队的开发过程起到了重要作用。它允许我们使用基于 Web 的编程(如 HTML/CSS 和 JavaScript)创建用户界面 (UI) 组件。尽管 虚幻引擎 Unreal Engine (我们选择的引擎)有一个实现了类似目的的内置 UI 编辑器,我们也选择使用这个开源插件。我们选择使用开源替代品有三个主要原因:它们的可访问性、易于实现以及伴随的开源程序活跃的、支持性好的在线社区。

在虚幻引擎的最早版本中,我们在游戏中创建 UI 的唯一方法是通过引擎的原生 UI 集成,使用 Autodesk 的 Scaleform 程序,或通过在虚幻社区中传播的一些选定的基于订阅的虚幻引擎集成。在这些情况下,这些解决方案要么不能为独立开发者提供有竞争力的 UI 解决方案,对于小型团队来说太昂贵,要么只能为大型团队和 AAA 开发者提供。

在商业产品和虚幻引擎的原生整合失败后,我们向独立社区寻求解决方案。我们在那里发现了 BLUI。它不仅与虚幻引擎无缝集成,而且还保持了一个强大且活跃的社区,经常推出更新并确保独立开发人员可以轻松访问文档。BLUI 使开发人员能够将 HTML 文件导入虚幻引擎,并在程序内部对其进行编程。这使得通过 web 语言创建的 UI 能够集成到游戏的代码、资源和其他元素中,并拥有所有 HTML、CSS、Javascript 和其他网络语言的能力。它还为开源 Chromium Embedded Framework 提供全面支持。

安装和使用 BLUI

使用 BLUI 的基本过程包括首先通过 HTML 创建 UI。开发人员可以使用任何工具来实现此目的,包括 自举 bootstrapped JavaScript 代码、外部 API 或任何数据库代码。一旦这个 HTML 页面完成,你可以像安装任何虚幻引擎插件那样安装它,并加载或创建一个项目。项目加载后,你可以将 BLUI 函数放在虚幻引擎 UI 图纸中的任何位置,或者通过 C++ 进行硬编码。开发人员可以通过其 HTML 页面调用函数,或使用 BLUI 的内部函数轻松更改变量。

 title=

将 BLUI 集成到虚幻 4 图纸中。

在我们当前的项目中,我们使用 BLUI 将 UI 元素与游戏中的音轨同步,为游戏机制的节奏方面提供视觉反馈。将定制引擎编程与 BLUI 插件集成很容易。

 title=

使用 BLUI 将 UI 元素与音轨同步。

通过 BLUI GitHub 页面上的文档,将 BLUI 集成到虚幻 4 中是一个轻松的过程。还有一个由支持虚幻引擎开发人员组成的论坛,他们乐于询问和回答关于插件以及实现该工具时出现的任何问题。

开源优势

开源插件可以在专有游戏引擎的范围内扩展创意。他们继续降低进入游戏开发的障碍,并且可以产生前所未有的游戏内的机制和资源。随着对专有游戏开发引擎的访问持续增长,开源插件社区将变得更加重要。不断增长的创造力必将超过专有软件,开源代码将会填补这些空白,并促进开发真正独特的游戏。而这种新颖性正是让独立游戏如此美好的原因!


via: https://opensource.com/article/18/6/blui-game-development-plugin

作者:Uwana lkaiddi 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出