Merge remote-tracking branch 'LCTT/master'

This commit is contained in:
Xingyu Wang 2019-08-11 07:26:46 +08:00
commit 8a3af84ff2
14 changed files with 1750 additions and 669 deletions

View File

@ -1,74 +1,69 @@
[#]: collector: (lujun9972)
[#]: translator: (arrowfeng)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-11208-1.html)
[#]: subject: (Understanding software design patterns)
[#]: via: (https://opensource.com/article/19/7/understanding-software-design-patterns)
[#]: author: (Bryant Son https://opensource.com/users/brsonhttps://opensource.com/users/erezhttps://opensource.com/users/brson)
理解软件设计模式
======
设计模式可以帮助消除冗余代码。学习如何利用Java使用单例模式、工厂模式和观察者模式。
![clouds in the sky with blue pattern][1]
> 设计模式可以帮助消除冗余代码。学习如何利用 Java 使用单例模式、工厂模式和观察者模式。
如果你是一名正在致力于计算机科学或者相关学科的程序员或者学生,很快,你将会遇到一条术语 “软件设计模式。” 根据维基百科_" [软件设计模式][2]是在平常的软件设计工作中所遭遇的问题是一种通用的, 可重复使用的解决方案。“_ 这里是我对定义的理解:当你在编码项目上的同时,你经常会思考,“呵呵,这里貌似是冗余代码,我想是否我能改变代码使得更灵活并且这个改变是可接受的?”因此,你将开始思考怎样分割那些保持不变的内容和需要经常改变的内容。
![](https://img.linux.net.cn/data/attachment/album/201908/10/080849ygyqtrw88f2qtzk4.jpg)
如果你是一名正在致力于计算机科学或者相关学科的程序员或者学生,很快,你将会遇到一条术语 “<ruby>软件设计模式<rt>software design pattern</rt></ruby>”。根据维基百科,“*[软件设计模式][2]是在平常的软件设计工作中所遭遇的问题的一种通用的、可重复使用的解决方案*”。我对该定义的理解是:当在从事于一个编码项目时,你经常会思考,“嗯,这里貌似是冗余代码,我觉得是否能改变这些代码使之更灵活和便于修改?”因此,你会开始考虑怎样分割那些保持不变的内容和需要经常改变的内容。
> 设计模式是一种通过分割那些保持不变的部分和经常变化的部分,让你的代码更容易修改的方法。
> **设计模式**是一种通过分割那些保持不变的部分和经常变化的部分,让你的代码更容易修改的方法。
不出意外的话,每个从事编码工程的人都可能会有同样的思考。特别是那些工业级别的工程,在那里通常工作着数十甚至数百名开发者;协作过程表明必须有一些标准和规则来使代码更加优雅并适应变化。 这就是为什么我们有 [面向对象编程][3]OOP和 [软件框架工具][4]。设计模式有点类似于OOP但它通过将变化视为自然开发过程的一部分而进一步发展。基本上设计模式利用了一些OOP的思想比如抽象和接口但是专注于改变的过程。
不出意外的话,每个从事编程项目的人都可能会有同样的思考。特别是那些工业级别的项目,在那里通常工作着数十甚至数百名开发者;协作过程表明必须有一些标准和规则来使代码更加优雅并适应变化。这就是为什么我们有 [面向对象编程][3]OOP和 [软件框架工具][4]。设计模式有点类似于 OOP但它通过将变化视为自然开发过程的一部分而进一步发展。基本上设计模式利用了一些 OOP 的思想,比如抽象和接口,但是专注于改变的过程。
当你开始开发项目时,你经常会听到这样一个术语*重构*,它意味着*通过改变代码使它变得更优雅和可复用*;这就是设计模式耀眼的地方。当你处理现有代码时(无论是由其他人构建还是你自己过去构建的),了解设计模式可以帮助你以不同的方式看待事物,你将发现问题以及改进代码的方法。
当你开始开发项目时, 你经常会听到这样一个术语 _重构__意味着通过改变代码使它变得更优雅和可复用_ 这就是设计模式耀眼的地方。 无论什么时候你处理现有代码时(无论是由其他人构建还是你自己过去构建的),了解设计模式可以帮助你以不同的方式看待事物,你将发现问题以及改进代码的方法。
那里有很多种设计模式,其中单例模式,工厂模式,和观察者模式三种最受欢迎,在这篇文章中我将会一一介绍它们。
有很多种设计模式,其中单例模式、工厂模式和观察者模式三种最受欢迎,在这篇文章中我将会一一介绍它们。
### 如何遵循本指南
无论你是一位有经验的编程工作者还是一名刚刚接触的新手,我想让这篇教程很容易让每个人都可以理解。设计模式概念并不容易理解,减少开始旅程时的学习曲线始终是首要任务。因此,除了这篇带有图表和代码片段的文章外,我还创建了一个 [GitHub仓库][5],你可以克隆和在你的电脑上运行代码去实现这三种设计模式。你也可以观看我创建的 [YouTube视频][6]。
无论你是一位有经验的编程工作者还是一名刚刚接触的新手,我想让这篇教程让每个人都很容易理解。设计模式概念并不容易理解,减少开始旅程时的学习曲线始终是首要任务。因此,除了这篇带有图表和代码片段的文章外,我还创建了一个 [GitHub 仓库][5],你可以克隆仓库并在你的电脑上运行这些代码来实现这三种设计模式。你也可以观看我创建的 [YouTube视频][6]。
#### 必要条件
如果你只是想了解一般的设计模式思想,则无需克隆示例项目或安装任何工具。但是,如果要运行示例代码,你需要安装以下工具:
* **Java 开发套件JDK**:我强烈建议使用 [OpenJDK][7]。
* **Apache Maven**:这个简单的项目使用 [Apache Maven][8] 构建;好的是许多 IDE 自带了Maven。
* **交互式开发编辑器IDE**:我使用 [社区版 IntelliJ][9],但是你也可以使用 [Eclipse IDE][10] 或者其他你喜欢的 Java IDE。
* **Git**:如果你想克隆这个工程,你需要 [Git][11] 客户端。
* **Java Development Kit (JDK):** 我强烈建议 [OpenJDK][7]。
* **Apache Maven:** 这个简单的工程使用 [Apache Maven][8] 构建; 幸好许多IDEs自带了Maven。
* **Interactive development editor (IDE):** 我使用 [IntelliJ Community Edition][9], 但是你也可以使用 [Eclipse IDE][10] 或者其他你喜欢的 Java IDE。
* **Git:** 如果你想克隆这个工程,你需要 [Git][11]客户端。
安装好Git后运行下列命令克隆这个工程
安装好 Git 后运行下列命令克隆这个工程:
```
`git clone https://github.com/bryantson/OpensourceDotComDemos.git`
git clone https://github.com/bryantson/OpensourceDotComDemos.git
```
然后在你喜欢的IDE中你可以将TopDesignPatterns仓库中的代码作为Apache Maven项目导入。
然后在你喜欢的 IDE 中,你可以将 TopDesignPatterns 仓库中的代码作为 Apache Maven 项目导入。
正在使用Java但你也可以使用支持 [抽象原理][12]的任何编程语言来实现设计模式。
使用的是 Java但你也可以使用支持[抽象原则][12]的任何编程语言来实现设计模式。
### 单例模式:避免每次创建一个对象
[单例模式][13]是非常受欢迎的设计模式它的实现相对来说很简单因为你只需要一个类。然而许多开发人员争论单例设计模式的是否利大于弊因为它缺乏明显的好处并且容易被滥用。很少有开发人员直接实现单例相反像Spring Framework和Google Guice等编程框架内置了单例设计模式的特性。
<ruby>[单例模式][13]<rt>singleton pattern</rt></ruby>是非常流行的设计模式,它的实现相对来说很简单,因为你只需要一个类。然而,许多开发人员争论单例设计模式的是否利大于弊,因为它缺乏明显的好处并且容易被滥用。很少有开发人员直接实现单例;相反,像 Spring Framework Google Guice 等编程框架内置了单例设计模式的特性。
但是了解单例模式仍然有巨大的用处。单例模式确保一个类仅创建一次且提供了一个对的全局访问点。
但是了解单例模式仍然有巨大的用处。单例模式确保一个类仅创建一次且提供了一个对的全局访问点。
> **Singleton pattern:** 确保仅有一个实例被创建且避免在同样的工程中创建多个实例。
> **单例模式**:确保仅创建一个实例且避免在同一个项目中创建多个实例。
下面这幅图展示了典的类对象创建过程。当客户端请求创建一个对象时,构造函数会创建或者实例化一个对象并调用方法返回这个类。但是每次请求一个对象都会发生这样的情况——构造函数被调用,一个新的对象被创建并且它返回一个唯一的对象。我猜面向对象语言的创建者有每次都创建一个新对象的原因,但是单例过程的支持者说这是冗余的且浪费资源。
下面这幅图展示了典的类对象创建过程。当客户端请求创建一个对象时,构造函数会创建或者实例化一个对象并调用方法返回这个类给调用者。但是每次请求一个对象都会发生这样的情况:构造函数被调用,一个新的对象被创建并且它返回了一个独一无二的对象。我猜面向对象语言的创建者有每次都创建一个新对象的理由,但是单例过程的支持者说这是冗余的且浪费资源。
![Normal class instantiation][14]
下面这幅图使用单例模式创建对象。这里,构造函数仅当对象首次通过调用预先设计好的 getInstance() 方法时才会被调用。这通常通过检查值是否为 null 来完成,并且这个对象被作为私有变量保存在单例类的内部。下次 getInstance() 被调用时,这个类会返回第一次被创建的对象。没有新的对象产生;它只是返回旧的那一个。
下面这幅图使用单例模式创建对象。这里,构造函数仅当对象首次通过调用预先设计好的 `getInstance()` 方法时才会被调用。这通常通过检查值是否为 `null` 来完成,并且这个对象被作为私有变量保存在单例类的内部。下次 `getInstance()` 被调用时,这个类会返回第一次被创建的对象。没有新的对象产生;它只是返回旧的那一个。
![Singleton pattern instantiation][15]
下面这段代码展示了创建单例模式最简单的方法:
```
package org.opensource.demo.singleton;
@ -89,7 +84,7 @@ public class OpensourceSingleton {
}
```
在调用方, 这里展示了如何调用单例类来获取对象:
在调用方,这里展示了如何调用单例类来获取对象:
```
Opensource newObject = Opensource.getInstance();
@ -97,11 +92,10 @@ Opensource newObject = Opensource.getInstance();
这段代码很好的验证了单例模式的思想:
1. 当 getInstance() 被调用时,它通过检查 null 值来检查对象是否已经被创建。
2. 如果值为,它会创建一个新对象并把它保存到私有域,返回这个对象给调用者。否则直接返回之前被创建的对象。
1. 当 `getInstance()` 被调用时,它通过检查 `null` 值来检查对象是否已经被创建。
2. 如果值为 `null`,它会创建一个新对象并把它保存到私有域,返回这个对象给调用者。否则直接返回之前被创建的对象。
单例模式实现的主要问题是它忽略了并行进程。当多个进程使用线程同时访问资源时,这个问题就产生了。对于这种情况有对应的解决方案,它被称为 _双重检查锁_ 用于多线程安全,如下所示:
单例模式实现的主要问题是它忽略了并行进程。当多个进程使用线程同时访问资源时,这个问题就产生了。对于这种情况有对应的解决方案,它被称为*双重检查锁*,用于多线程安全,如下所示:
```
package org.opensource.demo.singleton;
@ -126,21 +120,21 @@ public class ImprovedOpensourceSingleton {
}
```
只是为了强调前一点,确保只有在你认为这是一个安全的选项时才能直接实现你的单例模式。最好的方法是通过使用一个制作精良的编程框架来利用单例功能。
再强调一下前面的观点,确保只有在你认为这是一个安全的选择时才直接实现你的单例模式。最好的方法是通过使用一个制作精良的编程框架来利用单例功能。
### 工厂模式:将对象创建委派给工厂类以隐藏创建逻辑
[工厂模式][16] 是另一种众所周知的设计模式,但是有一小点复杂。实现工厂模式的方法有很多,而下列的代码示例为最简单的实现方式。为了创建对象,工厂模式定义了一个接口,让它的子类去决定哪一个实例化
<ruby>[工厂模式][16]<rt>factory pattern</rt></ruby>是另一种众所周知的设计模式,但是有一小点复杂。实现工厂模式的方法有很多,而下列的代码示例为最简单的实现方式。为了创建对象,工厂模式定义了一个接口,让它的子类去决定实例化哪一个类。
> **Factory pattern:** 将对象创建委派给工厂类,因此它能隐藏创建逻辑。
> **工厂模式**将对象创建委派给工厂类,因此它能隐藏创建逻辑。
下列的图片展示了最简单的工厂模式是如何实现的
下列的图片展示了最简单的工厂模式是如何实现的
![Factory pattern][17]
客户端请求工厂类创建某个对象,类型 x而不是客户端直接调用对象创建。根据类型工厂模式决定要创建和返回的对象。
客户端请求工厂类创建类型 x 的某个对象,而不是客户端直接调用对象创建。根据类型,工厂模式决定要创建和返回的对象。
在下列代码示例中,OpensourceFactory 是工厂类实现,它从调用者那里获取 _类型_ 并根据该输入值决定要创建和返回的对象:
在下列代码示例中,`OpensourceFactory` 是工厂类实现,它从调用者那里获取*类型*并根据该输入值决定要创建和返回的对象:
```
package org.opensource.demo.factory;
@ -164,8 +158,7 @@ public class OpensourceFactory {
}
```
OpenSourceJVMServer 是一个100%的抽象类(或者一个接口类),它指示要实现的是什么,而不是怎样实现:
`OpenSourceJVMServer` 是一个 100% 的抽象类(即接口类),它指示要实现的是什么,而不是怎样实现:
```
package org.opensource.demo.factory;
@ -177,8 +170,7 @@ public interface OpensourceJVMServers {
}
```
这是一个 OpensourceJVMServers 实现类示例。当 “RedHat” 被作为类型传递给工厂类WildFly 服务器将被创建:
这是一个 `OpensourceJVMServers` 类的实现示例。当 `RedHat` 被作为类型传递给工厂类,`WildFly` 服务器将被创建:
```
package org.opensource.demo.factory;
@ -200,18 +192,17 @@ public class WildFly implements OpensourceJVMServers {
### 观察者模式:订阅主题并获取相关更新的通知
最后是[观察者模式][20]。像单例模式那样,很少有专业的程序员直接实现观察者模式。但是,许多消息队列和数据服务实现都借用了观察者模式的概念。观察者模式在对象之间定义了一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都将被自动地通知和更新。
最后是<ruby>[观察者模式][20]<rt>observer pattern</rt></ruby>。像单例模式那样,很少有专业的程序员直接实现观察者模式。但是,许多消息队列和数据服务实现都借用了观察者模式的概念。观察者模式在对象之间定义了一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都将被自动地通知和更新。
> **Observer pattern:** 如果有更新,那么订阅了该话题/主题的客户端将被通知。
> **观察者模式**如果有更新,那么订阅了该话题/主题的客户端将被通知。
思考观察者模式的最简单方法是想象一个邮件列表,你可以在其中订阅任何主题,无论是开源,技术,名人,烹饪还是您感兴趣的任何其他内容。每个主题维护者一个它的订阅者列表,在观察者模式中它们相当于观察者。当某一个主题更新时,它所有的订阅者(观察者)都将被通知这次改变。并且订阅者总是能取消某一个主题的订阅。
理解观察者模式的最简单方法是想象一个邮件列表,你可以在其中订阅任何主题,无论是开源、技术、名人、烹饪还是您感兴趣的任何其他内容。每个主题维护者一个它的订阅者列表,在观察者模式中它们相当于观察者。当某一个主题更新时,它所有的订阅者(观察者)都将被通知这次改变。并且订阅者总是能取消某一个主题的订阅。
如下图所示,客户端可以订阅不同的主题并添加观察者以获得最新信息的通知。因为观察者不断的监听着这个主题,这个观察者会通知客户端任何发生的改变。
![Observer pattern][21]
让我们呢来看看观察者模式的代码示例,从主题/话题类开始:
让我们来看看观察者模式的代码示例,从主题/话题类开始:
```
package org.opensource.demo.observer;
@ -223,7 +214,8 @@ public interface Topic {
    public void notifyObservers();
}
```
这段代码描述了一个接口为不同的主题去实现已定义的方法。注意一个观察者如何被添加、移除和通知。
这段代码描述了一个为不同的主题去实现已定义方法的接口。注意一个观察者如何被添加、移除和通知的。
这是一个主题的实现示例:
@ -270,7 +262,7 @@ public class Conference implements Topic {
}
```
这段代码定义了一个特定主题的实现。当发生改变时,这个实现调用它自己的方法。 注意这将获取存储为列表的观察者的数量,并且可以通知和维护观察者。
这段代码定义了一个特定主题的实现。当发生改变时,这个实现调用它自己的方法。注意这将获取观察者的数量,它以列表方式存储,并且可以通知和维护观察者。
这是一个观察者类:
@ -286,7 +278,6 @@ public interface [Observer][22] {
例如,实现了该接口的观察者可以在会议上打印出与会者和发言人的数量:
```
package org.opensource.demo.observer;
@ -314,13 +305,11 @@ public class MonitorConferenceAttendees implements [Observer][22] {
}
```
### 之后去哪?
### 接下来
现在你已经阅读了这篇对于设计模式的介绍引导,你应该去一个好地方寻求其他设计模式,例如外观模式,模版模式和装饰器模式。也有一些并发和分布式系统的设计模式如断路器模式和锚定模式。
现在你已经阅读了这篇对于设计模式的介绍引导,你还可以去寻求了解其他设计模式,例如外观模式,模版模式和装饰器模式。也有一些并发和分布式系统的设计模式如断路器模式和锚定模式。
可是我相信最好的磨砺你的技能首先是通过在你的边缘工程或者练习中实现这些设计模式。你甚至可以开始考虑如何在实际项目中应用这些设计模式。接下来我强烈建议您查看OOP的 [SOLID原则][23]。之后,你将准备好了解其他设计模式。
However, I believe it's best to hone your skills first by implementing these design patterns in your side projects or just as practice. You can even begin to contemplate how you can apply these design patterns in your real projects. Next, I highly recommend checking out the [SOLID principles][23] of OOP. After that, you will be ready to look into the other design patterns.
可是,我相信最好的磨砺你的技能的方式首先是通过在你的业余项目或者练习中实现这些设计模式。你甚至可以开始考虑如何在实际项目中应用这些设计模式。接下来,我强烈建议你查看 OOP 的 [SOLID 原则][23]。之后,你就准备好了解其他设计模式。
--------------------------------------------------------------------------------
@ -329,7 +318,7 @@ via: https://opensource.com/article/19/7/understanding-software-design-patterns
作者:[Bryant Son][a]
选题:[lujun9972][b]
译者:[arrowfeng](https://github.com/arrowfeng)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,67 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Goodbye, Linux Journal)
[#]: via: (https://opensource.com/article/19/8/goodbye-linux-journal)
[#]: author: (Jim Hall https://opensource.com/users/jim-hallhttps://opensource.com/users/scottnesbitthttps://opensource.com/users/alanfdoss)
Goodbye, Linux Journal
======
Linux Journal's coverage from 1994 to 2019 highlighted Linuxs rise to
an enterprise platform that runs a majority of the worlds servers and
services.
![Linux keys on the keyboard for a desktop computer][1]
I first discovered Linux in 1993, when I was an undergraduate physics student who wanted the power of Big Unix on my home PC. I remember installing my first Linux distribution, SoftLanding Systems (SLS), and exploring the power of Linux on my 386 PC. I was immediately impressed. Since then, Ive run Linux at home—and even at work.
In those early days, it felt like I was the only person who knew about Linux. Certainly, there was an online community via Usenet, but there werent many other ways to get together with other Linux users—unless you had a local Linux User Group in your area. I shared what I knew about Linux with those around me, and we pooled our Linux fu.
So, it was awesome to learn about a print magazine that was dedicated to all things Linux. In March 1994, Phil Hughes and Red Hat co-founder Bob Young published a new magazine about Linux, named _Linux Journal_. The [first issue][2] featured an "[Interview With Linus, The Author of Linux][3]" by Robert Young, and an article comparing "[Linux Vs. Windows NT and OS/2][4]" by Bernie Thompson.
From the start, _Linux Journal_ aimed to be a community-driven magazine. Hughes and Young were not the only contributors to the magazine. Instead, they invited others to write about Linux and share what they had learned. In a way, _Linux Journal_ used a model similar to open source software. Anyone could contribute, and the editors acted as "maintainers" to ensure content was top quality and informative.
_Linux Journal_ also went for a broad audience. The editors realized that a purely technical magazine would lose too many new users, while a magazine written for "newbies" would not attract a more focused audience. In the first issue, [Hughes highlighted][5] both groups of users as the audience _Linux Journal_ was looking for, writing: "We see this part of our audience as being two groups. Lots of the current Linux users have worked professionally with Unix. The other segment is the DOS user who wants to upgrade to a multi-user system. With a combination of tutorials and technical articles, we hope to satisfy the needs of both these groups."
I was glad to discover _Linux Journal_ in those early days, and I quickly became a subscriber. In time, I contributed my own stories to _Linux Journal_. Ive written several articles including essays on usability in open source software, Bash shell scripting tricks, and C programming how-tos.
But my contributions to Linux Journal are meager compared to others. Over the years, I have enjoyed reading many article series from regular contributors. I loved Dave Taylor's "Work the Shell" series about practical and sometimes magical scripts written for the Bash shell. I always turned to Kyle Rankin's "Hack and /" series about cool projects with Linux. And I have enjoyed reading articles from the latest Linux Journal deputy editor Bryan Lunduke, especially a recent geeky article about "[How to Live Entirely in a Terminal][6]" that showed you can still do daily tasks on Linux without a graphical environment.
Many years later, things took a turn. Linux Journals Publisher Carlie Fairchild wrote a seemingly terminal essay [_Linux Journal Ceases Publication_][7] in December 2017 that indicated _Linux Journal_ had "run out of money, and options along with it." But a month later, Carlie updated the news item to report that "*Linux Journal *was saved and brought back to life" by an angel investor. London Trust Media, the parent company of Private Internet Access, injected new funds into Linux Journal to get the magazine back on its feet. _Linux Journal_ resumed regular issues in March 2018.
But it seems the rescue was not enough. Late in the evening of August 7, 2019, _Linux Journal_ posted a final, sudden goodbye. Kyle Rankins essay [_Linux Journal Ceases Publication: An Awkward Goodbye_][8] was preceded with this announcement:
**IMPORTANT NOTICE FROM LINUX JOURNAL, LLC:**
_On August 7, 2019, Linux Journal shut its doors for good. All staff were laid off and the company is left with no operating funds to continue in any capacity. The website will continue to stay up for the next few weeks, hopefully longer for archival purposes if we can make it happen.
Linux Journal, LLC_
The announcement came as a surprise to readers and staff alike. I reached out to Bryan Lunduke, who commented the shutdown was a "total surprise. Was writing an article the night before for an upcoming issue... No indication that things were preparing to fold." The next morning, on August 7, Lunduke said he "had a series of frantic messages from our Editor (Jill) and Publisher (Carlie). They had just found out, effective the night before... _Linux Journal_ was shut down. So we weren't so much being told that Linux Journal is shutting down... as _Linux Journal_ had already been shut down the day before... and we just didn't know it."
It's the end of an era. And as we salute the passing of _Linux Journal_, Id like to recognize the indelible mark the magazine has left on the Linux landscape. _Linux Journal_ was the first publication to highlight Linux as a serious platform, and I think that made people take notice.
And with that seriousness, that maturity, _Linux Journal_ helped Linux shake its early reputation of being a hobby project. _Linux Journal's_ coverage from 1994 to 2019 highlighted Linuxs rise to an enterprise platform that runs a majority of the worlds servers and services.
I tip my hat to everyone at _Linux Journal_ and any contributor who was part of its journey. It has been a pleasure to work with you over the years. You kept the spirit alive. This may be a painful experience, but I hope everyone ends up in a good place.
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/8/goodbye-linux-journal
作者:[Jim Hall][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/jim-hallhttps://opensource.com/users/scottnesbitthttps://opensource.com/users/alanfdoss
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/linux_keyboard_desktop.png?itok=I2nGw78_ (Linux keys on the keyboard for a desktop computer)
[2]: https://www.linuxjournal.com/issue/1
[3]: https://www.linuxjournal.com/article/2736
[4]: https://www.linuxjournal.com/article/2734
[5]: https://www.linuxjournal.com/article/2735
[6]: https://www.linuxjournal.com/content/without-gui-how-live-entirely-terminal
[7]: https://www.linuxjournal.com/content/linux-journal-ceases-publication
[8]: https://www.linuxjournal.com/content/linux-journal-ceases-publication-awkward-goodbye

View File

@ -1,5 +1,5 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: translator: (luming)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )

View File

@ -1,311 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: (MjSeven)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Learn object-oriented programming with Python)
[#]: via: (https://opensource.com/article/19/7/get-modular-python-classes)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
Learn object-oriented programming with Python
======
Make your code more modular with Python classes.
![Developing code.][1]
In my previous article, I explained how to [make Python modular][2] by using functions, creating modules, or both. Functions are invaluable to avoid repeating code you intend to use several times, and modules ensure that you can use your code across different projects. But there's another component to modularity: the class.
If you've heard the term _object-oriented programming_, then you may have some notion of the purpose classes serve. Programmers tend to consider a class as a virtual object, sometimes with a direct correlation to something in the physical world, and other times as a manifestation of some programming concept. Either way, the idea is that you can create a class when you want to create "objects" within a program for you or other parts of the program to interact with.
### Templates without classes
Assume you're writing a game set in a fantasy world, and you need this application to be able to drum up a variety of baddies to bring some excitement into your players' lives. Knowing quite a lot about functions, you might think this sounds like a textbook case for functions: code that needs to be repeated often but is written once with allowance for variations when called.
Here's an example of a purely function-based implementation of an enemy generator:
```
#!/usr/bin/env python3
import random
def enemy(ancestry,gear):
    enemy=ancestry
    weapon=gear
    hp=random.randrange(0,20)
    ac=random.randrange(0,20)
    return [enemy,weapon,hp,ac]
def fight(tgt):
    print("You take a swing at the " + tgt[0] + ".")
    hit=random.randrange(0,20)
    if hit &gt; tgt[3]:
        print("You hit the " + tgt[0] + " for " + str(hit) + " damage!")
        tgt[2] = tgt[2] - hit
    else:
        print("You missed.")
foe=enemy("troll","great axe")
print("You meet a " + foe[0] + " wielding a " + foe[1])
print("Type the a key and then RETURN to attack.")
while True:
    action=input()
    if action.lower() == "a":
        fight(foe)
    if foe[2] &lt; 1:
        print("You killed your foe!")
    else:
        print("The " + foe[0] + " has " + str(foe[2]) + " HP remaining")
```
The **enemy** function creates an enemy with several attributes, such as ancestry, a weapon, health points, and a defense rating. It returns a list of each attribute, representing the sum total of the enemy.
In a sense, this code has created an object, even though it's not using a class yet. Programmers call this "enemy" an _object_ because the result (a list of strings and integers, in this case) of the function represents a singular but complex _thing_ in the game. That is, the strings and integers in the list aren't arbitrary: together, they describe a virtual object.
When writing a collection of descriptors, you use variables so you can use them any time you want to generate an enemy. It's a little like a template.
In the example code, when an attribute of the object is needed, the corresponding list item is retrieved. For instance, to get the ancestry of an enemy, the code looks at **foe[0]**, for health points, it looks at **foe[2]** for health points, and so on.
There's nothing necessarily wrong with this approach. The code runs as expected. You could add more enemies of different types, you could create a list of enemy types and randomly select from the list during enemy creation, and so on. It works well enough, and in fact [Lua][3] uses this principle very effectively to approximate an object-oriented model.
However, there's sometimes more to an object than just a list of attributes.
### The way of the object
In Python, everything is an object. Anything you create in Python is an _instance_ of some predefined template. Even basic strings and integers are derivatives of the Python **type** class. You can witness this for yourself an interactive Python shell:
```
&gt;&gt;&gt; foo=3
&gt;&gt;&gt; type(foo)
&lt;class 'int'&gt;
&gt;&gt;&gt; foo="bar"
&gt;&gt;&gt; type(foo)
&lt;class 'str'&gt;
```
When an object is defined by a class, it is more than just a collection of attributes. Python classes have functions all their own. This is convenient, logically, because actions that pertain only to a certain class of objects are contained within that object's class.
In the example code, the fight code is a function of the main application. That works fine for a simple game, but in a complex one, there would be more than just players and enemies in the game world. There might be townsfolk, livestock, buildings, forests, and so on, and none of them ever need access to a fight function. Placing code for combat in an enemy class means your code is better organized; and in a complex application, that's a significant advantage.
Furthermore, each class has privileged access to its own local variables. An enemy's health points, for instance, isn't data that should ever change except by some function of the enemy class. A random butterfly in the game should not accidentally reduce an enemy's health to 0. Ideally, even without classes, that would never happen, but in a complex application with lots of moving parts, it's a powerful trick of the trade to ensure that parts that don't need to interact with one another never do.
Python classes are also subject to garbage collection. When an instance of a class is no longer used, it is moved out of memory. You may never know when this happens, but you tend to notice when it doesn't happen because your application takes up more memory and runs slower than it should. Isolating data sets into classes helps Python track what is in use and what is no longer needed.
### Classy Python
Here's the same simple combat game using a class for the enemy:
```
#!/usr/bin/env python3
import random
class Enemy():
    def __init__(self,ancestry,gear):
        self.enemy=ancestry
        self.weapon=gear
        self.hp=random.randrange(10,20)
        self.ac=random.randrange(12,20)
        self.alive=True
    def fight(self,tgt):
        print("You take a swing at the " + self.enemy + ".")
        hit=random.randrange(0,20)
        if self.alive and hit &gt; self.ac:
            print("You hit the " + self.enemy + " for " + str(hit) + " damage!")
            self.hp = self.hp - hit
            print("The " + self.enemy + " has " + str(self.hp) + " HP remaining")
        else:
            print("You missed.")
        if self.hp &lt; 1:
            self.alive=False
# game start
foe=Enemy("troll","great axe")
print("You meet a " + foe.enemy + " wielding a " + foe.weapon)
# main loop
while True:
   
    print("Type the a key and then RETURN to attack.")
       
    action=input()
    if action.lower() == "a":
        foe.fight(foe)
               
    if foe.alive == False:
        print("You have won...this time.")
        exit()
```
This version of the game handles the enemy as an object containing the same attributes (ancestry, weapon, health, and defense), plus a new attribute measuring whether the enemy has been vanquished yet, as well as a function for combat.
The first function of a class is a special function called (in Python) an _init_, or initialization, function. This is similar to a [constructor][4] in other languages; it creates an instance of the class, which is identifiable to you by its attributes and to whatever variable you use when invoking the class (**foe** in the example code).
### Self and class instances
The class' functions accept a new form of input you don't see outside of classes: **self**. If you don't include **self**, then Python has no way of knowing _which_ instance of the class to use when you call a class function. It's like challenging a single orc to a duel by saying "I'll fight the orc" in a room full of orcs; nobody knows which one you're referring to, and so bad things happen.
![Image of an Orc, CC-BY-SA by Buch on opengameart.org][5]
CC-BY-SA by Buch on opengameart.org
Each attribute created within a class is prepended with the **self** notation, which identifies that variable as an attribute of the class. Once an instance of a class is spawned, you swap out the **self** prefix with the variable representing that instance. Using this technique, you could challenge just one orc to a duel in a room full of orcs by saying "I'll fight the gorblar.orc"; when Gorblar the Orc hears **gorblar.orc**, he knows which orc you're referring to (him_self_), and so you get a fair fight instead of a brawl. In Python:
```
gorblar=Enemy("orc","sword")
print("The " + gorblar.enemy + " has " + str(gorblar.hp) + " remaining.")
```
Instead of looking to **foe[0]** (as in the functional example) or **gorblar[0]** for the enemy type, you retrieve the class attribute (**gorblar.enemy** or **gorblar.hp** or whatever value for whatever object you need).
### Local variables
If a variable in a class is not prepended with the **self** keyword, then it is a local variable, just as in any function. For instance, no matter what you do, you cannot access the **hit** variable outside the **Enemy.fight** class:
```
&gt;&gt;&gt; print(foe.hit)
Traceback (most recent call last):
  File "./enclass.py", line 38, in &lt;module&gt;
    print(foe.hit)
AttributeError: 'Enemy' object has no attribute 'hit'
&gt;&gt;&gt; print(foe.fight.hit)
Traceback (most recent call last):
  File "./enclass.py", line 38, in &lt;module&gt;
    print(foe.fight.hit)
AttributeError: 'function' object has no attribute 'hit'
```
The **hit** variable is contained within the Enemy class, and only "lives" long enough to serve its purpose in combat.
### More modularity
This example uses a class in the same text document as your main application. In a complex game, it's easier to treat each class almost as if it were its own self-standing application. You see this when multiple developers work on the same application: one developer works on a class, and the other works on the main program, and as long as they communicate with one another about what attributes the class must have, the two code bases can be developed in parallel.
To make this example game modular, split it into two files: one for the main application and one for the class. Were it a more complex application, you might have one file per class, or one file per logical groups of classes (for instance, a file for buildings, a file for natural surroundings, a file for enemies and NPCs, and so on).
Save one file containing just the Enemy class as **enemy.py** and another file containing everything else as **main.py**.
Here's **enemy.py**:
```
import random
class Enemy():
    def __init__(self,ancestry,gear):
        self.enemy=ancestry
        self.weapon=gear
        self.hp=random.randrange(10,20)
        self.stg=random.randrange(0,20)
        self.ac=random.randrange(0,20)
        self.alive=True
    def fight(self,tgt):
        print("You take a swing at the " + self.enemy + ".")
        hit=random.randrange(0,20)
        if self.alive and hit &gt; self.ac:
            print("You hit the " + self.enemy + " for " + str(hit) + " damage!")
            self.hp = self.hp - hit
            print("The " + self.enemy + " has " + str(self.hp) + " HP remaining")
        else:
            print("You missed.")
        if self.hp &lt; 1:
            self.alive=False
```
Here's **main.py**:
```
#!/usr/bin/env python3
import enemy as en
# game start
foe=en.Enemy("troll","great axe")
print("You meet a " + foe.enemy + " wielding a " + foe.weapon)
# main loop
while True:
   
    print("Type the a key and then RETURN to attack.")
    action=input()
    if action.lower() == "a":
        foe.fight(foe)
    if foe.alive == False:
        print("You have won...this time.")
        exit()
```
Importing the module **enemy.py** is done very specifically with a statement that refers to the file of classes as its name without the **.py** extension, followed by a namespace designator of your choosing (for example, **import enemy as en**). This designator is what you use in the code when invoking a class. Instead of just using **Enemy()**, you preface the class with the designator of what you imported, such as **en.Enemy**.
All of these file names are entirely arbitrary, although not uncommon in principle. It's a common convention to name the part of the application that serves as the central hub **main.py**, and a file full of classes is often named in lowercase with the classes inside it, each beginning with a capital letter. Whether you follow these conventions doesn't affect how the application runs, but it does make it easier for experienced Python programmers to quickly decipher how your application works.
There's some flexibility in how you structure your code. For instance, using the code sample, both files must be in the same directory. If you want to package just your classes as a module, then you must create a directory called, for instance, **mybad** and move your classes into it. In **main.py**, your import statement changes a little:
```
`from mybad import enemy as en`
```
Both systems produce the same results, but the latter is best if the classes you have created are generic enough that you think other developers could use them in their projects.
Regardless of which you choose, launch the modular version of the game:
```
$ python3 ./main.py
You meet a troll wielding a great axe
Type the a key and then RETURN to attack.
a
You take a swing at the troll.
You missed.
Type the a key and then RETURN to attack.
a
You take a swing at the troll.
You hit the troll for 8 damage!
The troll has 4 HP remaining
Type the a key and then RETURN to attack.
a
You take a swing at the troll.
You hit the troll for 11 damage!
The troll has -7 HP remaining
You have won...this time.
```
The game works. It's modular. And now you know what it means for an application to be object-oriented. But most importantly, you know to be specific when challenging an orc to a duel.
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/7/get-modular-python-classes
作者:[Seth Kenlon][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/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_development_programming.png?itok=M_QDcgz5 (Developing code.)
[2]: https://opensource.com/article/19/6/get-modular-python-functions
[3]: https://opensource.com/article/17/4/how-program-games-raspberry-pi
[4]: https://opensource.com/article/19/6/what-java-constructor
[5]: https://opensource.com/sites/default/files/images/orc-buch-opengameart_cc-by-sa.jpg (CC-BY-SA by Buch on opengameart.org)

View File

@ -1,144 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: (furrybear)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (How to create a pull request in GitHub)
[#]: via: (https://opensource.com/article/19/7/create-pull-request-github)
[#]: author: (Kedar Vijay Kulkarni https://opensource.com/users/kkulkarnhttps://opensource.com/users/fontanahttps://opensource.com/users/mhanwellhttps://opensource.com/users/mysentimentshttps://opensource.com/users/greg-p)
How to create a pull request in GitHub
======
Learn how to fork a repo, make changes, and ask the maintainers to
review and merge it.
![a checklist for a team][1]
So, you know how to use git. You have a [GitHub][2] repo and can push to it. All is well. But how the heck do you contribute to other people's GitHub projects? That is what I wanted to know after I learned git and GitHub. In this article, I will explain how to fork a git repo, make changes, and submit a pull request.
When you want to work on a GitHub project, the first step is to fork a repo.
![Forking a GitHub repo][3]
Use [my demo repo][4] to try it out.
Once there, click on the **Fork** button in the top-right corner. This creates a new copy of my demo repo under your GitHub user account with a URL like:
```
`https://github.com/<YourUserName>/demo`
```
The copy includes all the code, branches, and commits from the original repo.
Next, clone the repo by opening the terminal on your computer and running the command:
```
`git clone https://github.com/<YourUserName>/demo`
```
Once the repo is cloned, you need to do two things:
1. Create a new branch by issuing the command:
```
`git checkout -b new_branch`
```
2. Create a new remote for the upstream repo with the command:
```
`git remote add upstream https://github.com/kedark3/demo`
```
In this case, "upstream repo" refers to the original repo you created your fork from.
Now you can make changes to the code. The following code creates a new branch, makes an arbitrary change, and pushes it to **new_branch**:
```
$ git checkout -b new_branch
Switched to a new branch new_branch
$ echo “some test file” &gt; test
$ cat test
Some test file
$ git status
On branch new_branch
No commits yet
Untracked files:
  (use "git add &lt;file&gt;..." to include in what will be committed)
    test
nothing added to commit but untracked files present (use "git add" to track)
$ git add test
$ git commit -S -m "Adding a test file to new_branch"
[new_branch (root-commit) 4265ec8] Adding a test file to new_branch
 1 file changed, 1 insertion(+)
 create mode 100644 test
$ git push -u origin new_branch
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 918 bytes | 918.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
Remote: Create a pull request for new_branch on GitHub by visiting:
Remote:   <http://github.com/example/Demo/pull/new/new\_branch>
Remote:
 * [new branch]         new_branch -&gt; new_branch
```
Once you push the changes to your repo, the **Compare &amp; pull request** button will appear in GitHub.
![GitHub's Compare & Pull Request button][5]
Click it and you'll be taken to this screen:
![GitHub's Open pull request button][6]
Open a pull request by clicking the **Create pull request** button. This allows the repo's maintainers to review your contribution. From here, they can merge it if it is good, or they may ask you to make some changes.
### TLDR
In summary, if you want to contribute to a project, the simplest way is to:
1. Find a project you want to contribute to
2. Fork it
3. Clone it to your local system
4. Make a new branch
5. Make your changes
6. Push it back to your repo
7. Click the **Compare &amp; pull request** button
8. Click **Create pull request** to open a new pull request
If the reviewers ask for changes, repeat steps 5 and 6 to add more commits to your pull request.
Happy coding!
In a previous article , I discussed the complaints that have been leveled against GitHub during the...
Arfon Smith works at GitHub and is involved in a number of activities at the intersection of open...
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/7/create-pull-request-github
作者:[Kedar Vijay Kulkarni][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/kkulkarnhttps://opensource.com/users/fontanahttps://opensource.com/users/mhanwellhttps://opensource.com/users/mysentimentshttps://opensource.com/users/greg-p
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/checklist_hands_team_collaboration.png?itok=u82QepPk (a checklist for a team)
[2]: https://github.com/
[3]: https://opensource.com/sites/default/files/uploads/forkrepo.png (Forking a GitHub repo)
[4]: https://github.com/kedark3/demo
[5]: https://opensource.com/sites/default/files/uploads/compare-and-pull-request-button.png (GitHub's Compare & Pull Request button)
[6]: https://opensource.com/sites/default/files/uploads/open-a-pull-request_crop.png (GitHub's Open pull request button)

View File

@ -1,155 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: (FSSlc)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (How To Verify ISO Images In Linux)
[#]: via: (https://www.ostechnix.com/how-to-verify-iso-images-in-linux/)
[#]: author: (sk https://www.ostechnix.com/author/sk/)
How To Verify ISO Images In Linux
======
![How To Verify ISO Images In Linux][1]
You just downloaded an ISO image of your favorite Linux distribution from the official site or a third party site, now what? [**Create bootable medium**][2] and start installing the OS? No, wait. Before start using it, It is highly recommended to verify that the downloaded ISO in your local system is the exact copy of the ISO present in the download mirrors. Because, [**Linux Mints website is hacked**][3] few years ago and the hackers made a modified Linux Mint ISO, with a backdoor in it. So, It is important to check the authenticity and integrity of your Linux ISO images. If you dont know how to verify ISO images in Linux, this brief guide will help. Read on!
### Verify ISO Images In Linux
We can verify ISO images using the **Checksum** values. Checksum is a sequence of letters and numbers used to check data for errors and verify the authenticity and integrity of the downloaded files. There are different types of checksums, such as SHA-0, SHA-1, SHA-2 (224, 256, 384, 512) and MD5. MD5 sums have been the most popular, but nowadays SHA-256 sums are mostly used by modern Linux distros.
We are going to use two tools namely **“gpg”** and **“sha256”** to verify authenticity and integrity of the ISO images.
##### Download checksums and signatures
For the purpose of this guide, I am going to use Ubuntu 18.04 LTS server ISO image. However, the steps given below should work on other Linux distributions as well.
Near the top of the Ubuntu download page, you will see a few extra files (checksums and signatures) as shown in the following picture.
![][4]
Ubuntu 18.04 checksum and signature
Here, the **SHA256SUMS** file contains checksums for all the available images and the **SHA256SUMS.gpg** file is the GnuPG signature for that file. We use this signature file to **verify** the checksum file in subsequent steps.
Download the Ubuntu ISO images and these two files and put them all in a directory, for example **ISO**.
```
$ ls ISO/
SHA256SUMS SHA256SUMS.gpg ubuntu-18.04.2-live-server-amd64.iso
```
As you see in the above output, I have downloaded Ubuntu 18.04.2 LTS server image along with checksum and signature values.
##### Download valid signature key
Now, download the correct signature key using command:
```
$ gpg --keyid-format long --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x46181433FBB75451 0xD94AA3F0EFE21092
```
Sample output:
```
gpg: key D94AA3F0EFE21092: 57 signatures not checked due to missing keys
gpg: key D94AA3F0EFE21092: public key "Ubuntu CD Image Automatic Signing Key (2012) <[email protected]>" imported
gpg: key 46181433FBB75451: 105 signatures not checked due to missing keys
gpg: key 46181433FBB75451: public key "Ubuntu CD Image Automatic Signing Key <[email protected]>" imported
gpg: no ultimately trusted keys found
gpg: Total number processed: 2
gpg: imported: 2
```
##### Verify SHA-256 checksum
Next verify the checksum file using the signature with command:
```
$ gpg --keyid-format long --verify SHA256SUMS.gpg SHA256SUMS
```
Sample output:
```
gpg: Signature made Friday 15 February 2019 04:23:33 AM IST
gpg: using DSA key 46181433FBB75451
gpg: Good signature from "Ubuntu CD Image Automatic Signing Key <[email protected]>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: C598 6B4F 1257 FFA8 6632 CBA7 4618 1433 FBB7 5451
gpg: Signature made Friday 15 February 2019 04:23:33 AM IST
gpg: using RSA key D94AA3F0EFE21092
gpg: Good signature from "Ubuntu CD Image Automatic Signing Key (2012) <[email protected]>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 8439 38DF 228D 22F7 B374 2BC0 D94A A3F0 EFE2 1092
```
If you see “Good signature” in the output,the checksum file is created by Ubuntu developer and signed by the owner of the key file.
##### Check the downloaded ISO file
Next, let us go ahead and check the downloaded ISO file matches the checksum. To do so, simply run:
```
$ sha256sum -c SHA256SUMS 2>&1 | grep OK
ubuntu-18.04.2-live-server-amd64.iso: OK
```
If the checksum values are matched, you will see the **“OK”** message. Meaning the downloaded file is legitimate and hasnt altered or tampered.
If you dont get any output or different than above output, the ISO file has been modified or incorrectly downloaded. You must re-download the file again from a good source.
Some Linux distributions have included the checksum value in the download page itself. For example, **Pop!_os** developers have provided the SHA-256 checksum values for all ISO images in the download page itself, so you can quickly verify the ISO images.
![][5]
Pop os SHA256 sum value in download page
After downloading the the ISO image, verify it using command:
```
$ sha256sum Soft_backup/ISOs/pop-os_18.04_amd64_intel_54.iso
```
Sample output:
```
680e1aa5a76c86843750e8120e2e50c2787973343430956b5cbe275d3ec228a6 Soft_backup/ISOs/pop-os_18.04_amd64_intel_54.iso
```
![][6]
Pop os SHA256 sum value
Here, the random string starting with **“680elaa…”** is the SHA-256 checksum value. Compare this value with the SHA-256 sum value provided on the downloads page. If both values are same, youre good to go! The downloaded ISO file is legitimate and it hasnt changed or modified from its original state.
This is how we can verify the authenticity and integrity of an ISO file in Linux. Whether you download ISOs from official or third-party sources, it is always recommended to do a quick verification before using them. Hope this was useful.
**Reference:**
* [**https://tutorials.ubuntu.com/tutorial/tutorial-how-to-verify-ubuntu**][7]
--------------------------------------------------------------------------------
via: https://www.ostechnix.com/how-to-verify-iso-images-in-linux/
作者:[sk][a]
选题:[lujun9972][b]
译者:[FSSlc](https://github.com/FSSlc)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.ostechnix.com/author/sk/
[b]: https://github.com/lujun9972
[1]: https://www.ostechnix.com/wp-content/uploads/2019/07/Verify-ISO-Images-In-Linux-720x340.png
[2]: https://www.ostechnix.com/etcher-beauitiful-app-create-bootable-sd-cards-usb-drives/
[3]: https://blog.linuxmint.com/?p=2994
[4]: https://www.ostechnix.com/wp-content/uploads/2019/07/Ubuntu-18.04-checksum-and-signature.png
[5]: https://www.ostechnix.com/wp-content/uploads/2019/07/Pop-os-SHA256-sum.png
[6]: https://www.ostechnix.com/wp-content/uploads/2019/07/Pop-os-SHA256-sum-value.png
[7]: https://tutorials.ubuntu.com/tutorial/tutorial-how-to-verify-ubuntu

View File

@ -0,0 +1,222 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Copying files in Linux)
[#]: via: (https://opensource.com/article/19/8/copying-files-linux)
[#]: author: (Seth Kenlon https://opensource.com/users/sethhttps://opensource.com/users/scottnesbitthttps://opensource.com/users/greg-p)
Copying files in Linux
======
Learn multiple ways to copy files on Linux, and the advantages of each.
![Filing papers and documents][1]
Copying documents used to require a dedicated staff member in offices, and then a dedicated machine. Today, copying is a task computer users do without a second thought. Copying data on a computer is so trivial that copies are made without you realizing it, such as when dragging a file to an external drive.
The concept that digital entities are trivial to reproduce is pervasive, so most modern computerists dont think about the options available for duplicating their work. And yet, there are several different ways to copy a file on Linux. Each method has nuanced features that might benefit you, depending on what you need to get done.
Here are a number of ways to copy files on Linux, BSD, and Mac.
### Copying in the GUI
As with most operating systems, you can do all of your file management in the GUI, if that's the way you prefer to work.
Drag and drop
The most obvious way to copy a file is the way youre probably used to copying files on computers: drag and drop. On most Linux desktops, dragging and dropping from one local folder to another local folder _moves_ a file by default. You can change this behavior to a copy operation by holding down the **Ctrl** key after you start dragging the file.
Your cursor may show an indicator, such as a plus sign, to show that you are in copy mode:
![Copying a file.][2]
Note that if the file exists on a remote system, whether its a web server or another computer on your own network that you access through a file-sharing protocol, the default action is often to copy, not move, the file.
#### Right-click
If you find dragging and dropping files around your desktop imprecise or clumsy, or doing so takes your hands away from your keyboard too much, you can usually copy a file using the right-click menu. This possibility depends on the file manager you use, but generally, a right-click produces a contextual menu containing common actions.
The contextual menu copy action stores the [file path][3] (where the file exists on your system) in your clipboard so you can then _paste_ the file somewhere else:
![Copying a file from the context menu.][4]
In this case, youre not actually copying the files contents to your clipboard. Instead, you're copying the [file path][3]. When you paste, your file manager looks at the path in your clipboard and then runs a copy command, copying the file located at that path to the path you are pasting into.
### Copying on the command line
While the GUI is a generally familiar way to copy files, copying in a terminal can be more efficient.
#### cp
The obvious terminal-based equivalent to copying and pasting a file on the desktop is the **cp** command. This command copies files and directories and is relatively straightforward. It uses the familiar _source_ and _target_ (strictly in that order) syntax, so to copy a file called **example.txt** into your **Documents** directory:
```
$ cp example.txt ~/Documents
```
Just like when you drag and drop a file onto a folder, this action doesnt replace **Documents** with **example.txt**. Instead, **cp** detects that **Documents** is a folder, and places a copy of **example.txt** into it.
You can also, conveniently (and efficiently), rename the file as you copy it:
```
$ cp example.txt ~/Documents/example_copy.txt
```
That fact is important because it allows you to make a copy of a file in the same directory as the original:
```
$ cp example.txt example.txt
cp: 'example.txt' and 'example.txt' are the same file.
$ cp example.txt example_copy.txt
```
To copy a directory, you must use the **-r** option, which stands for --**recursive**. This option runs **cp** on the directory _inode_, and then on all files within the directory. Without the **-r** option, **cp** doesnt even recognize a directory as an object that can be copied:
```
$ cp notes/ notes-backup
cp: -r not specified; omitting directory 'notes/'
$ cp -r notes/ notes-backup
```
#### cat
The **cat** command is one of the most misunderstood commands, but only because it exemplifies the extreme flexibility of a [POSIX][5] system. Among everything else **cat** does (including its intended purpose of con_cat_enating files), it can also copy. For instance, with **cat** you can [create two copies from one file][6] with just a single command. You cant do that with **cp**.
The significance of using **cat** to copy a file is the way the system interprets the action. When you use **cp** to copy a file, the files attributes are copied along with the file itself. That means that the file permissions of the duplicate are the same as the original:
```
$ ls -l -G -g
-rw-r--r--. 1 57368 Jul 25 23:57  foo.jpg
$ cp foo.jpg bar.jpg
-rw-r--r--. 1 57368 Jul 29 13:37  bar.jpg
-rw-r--r--. 1 57368 Jul 25 23:57  foo.jpg
```
Using **cat** to read the contents of a file into another file, however, invokes a system call to create a new file. These new files are subject to your default **umask** settings. To learn more about `umask`, read Alex Juarezs article covering [umask][7] and permissions in general.
Run **umask** to get the current settings:
```
$ umask
0002
```
This setting means that new files created in this location are granted **664** (**rw-rw-r--**) permission because nothing is masked by the first digits of the **umask** setting (and the executable bit is not a default bit for file creation), and the write permission is blocked by the final digit.
When you copy with **cat**, you dont actually copy the file. You use **cat** to read the contents of the file, and then redirect the output into a new file:
```
$ cat foo.jpg &gt; baz.jpg
$ ls -l -G -g
-rw-r--r--. 1 57368 Jul 29 13:37  bar.jpg
-rw-rw-r--. 1 57368 Jul 29 13:42  baz.jpg
-rw-r--r--. 1 57368 Jul 25 23:57  foo.jpg
```
As you can see, **cat** created a brand new file with the systems default umask applied.
In the end, when all you want to do is copy a file, the technicalities often dont matter. But sometimes you want to copy a file and end up with a default set of permissions, and with **cat** you can do it all in one command**.**
#### rsync
The **rsync** command is a versatile tool for copying files, with the notable ability to synchronize your source and destination. At its most simple, **rsync** can be used similarly to **cp** command:
```
$ rsync example.txt example_copy.txt
$ ls
example.txt    example_copy.txt
```
The commands true power lies in its ability to _not_ copy when its not necessary. If you use **rsync** to copy a file into a directory, but that file already exists in that directory, then **rsync** doesnt bother performing the copy operation. Locally, that fact doesnt necessarily mean much, but if youre copying gigabytes of data to a remote server, this feature makes a world of difference.
What does make a difference even locally, though, is the commands ability to differentiate files that share the same name but which contain different data. If youve ever found yourself faced with two copies of what is meant to be the same directory, then **rsync** can synchronize them into one directory containing the latest changes from each. This setup is a pretty common occurrence in industries that havent yet discovered the magic of version control, and for backup solutions in which there is one source of truth to propagate.
You can emulate this situation intentionally by creating two folders, one called **example** and the other **example_dupe**:
```
$ mkdir example example_dupe
```
Create a file in the first folder:
```
$ echo "one" &gt; example/foo.txt
```
Use **rsync** to synchronize the two directories. The most common options for this operation are **-a** (for _archive_, which ensures symlinks and other special files are preserved) and **-v** (for _verbose_, providing feedback to you on the commands progress):
```
$ rsync -av example/ example_dupe/
```
The directories now contain the same information:
```
$ cat example/foo.txt
one
$ cat example_dupe/foo.txt
one
```
If the file you are treating as the source diverges, then the target is updated to match:
```
$ echo "two" &gt;&gt; example/foo.txt
$ rsync -av example/  example_dupe/
$ cat example_dupe/foo.txt
one
two
```
Keep in mind that the **rsync** command is meant to copy data, not to act as a version control system. For instance, if a file in the destination somehow gets ahead of a file in the source, that file is still overwritten because **rsync** compares files for divergence and assumes that the destination is always meant to mirror the source:
```
$ echo "You will never see this note again" &gt; example_dupe/foo.txt
$ rsync -av example/  example_dupe/
$ cat example_dupe/foo.txt
one
two
```
If there is no change, then no copy occurs.
The **rsync** command has many options not available in **cp**, such as the ability to set target permissions, exclude files, delete outdated files that dont appear in both directories, and much more. Use **rsync** as a powerful replacement for **cp**, or just as a useful supplement.
### Many ways to copy
There are many ways to achieve essentially the same outcome on a POSIX system, so it seems that open sources reputation for flexibility is well earned. Have I missed a useful way to copy data? Share your copy hacks in the comments.
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/8/copying-files-linux
作者:[Seth Kenlon][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/sethhttps://opensource.com/users/scottnesbitthttps://opensource.com/users/greg-p
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/documents_papers_file_storage_work.png?itok=YlXpAqAJ (Filing papers and documents)
[2]: https://opensource.com/sites/default/files/uploads/copy-nautilus.jpg (Copying a file.)
[3]: https://opensource.com/article/19/7/understanding-file-paths-and-how-use-them
[4]: https://opensource.com/sites/default/files/uploads/copy-files-menu.jpg (Copying a file from the context menu.)
[5]: https://opensource.com/article/19/7/what-posix-richard-stallman-explains
[6]: https://opensource.com/article/19/2/getting-started-cat-command
[7]: https://opensource.com/article/19/7/linux-permissions-101

View File

@ -0,0 +1,285 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Mutation testing is the evolution of TDD)
[#]: via: (https://opensource.com/article/19/8/mutation-testing-evolution-tdd)
[#]: author: (Alex Bunardzic https://opensource.com/users/alex-bunardzic)
Mutation testing is the evolution of TDD
======
Since test-driven development is modeled on how nature works, mutation
testing is the natural next step in the evolution of DevOps.
![Ants and a leaf making the word "open"][1]
In "[Failure is a feature in blameless DevOps][2]," I discussed the central role of failure in delivering quality by soliciting feedback. This is the failure agile DevOps teams rely on to guide them and drive development. [Test-driven development (TDD)][3] is the _[conditio sine qua non][4]_ of any agile DevOps value stream delivery. Failure-centric TDD methodology only works if it is paired with measurable tests.
TDD methodology is modeled on how nature works and how nature produces winners and losers in the evolutionary game.
### Natural selection
![Charles Darwin][5]
In 1859, [Charles Darwin][6] proposed the theory of evolution in his book _[On the Origin of Species][7]_. Darwin's thesis was that natural variability is caused by the combination of spontaneous mutations in individual organisms and environmental pressures. These pressures eliminate less-adapted organisms while favoring other, more fit organisms. Each and every living being mutates its chromosomes, and those spontaneous mutations are carried to the next generation (the offspring). The newly emerged variability is then tested under natural selection—the environmental pressures that exist due to the variability of environmental conditions.
This simplified diagram illustrates the process of adjusting to environmental conditions.
![Environmental pressures on fish][8]
Fig. 1. Different environmental pressures result in different outcomes governed by natural selection. Image screenshot from a [video by Richard Dawkins][9].
This illustration shows a school of fish in their natural habitat. The habitat varies (darker or lighter gravel at the bottom of the sea or riverbed), as does each fish (darker or lighter body patterns and colors).
It also shows two situations (i.e., two variations of the environmental pressure):
1. The predator is present
2. The predator is absent
In the first situation, fish that are easier to spot against the gravel shade are at higher risk of being picked off by predators. When the gravel is darker, the lighter portion of the fish population is thinned out. And vice versa—when the gravel is a lighter shade, the darker portion of the fish population suffers the thinning out scenario.
In the second situation, fish are sufficiently relaxed to engage in mating. In the absence of predators and in the presence of the mating ritual, the opposite results can be expected: The fish that stand out against the background have a better chance of being picked for mating and transferring their characteristics to offspring.
### Selection criteria
When selecting among variability, the process is never arbitrary, capricious, whimsical, nor random. The decisive factor is always measurable. That decisive factor is usually called a _test_ or a _goal_.
A simple mathematical example can illustrate this process of decision making. (Only in this case it won't be governed by natural selection, but by artificial selection.) Suppose someone asks you to build a little function that will take a positive number and calculate that number's square root. How would you go about doing that?
The agile DevOps way is to _fail fast_. Start with humility, admitting upfront that you don't really know how to develop that function. All you know, at this point, is how to _describe_ what you'd like to do. In technical parlance, you are ready to engage in crafting a _unit test_.
"Unit test" describes your specific expectation. It could simply be formulated as "given the number 16, I expect the square root function to return number 4." You probably know that the square root of 16 is 4. However, you don't know the square root for some larger numbers (such as 533).
At the very least, you have formulated your selection criteria, your test or goal.
### Implement the failing test
The [.NET Core][10] platform can illustrate the implementation. .NET typically uses [xUnit.net][11] as a unit-testing framework. (To follow the coding examples, please install .NET Core and xUnit.net.)
Open the command line and create a folder where your square root solution will be implemented. For example, type:
```
`mkdir square_root`
```
Then type:
```
`cd square_root`
```
Create a separate folder for unit tests:
```
`mkdir unit_tests`
```
Move into the **unit_tests** folder (**cd unit_tests**) and initiate the xUnit framework:
```
`dotnet new xunit`
```
Now, move one folder up to the **square_root** folder, and create the **app** folder:
```
mkdir app
cd app
```
Create the scaffold necessary for the C# code:
```
`dotnet new classlib`
```
Now open your favorite editor and start cracking!
In your code editor, navigate to the **unit_tests** folder and open **UnitTest1.cs**.
Replace auto-generated code in **UnitTest1.cs** with:
```
using System;
using Xunit;
using app;
namespace unit_tests{
   public class UnitTest1{
       Calculator calculator = new Calculator();
       [Fact]
       public void GivenPositiveNumberCalculateSquareRoot(){
           var expected = 4;
           var actual = calculator.CalculateSquareRoot(16);
           Assert.Equal(expected, actual);
       }
   }
}
```
This unit test describes the expectation that the variable **expected** should be 4. The next line describes the **actual** value. It proposes to calculate the **actual** value by sending a message to the component called **calculator**. This component is described as capable of handling the **CalculateSquareRoot** message by accepting a numeric value. That component hasn't been developed yet. But it doesn't really matter, because this merely describes the expectations.
Finally, it describes what happens when the message is triggered to be sent. At that point, it asserts whether the **expected** value is equal to the **actual** value. If it is, the test passed and the goal is reached. If the **expected** value isn't equal to the **actual value**, the test fails.
Next, to implement the component called **calculator**, create a new file in the **app** folder and call it **Calculator.cs**. To implement a function that calculates the square root of a number, add the following code to this new file:
```
namespace app {
   public class Calculator {
       public double CalculateSquareRoot(double number) {
           double bestGuess = number;
           return bestGuess;
       }
   }
}
```
Before you can test this implementation, you need to instruct the unit test how to find this new component (**Calculator**). Navigate to the **unit_tests** folder and open the **unit_tests.csproj** file. Add the following line in the **&lt;ItemGroup&gt;** code block:
```
`<ProjectReference Include="../app/app.csproj" />`
```
Save the **unit_test.csproj** file. Now you are ready for your first test run.
Go to the command line and **cd** into the **unit_tests** folder. Run the following command:
```
`dotnet test`
```
Running the unit test will produce the following output:
![xUnit output after the unit test run fails][12]
Fig. 2. xUnit output after the unit test run fails.
As you can see, the unit test failed. It expected that sending number 16 to the **calculator** component would result in the number 4 as the output, but the output (the **actual** value) was the number 16.
Congratulations! You have created your first failure. Your unit test provided strong, immediate feedback urging you to fix the failure.
### Fix the failure
To fix the failure, you must improve **bestGuess**. Right now, **bestGuess** merely takes the number the function receives and returns it. Not good enough.
But how do you figure out a way to calculate the square root value? I have an idea—how about looking at how Mother Nature solves problems.
### Emulate Mother Nature by iterating
It is extremely hard (pretty much impossible) to guess the correct value from the first (and only) attempt. You must allow for several attempts at guessing to increase your chances of solving the problem. And one way to allow for multiple attempts is to _iterate_.
To iterate, store the **bestGuess** value in the **previousGuess** variable, transform the **bestGuess** value, and compare the difference between the two values. If the difference is 0, you solved the problem. Otherwise, keep iterating.
Here is the body of the function that produces the correct value for the square root of any positive number:
```
double bestGuess = number;
double previousGuess;
do {
   previousGuess = bestGuess;
   bestGuess = (previousGuess + (number/previousGuess))/2;
} while((bestGuess - previousGuess) != 0);
return bestGuess;
```
This loop (iteration) converges bestGuess values to the desired solution. Now your carefully crafted unit test passes!
![Unit test successful][13]
Fig. 3. Unit test successful, 0 tests failed.
### The iteration solves the problem
Just like Mother Nature's approach, in this exercise, iteration solves the problem. An incremental approach combined with stepwise refinement is the guaranteed way to arrive at a satisfactory solution. The decisive factor in this game is having a measurable goal and test. Once you have that, you can keep iterating until you hit the mark.
### Now the punchline!
OK, this was an amusing experiment, but the more interesting discovery comes from playing with this newly minted solution. Until now, your starting **bestGuess** was always equal to the number the function receives as the input parameter. What happens if you change the initial **bestGuess**?
To test that, you can run a few scenarios. First, observe the stepwise refinement as the iteration loops through a series of guesses as it tries to calculate the square root of 25:
![Code iterating for the square root of 25][14]
Fig. 4. Iterating to calculate the square root of 25.
Starting with 25 as the **bestGuess**, it takes eight iterations for the function to calculate the square root of 25. But what would happen if you made a comical, ridiculously wrong stab at the **bestGuess**? What if you started with a clueless second guess, that 1 million might be the square root of 25? What would happen in such an obviously erroneous situation? Would your function be able to deal with such idiocy?
Take a look at the horse's mouth. Rerun the scenario, this time starting from 1 million as the **bestGuess**:
![Stepwise refinement][15]
Fig. 5. Stepwise refinement when calculating the square root of 25 by starting with 1 million as the initial **bestGuess**.
Oh wow! Starting with a ludicrously large number, the number of iterations only tripled (from eight iterations to 23). Not nearly as dramatic an increase as you might intuitively expect.
### The moral of the story
The _Aha!_ moment arrives when you realize that, not only is iteration guaranteed to solve the problem, but it doesn't matter whether your search for the solution begins with a good or a terribly botched initial guess. However erroneous your initial understanding, the process of iteration, coupled with a measurable test/goal, puts you on the right track and delivers the solution. Guaranteed.
Figures 4 and 5 show a steep and dramatic burndown. From a wildly incorrect starting point, the iteration quickly burns down to an absolutely correct solution.
This amazing methodology, in a nutshell, is the essence of agile DevOps.
### Back to some high-level observations
Agile DevOps practice stems from the recognition that we live in a world that is fundamentally based on uncertainty, ambiguity, incompleteness, and a healthy dose of confusion. From the scientific/philosophical point of view, these traits are well documented and supported by [Heisenberg's Uncertainty Principle][16] (covering the uncertainty part), [Wittgenstein's Tractatus Logico-Philosophicus][17] (the ambiguity part), [Gödel's incompleteness theorems][18] (the incompleteness aspect), and the [Second Law of Thermodynamics][19] (the confusion caused by relentless entropy).
In a nutshell, no matter how hard you try, you can never get complete information when trying to solve any problem. It is, therefore, more profitable to abandon an arrogant stance and adopt a more humble approach to solving problems. Humility pays big dividends in rewarding you—not only with the hoped-for solution but also with the byproduct of a well-structured solution.
### Conclusion
Nature works incessantly—it's a continuous flow. Nature has no master plan; everything happens as a response to what happened earlier. The feedback loops are very tight, and apparent progress/regress is piecemeal. Everywhere you look in nature, you see stepwise refinement, in one shape or form or another.
Agile DevOps is a very interesting outcome of the engineering model's gradual maturation. DevOps is based on the recognition that the information you have available is always incomplete, so you'd better proceed cautiously. Obtain a measurable test (e.g., a hypothesis, a measurable expectation), make a humble attempt at satisfying it, most likely fail, then collect the feedback, fix the failure, and continue. There is no plan other than agreeing that, with each step of the way, there must be a measurable hypothesis/test.
In the next article in this series, I'll take a closer look at how mutation testing provides much-needed feedback that drives value.
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/8/mutation-testing-evolution-tdd
作者:[Alex Bunardzic][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/alex-bunardzic
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/osdc_520X292_openanttrail-2.png?itok=xhD3WmUd (Ants and a leaf making the word "open")
[2]: https://opensource.com/article/19/7/failure-feature-blameless-devops
[3]: https://en.wikipedia.org/wiki/Test-driven_development
[4]: https://www.merriam-webster.com/dictionary/conditio%20sine%20qua%20non
[5]: https://opensource.com/sites/default/files/uploads/darwin.png (Charles Darwin)
[6]: https://en.wikipedia.org/wiki/Charles_Darwin
[7]: https://en.wikipedia.org/wiki/On_the_Origin_of_Species
[8]: https://opensource.com/sites/default/files/uploads/environmentalconditions2.png (Environmental pressures on fish)
[9]: https://www.youtube.com/watch?v=MgK5Rf7qFaU
[10]: https://dotnet.microsoft.com/
[11]: https://xunit.net/
[12]: https://opensource.com/sites/default/files/uploads/xunit-output.png (xUnit output after the unit test run fails)
[13]: https://opensource.com/sites/default/files/uploads/unit-test-success.png (Unit test successful)
[14]: https://opensource.com/sites/default/files/uploads/iterating-square-root.png (Code iterating for the square root of 25)
[15]: https://opensource.com/sites/default/files/uploads/bestguess.png (Stepwise refinement)
[16]: https://en.wikipedia.org/wiki/Uncertainty_principle
[17]: https://en.wikipedia.org/wiki/Tractatus_Logico-Philosophicus
[18]: https://en.wikipedia.org/wiki/G%C3%B6del%27s_incompleteness_theorems
[19]: https://en.wikipedia.org/wiki/Second_law_of_thermodynamics

View File

@ -0,0 +1,193 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Use a drop-down terminal for fast commands in Fedora)
[#]: via: (https://fedoramagazine.org/use-a-drop-down-terminal-for-fast-commands-in-fedora/)
[#]: author: (Guilherme Schelp https://fedoramagazine.org/author/schelp/)
Use a drop-down terminal for fast commands in Fedora
======
![][1]
A **drop-down terminal** lets you tap a key and quickly enter any command on your desktop. Often it creates a terminal in a smooth way, sometimes with effects. This article demonstrates how it helps to improve and speed up daily tasks, using drop-down terminals like Yakuake, Tilda, Guake and a GNOME extension.
### Yakuake
[Yakuake][2] is a drop-down terminal emulator based on KDE Konsole techonology. It is distributed under the terms of the GNU GPL Version 2. It includes features such as:
* Smoothly rolls down from the top of your screen
* Tabbed interface
* Configurable dimensions and animation speed
* Skinnable
* Sophisticated D-Bus interface
To install Yakuake, use the following command:
```
$ sudo dnf install -y yakuake
```
#### Startup and configuration
If youre runnign KDE, open the System Settings and go to _Startup and Shutdown_. Add _yakuake_ to the list of programs under _Autostart_, like this:
![][3]
Its easy to configure Yakuake while running the app. To begin, launch the program at the command line:
```
$ yakuake &
```
The following welcome dialog appears. You can set a new keyboard shortcut if the standard one conflicts with another keystroke you already use:
![][4]
Now click the menu button, and the following help menu appears. Next, select _Configure Yakuake…_ to access the configuration options.
![][5]
You can customize the options for appearance, such as opacity; behavior, such as focusing terminals when the mouse pointer is moved over them; and window, such as size and animation. In the window options youll find one of the most useful options is you use two or more monitors: _Open on screen: At mouse location_.
#### Using Yakuake
The main shortcuts are:
* **F12** = Open/Retract Yakuake
* **Ctrl+F11** = Full Screen Mode
* **Ctrl+)** = Split Top/Bottom
* **Ctrl+(** = Split Left/Right
* **Ctrl+Shift+T** = New Session
* **Shift+Right** = Next Session
* **Shift+Left** = Previous Session
* **Ctrl+Alt+S** = Rename Session
Below is an example of Yakuake being used to split the session like a [terminal multiplexer][6]. Using this feature, you can run several shells in one session.
![][7]
### Tilda
[Tilda][8] is a drop-down terminal that compares with other popular terminal emulators such as GNOME Terminal, KDEs Konsole, xterm, and many others.
It features a highly configurable interface. You can even change options such as the terminal size and animation speed. Tilda also lets you enable hotkeys you can bind to commands and operations.
To install Tilda, run this command:
```
$ sudo dnf install -y tilda
```
#### Startup and configuration
Most users prefer to have a drop-down terminal available behind the scenes when they login. To set this option, first go to the app launcher in your desktop, search for Tilda, and open it.
Next, open up the Tilda Config window. Select _Start Tilda hidden_, which means it will not display a terminal immediately when started.
![][9]
Next, youll set your desktop to start Tilda automatically. If youre using KDE, go to _System Settings_ &gt; _Startup and Shutdown_ &gt; _Autostart_ and use _Add a Program_.
![][10]
If youre using GNOME, you can run this command in a terminal:
```
$ ln -s /usr/share/applications/tilda.desktop ~/.config/autostart/
```
When you run for the first time, a wizard shows up to set your preferences. If you need to change something, right click and go to _Preferences_ in the menu.
![][11]
You can also create multiple configuration files, and bind other keys to open new terminals at different places on the screen. To do that, run this command:
```
$ tilda -C
```
Every time you use the above command, Tilda creates a new config file located in the _~/.config/tilda/_ folder called _config_0_, _config_1_, and so on. You can then map a key combination to open a new Tilda terminal with a specific set of options.
#### Using Tilda
The main shortcuts are:
* **F1** = Pull Down Terminal Tilda (Note: If you have more than one config file, the shortcuts are the same, with a diferent _open/retract_ shortcut like F1, F2, F3, and so on)
* **F11** = Full Screen Mode
* **F12** = Toggle Transparency
* **Ctrl+Shift+T** = Add Tab
* **Ctrl+Page Up** = Go to Next Tab
* **Ctrl+Page Down** = Go to Previous Tab
### GNOME Extension
The Drop-down Terminal [GNOME Extension][12] lets you use this useful tool in your GNOME Shell. It is easy to install and configure, and gives you fast access to a terminal session.
#### Installation
Open a browser and go to the [site for this GNOME extension][12]. Enable the extension setting to _On_, as shown here:
![][13]
Then select _Install_ to install the extension on your system.
![][14]
Once you do this, theres no reason to set any autostart options. The extension will automatically run whenever you login to GNOME!
#### Configuration
After install, the Drop Down Terminal configuration window opens to set your preferences. For example, you can set the size of the terminal, animation, transparency, and scrollbar use.
![][15]
If you need change some preferences in the future, run the _gnome-shell-extension-prefs_ command and choose _Drop Down Terminal_.
#### Using the extension
The shortcuts are simple:
* **`** (usually the key above **Tab**) = Open/Retract Terminal
* **F12** (customize as you prefer) = Open/Retract Terminal
* * *
--------------------------------------------------------------------------------
via: https://fedoramagazine.org/use-a-drop-down-terminal-for-fast-commands-in-fedora/
作者:[Guilherme Schelp][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://fedoramagazine.org/author/schelp/
[b]: https://github.com/lujun9972
[1]: https://fedoramagazine.org/wp-content/uploads/2019/07/dropdown-terminals-816x345.jpg
[2]: https://kde.org/applications/system/org.kde.yakuake
[3]: https://fedoramagazine.org/wp-content/uploads/2019/07/auto_start-1024x723.png
[4]: https://fedoramagazine.org/wp-content/uploads/2019/07/yakuake_config-1024x419.png
[5]: https://fedoramagazine.org/wp-content/uploads/2019/07/yakuake_config_01.png
[6]: https://fedoramagazine.org/4-cool-terminal-multiplexers/
[7]: https://fedoramagazine.org/wp-content/uploads/2019/07/yakuake_usage.gif
[8]: https://github.com/lanoxx/tilda
[9]: https://fedoramagazine.org/wp-content/uploads/2019/07/tilda_startup.png
[10]: https://fedoramagazine.org/wp-content/uploads/2019/07/tilda_startup_alt.png
[11]: https://fedoramagazine.org/wp-content/uploads/2019/07/tilda_config.png
[12]: https://extensions.gnome.org/extension/442/drop-down-terminal/
[13]: https://fedoramagazine.org/wp-content/uploads/2019/07/gnome-shell-install_2-1024x455.png
[14]: https://fedoramagazine.org/wp-content/uploads/2019/07/gnome-shell-install_3.png
[15]: https://fedoramagazine.org/wp-content/uploads/2019/07/gnome-shell-install_4.png

View File

@ -0,0 +1,106 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (EndeavourOS Aims to Fill the Void Left by Antergos in Arch Linux World)
[#]: via: (https://itsfoss.com/endeavouros/)
[#]: author: (John Paul https://itsfoss.com/author/john/)
EndeavourOS Aims to Fill the Void Left by Antergos in Arch Linux World
======
![][1]
Im sure that most of our readers are aware of the [end of the Antergos project][2]. In the wake of the announcement, the members of the Antergos community created several successors. Today, we will be looking at one of the spiritual successors of Antergos: [EndeavourOS][3].
### EndeavourOS is not a fork of Antergos
Before we start, I would like to make it very clear that EndeavourOS is not a fork of Antergos. The developers used Antergos as their inspiration to create a light Arch-based distro.
![Endeavouros First Boot][4]
According to the [projects site][5], EndeavourOS came into existence because people in the Antergos community wanted to keep the spirit of Antergos alive. Their goal was simply to “have Arch installed with an easy to use installer and a friendly, helpful community to fall back on during the journey to master the system”.
Unlike many Arch-based distros, EndeavourOS is intending to work [like vanilla Arch][5], “so no one-click solutions to install your favorite app or a bunch of preinstalled apps youll eventually dont need”. For most people, especially those new to Linux and Arch, there will be a learning curve, but EndeavourOS aims to have a large friendly community where people are encouraged to ask questions and learn about their systems.
![Endeavouros Installing][6]
### A Work in Progress
EndeavourOS was [first released on July 15th][7] of this year after the project was first announced on [May 23rd][8]. Unfortunately, this means that the developers were unable to incorporate all of the features that they have planned.
For example, they want to have an online install similar to the one used by Antergos but ran into [issues with the current options][9]. “Cnchi has caused serious problems to be working outside the Antergos eco system and it needs a complete rewrite to work. The Fenix installer by RebornOS is getting more into shape, but needs more time to properly function.” For now, EndeavourOS will ship with the [Calamares installer][10].
[][11]
Suggested read  Velt/OS: A Material Design-Themed Desktop Environment
EndeavourOS will also offer [less stuff than Antergos][9]: Its repo is smaller than Antergos though they ship with some AUR packages. Their goal is to deliver a system thats close to Arch an not vanilla Arch.
![Endeavouros Updating With Kalu][12]
The developers [stated further][13]:
> “Linux and specifically Arch are all about freedom of choice, we provide a basic install that lets you explore those choices with a small layer of convenience. We will never judge you by installing GUI apps like Pamac or even work with sandbox solutions like Flatpak or Snaps. Its up to you what you are installing to make EndeavourOS work in your circumstances, thats the main difference we have with Antergos or Manjaro, but like Antergos we will try to help you if you run into a problem with one of your installed packages.”
### Experiencing EndeavourOS
I installed EndeavourOS in [VirtualBox][14] and took a look around. When I first booted from the image, I was greeted by a little box with links to the EndeavourOS site about installing. It also has a button to install and one to manually partition the drive. The Calamares installer worked very smoothly for me.
After I rebooted into a fresh install of EndeavourOS, I was greeted by a colorful themed XFCE desktop. I was also treated to a bunch of notification balloons. Most Arch-based distros Ive used come with a GUI tool like [pamac][15] or [octopi][16] to keep the system up-to-date. EndeavourOS comes with [kalu][17]. (kalu stands for “Keeping Arch Linux Up-to-date”.) It checks for updated packages, Arch Linux News, updated AUR packages and more. Once it sees an update for any of those areas, it will create a notification balloon.
I took a look through the menu to see what was installed by default. The answer is not much, not even an office suite. If they intend for EndeavourOS to be a blank canvas for anyone to create the system they want. they are headed in the right direction.
![Endeavouros Desktop][18]
### Final Thoughts
EndeavourOS is still very young. The first stable release was issued only 3 weeks ago. It is missing some stuff, most importantly an online installer. That being said, it is possible to gauge where EndeavourOS will be heading.
[][19]
Suggested read  An Overview of Intel's Clear Linux, its Features and Installation Procedure
While it is not an exact clone of Antergos, EndeavourOS wants to replicate the most important part of Antergos the welcoming, friendly community. All to often, the Linux community can seem to be unwelcoming and downright hostile to the beginner. Ive seen more and more people trying to combat that negativity and bring more people into Linux. With the EndeavourOS team making that their main focus, a great distro can be the only result.
If you are currently using Antergos, there is a way for you to [switch to EndeavourOS without performing a clean install.][20]
If you want an exact clone of Antergos, I would recommend checking out [RebornOS][21]. They are currently working on a replacement of the Cnchi installer named Fenix.
Have you tried EndeavourOS already? Hows your experience with it?
--------------------------------------------------------------------------------
via: https://itsfoss.com/endeavouros/
作者:[John Paul][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/john/
[b]: https://github.com/lujun9972
[1]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/08/endeavouros-logo.png?ssl=1
[2]: https://itsfoss.com/antergos-linux-discontinued/
[3]: https://endeavouros.com/
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/08/endeavouros-first-boot.png?resize=800%2C600&ssl=1
[5]: https://endeavouros.com/info-2/
[6]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/08/endeavouros-installing.png?resize=800%2C600&ssl=1
[7]: https://endeavouros.com/endeavouros-first-stable-release-has-arrived/
[8]: https://forum.antergos.com/topic/11780/endeavour-antergos-community-s-next-stage
[9]: https://endeavouros.com/what-to-expect-on-the-first-release/
[10]: https://calamares.io/
[11]: https://itsfoss.com/veltos-linux/
[12]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/08/endeavouros-updating-with-kalu.png?resize=800%2C600&ssl=1
[13]: https://endeavouros.com/second-week-after-the-stable-release/
[14]: https://itsfoss.com/install-virtualbox-ubuntu/
[15]: https://aur.archlinux.org/packages/pamac-aur/
[16]: https://octopiproject.wordpress.com/
[17]: https://github.com/jjk-jacky/kalu
[18]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/08/endeavouros-desktop.png?resize=800%2C600&ssl=1
[19]: https://itsfoss.com/clear-linux/
[20]: https://forum.endeavouros.com/t/how-to-switch-from-antergos-to-endevouros/105/2
[21]: https://rebornos.org/

View File

@ -0,0 +1,245 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (How to Upgrade Linux Mint 19.1 (Tessa) to Linux Mint 19.2 (Tina)?)
[#]: via: (https://www.2daygeek.com/upgrade-linux-mint-19-1-tessa-to-linux-mint-19-2-tina/)
[#]: author: (2daygeek http://www.2daygeek.com/author/2daygeek/)
How to Upgrade Linux Mint 19.1 (Tessa) to Linux Mint 19.2 (Tina)?
======
Linux Mint 19.2 “Tina” was released on Aug 02nd 2019, it is a long term support release, which is based on Ubuntu 18.04 LTS (Bionic Beaver).
It will be supported until 2023. It comes with updated software and brings refinements and many new features to make your desktop even more comfortable to use.
Linux Mint 19.2 features with Cinnamon 4.2, Linux kernel 4.15, and Ubuntu 18.04 package base.
**`Note:`**` ` Dont forget to take backup of your important data. If something goes wrong you can restore the data from the backup after fresh installation.
Backup can be done either rsnapshot or timeshift.
Linux Mint 19.2 “Tina” Release notes can be found in the following link.
* **[Linux Mint 19.2 (Tina) Release Notes][1]**
There are three ways that we can upgrade to Linux Mint 19.2 “Tina”.
* Upgrade Linux Mint 19.2 (Tina) Using Native Method
* Upgrade Linux Mint 19.2 (Tina) Using Mintupgrade Utility
* Upgrade Linux Mint 19.2 (Tina) Using GUI
### How to Perform The Upgrade from Linux Mint 19.1 (Tessa) to Linux Mint 19.2 (Tina)?
Upgrading the Linux Mint system is an easy and painless task. It can be done three ways.
### Method-1: Upgrade Linux Mint 19.2 (Tina) Using Native Method
This is one of the native and standard method to perform the upgrade for Linux Mint system.
To do so, follow the below procedures.
Make sure that your current Linux Mint system is up-to-date.
Update your existing software to latest available version using the following commands.
### Step-1:
Refresh the repositories index by running the following command.
```
$ sudo apt update
```
Run the following command to install the available updates on system.
```
$ sudo apt upgrade
```
Run the following command to perform the available minor upgrade with in version.
```
$ sudo apt full-upgrade
```
By default, it will remove obsolete packages by running the above command. However, i advise you to run the below commands.
```
$ sudo apt autoremove
$ sudo apt clean
```
You may need to reboot the system, if a new kernel is installed. If so, run the following command.
```
$ sudo shutdown -r now
```
Finally check the currently installed version.
```
$ lsb_release -a
No LSB modules are available.
Distributor ID: Linux Mint
Description: Linux Mint 19.1 (Tessa)
Release: 19.1
Codename: Tessa
```
### Step-2: Update/Modify the /etc/apt/sources.list file
After reboot, modify the sources.list file and point from Linux Mint 19.1 (Tessa) to Linux Mint 19.2 (Tina).
First backup the below config files using the cp command.
```
$ sudo cp /etc/apt/sources.list /root
$ sudo cp -r /etc/apt/sources.list.d/ /root
```
Modify the “sources.list” file and point to Linux Mint 19.1 (Tina).
```
$ sudo sed -i 's/tessa/tina/g' /etc/apt/sources.list
$ sudo sed -i 's/tessa/tina/g' /etc/apt/sources.list.d/*
```
Refresh the repositories index by running the following command.
```
$ sudo apt update
```
Run the following command to install the available updates on system. During the upgrade you may need to confirm for service restart and config file replace so, just follow on-screen instructions.
The upgrade may take some time depending on the number of updates and your Internet speed.
```
$ sudo apt upgrade
```
Run the following command to perform a complete upgrade of the system.
```
$ sudo apt full-upgrade
```
By default, the above command will remove obsolete packages. However, i advise you to run the below commands once again.
```
$ sudo apt autoremove
$ sudo apt clean
```
Finally reboot the system to boot with Linux Mint 19.2 (Tina).
```
$ sudo shutdown -r now
```
The upgraded Linux Mint version can be verified by running the following command.
```
$ lsb_release -a
No LSB modules are available.
Distributor ID: Linux Mint
Description: Linux Mint 19.2 (Tina)
Release: 19.2
Codename: Tina
```
### Method-2: Upgrade Linux Mint 19.2 (Tina) Using Mintupgrade Utility
This is Mint official utility that allow us to perform the smooth upgrade for Linux Mint system.
Use the below command to install mintupgrade package.
```
$ sudo apt install mintupgrade
```
Make sure you have installed the latest version of mintupgrade package.
```
$ apt version mintupgrade
```
Run the below command as a normal user to simulate an upgrade and follow on-screen instructions.
```
$ mintupgrade check
```
Use the below command to download the packages necessary to upgrade to Linux Mint 19.2 (Tina) and follow on screen instructions.
```
$ mintupgrade download
```
Run the following command to apply the upgrades and follow on-screen instructions.
```
$ mintupgrade upgrade
```
Once upgrade done successfully, Reboot the system and check the upgraded version.
```
$ lsb_release -a
No LSB modules are available.
Distributor ID: Linux Mint
Description: Linux Mint 19.2 (Tina)
Release: 19.2
Codename: Tina
```
### Method-3: Upgrade Linux Mint 19.2 (Tina) Using GUI
Alternatively, we can perform the upgrade through GUI.
### Step-1:
Create a system snapshot through Timeshift. If anything goes wrong, you can easily restore your operating system to its previous state.
### Step-2:
Open the Update Manager, click on the Refresh button to check for any new version of mintupdate and mint-upgrade-info. If there are updates for these packages, apply them.
Launch the System Upgrade by clicking on “Edit-&gt;Upgrade to Linux Mint 19.2 Tina”.
[![][2]![][2]][3]
Follow the instructions on the screen. If asked whether to keep or replace configuration files, choose to replace them.
[![][2]![][2]][4]
### Step-3:
Once the upgrade is finished, reboot your computer.
--------------------------------------------------------------------------------
via: https://www.2daygeek.com/upgrade-linux-mint-19-1-tessa-to-linux-mint-19-2-tina/
作者:[2daygeek][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: http://www.2daygeek.com/author/2daygeek/
[b]: https://github.com/lujun9972
[1]: https://www.linuxtechnews.com/linux-mint-19-2-tina-released-check-what-is-new-feature/
[2]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
[3]: https://www.2daygeek.com/wp-content/uploads/2019/08/linux-mint-19-2-tina-mintupgrade.png
[4]: https://www.2daygeek.com/wp-content/uploads/2019/08/linux-mint-19-2-tina-mintupgrade-1.png

View File

@ -0,0 +1,302 @@
[#]: collector: (lujun9972)
[#]: translator: (MjSeven)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Learn object-oriented programming with Python)
[#]: via: (https://opensource.com/article/19/7/get-modular-python-classes)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
使用 Python 学习面对对象的编程
======
使用 Python 类使你的代码变得更加模块化。
![Developing code.][1]
在我上一篇文章中,我解释了如何通过使用函数、创建模块或者两者一起来[使 Python 代码更加模块化][2]。函数对于避免重复多次使用的代码非常有用,而模块可以确保你在不同的项目中复用代码。但是模块化还有另一种方法:类。
如果你已经听过 _面对对象编程_ 这个术语,那么你可能会对类的用途有一些概念。程序员倾向于将类视为一个虚拟对象,有时与物理世界中的某些东西直接相关,有时则作为某种编程概念的表现形式。无论哪种表示,当你想要在程序中为你或程序的其他部分创建“对象”时,你都可以创建一个类来交互。
### 没有类的模板
假设你正在编写一个以幻想世界为背景的游戏,并且你需要这个应用程序能够涌现出各种坏蛋来给玩家的生活带来一些刺激。了解了很多关于函数的知识后,你可能会认为这听起来像是函数的一个教科书案例:需要经常重复的代码,但是在调用时可以考虑变量而只编写一次。
下面一个纯粹基于函数的敌人生成器实现的例子:
```
#!/usr/bin/env python3
import random
def enemy(ancestry,gear):
    enemy=ancestry
    weapon=gear
    hp=random.randrange(0,20)
    ac=random.randrange(0,20)
    return [enemy,weapon,hp,ac]
def fight(tgt):
    print("You take a swing at the " + tgt[0] + ".")
    hit=random.randrange(0,20)
    if hit &gt; tgt[3]:
        print("You hit the " + tgt[0] + " for " + str(hit) + " damage!")
        tgt[2] = tgt[2] - hit
    else:
        print("You missed.")
foe=enemy("troll","great axe")
print("You meet a " + foe[0] + " wielding a " + foe[1])
print("Type the a key and then RETURN to attack.")
while True:
    action=input()
    if action.lower() == "a":
        fight(foe)
    if foe[2] &lt; 1:
        print("You killed your foe!")
    else:
        print("The " + foe[0] + " has " + str(foe[2]) + " HP remaining")
```
**enemy** 函数创造了一个具有多个属性的敌人,例如祖先、武器、生命值和防御等级。它返回每个属性的列表,表示敌人全部特征。
从某种意义上说,这段代码创建了一个对象,即使它还没有使用类。程序员将这个 "enemy" 称为 _对象_,因为该函数的结果(本例中是一个包含字符串和整数的列表)表示游戏中一个单独但复杂的 _东西_。也就是说,列表中字符串和整数不是任意的:它们一起描述了一个虚拟对象。
在编写描述符集合时,你可以使用变量,以便随时使用它们来生成敌人。这有点像模板。
在示例代码中,当需要对象的属性时,会检索相应的列表项。例如,要获取敌人的祖先,代码会查询 **foe[0]**,对于生命值,会查询 **foe[2]**,以此类推。
这种方法没有什么不妥,代码按预期运行。你可以添加更多不同类型的敌人,创建一个敌人类型列表,并在敌人创建期间从列表中随机选择,等等,它工作得很好。实际上,[Lua][3] 非常有效地利用这个原理来近似面对对象模型。
然而,有时候对象不仅仅是属性列表。
### 使用对象
在 Python 中,一切都是对象。你在 Python 中创建的任何东西都是某个预定义模板的 _实例_。甚至基本的字符串和整数都是 Python **type** 类的衍生物。你可以在这个交互式 Python shell 中见证:
```
&gt;&gt;&gt; foo=3
&gt;&gt;&gt; type(foo)
&lt;class 'int'&gt;
&gt;&gt;&gt; foo="bar"
&gt;&gt;&gt; type(foo)
&lt;class 'str'&gt;
```
当一个对象由一个类定义时它不仅仅是一个属性的集合Python 类具有各自的函数。从逻辑上讲,这很方便,因为只涉及某个对象类的操作包含在该对象的类中。
在示例代码中fight 代码是主应用程序的功能。这对于一个简单的游戏来说是可行的,但对于一个复杂的游戏来说,世界中不仅仅有玩家和敌人,还可能有城镇居民、牲畜、建筑物、森林等等,他们都不需要使用战斗功能。将战斗代码放在敌人的类中意味着你的代码更有条理,在一个复杂的应用程序中,这是一个重要的优势。
此外,每个类都有特权访问自己的本地变量。例如,敌人的生命值,除了某些功能之外,是不会改变的数据。游戏中的随机蝴蝶不应该意外地将敌人的生命值降低到 0。理想情况下即使没有类也不会发生这种情况。但是在具有大量活动部件的复杂应用程序中确保不需要相互交互的部件永远不会发生这种情况这是一个非常有用的技巧。
Python 类也受垃圾收集的影响。当不再使用类的实例时,它将被移出内存。你可能永远不知道这种情况会什么时候发生,但是你往往知道什么时候它不会发生,因为你的应用程序占用了更多的内存,而且运行速度比较慢。将数据集隔离到类中可以帮助 Python 跟踪哪些数据正在使用,哪些不在需要了。
### 优雅的 Python
下面是一个同样简单的战斗游戏,使用了 Enemy 类:
```
#!/usr/bin/env python3
import random
class Enemy():
    def __init__(self,ancestry,gear):
        self.enemy=ancestry
        self.weapon=gear
        self.hp=random.randrange(10,20)
        self.ac=random.randrange(12,20)
        self.alive=True
    def fight(self,tgt):
        print("You take a swing at the " + self.enemy + ".")
        hit=random.randrange(0,20)
        if self.alive and hit &gt; self.ac:
            print("You hit the " + self.enemy + " for " + str(hit) + " damage!")
            self.hp = self.hp - hit
            print("The " + self.enemy + " has " + str(self.hp) + " HP remaining")
        else:
            print("You missed.")
        if self.hp &lt; 1:
            self.alive=False
# 游戏开始
foe=Enemy("troll","great axe")
print("You meet a " + foe.enemy + " wielding a " + foe.weapon)
# 主函数循环
while True:
   
    print("Type the a key and then RETURN to attack.")
       
    action=input()
    if action.lower() == "a":
        foe.fight(foe)
               
    if foe.alive == False:
        print("You have won...this time.")
        exit()
```
这个版本的游戏将敌人作为一个包含相同属性(祖先,武器,生命值和防御)的对象来处理,并添加一个新的属性来衡量敌人时候已被击败,以及一个战斗功能。
类的第一个函数是一个特殊的函数,在 Python 中称为 \_init\_ 或初始化函数。这类似于其他语言中的[构造器][4],它创建了类的一个实例,你可以通过它的属性和调用类时使用的任何变量来识别它(示例代码中的 **foe**)。
### Self 和类实例
类的函数接受一种你在类之外看不到的新形式的输入:**self**。如果不包含 **self**那么当你调用类函数时Python 无法知道要使用的类的 _哪个_ 实例。这就像在一间充满兽人的房间里说:“我要和兽人战斗”,向一个兽人发起。没有人知道你指的是谁,所以坏事就发生了。
![Image of an Orc, CC-BY-SA by Buch on opengameart.org][5]
CC-BY-SA by Buch on opengameart.org
类中创建的每个属性都以 **self** 符号作为前缀,该符号将变量标识为类的属性。一旦派生出类的实例,就用表示该实例的变量替换掉 **self** 前缀。使用这个技巧,你可以在一间满是兽人的房间里说:“我要和祖先是 orc 的兽人战斗”,这样来挑战一个兽人。当 orc 听到 "gorblar.orc" 时,它就知道你指的是谁(他自己),所以你得到是一场公平的战斗而不是争吵。在 Python 中:
```
gorblar=Enemy("orc","sword")
print("The " + gorblar.enemy + " has " + str(gorblar.hp) + " remaining.")
```
通过检索类属性而不是查询 **foe[0]**(在函数示例中)或 **gorblar[0]** 来寻找敌人(**gorblar.enemy** 或 **gorblar.hp** 或你需要的任何对象的任何值)。
### 本地变量
如果类中的变量没有以 **self** 关键字作为前缀,那么它就是一个局部变量,就像在函数中一样。例如,无论你做什么,你都无法访问 **Enemy.fight** 类之外的 **hit** 变量:
```
&gt;&gt;&gt; print(foe.hit)
Traceback (most recent call last):
  File "./enclass.py", line 38, in &lt;module&gt;
    print(foe.hit)
AttributeError: 'Enemy' object has no attribute 'hit'
&gt;&gt;&gt; print(foe.fight.hit)
Traceback (most recent call last):
  File "./enclass.py", line 38, in &lt;module&gt;
    print(foe.fight.hit)
AttributeError: 'function' object has no attribute 'hit'
```
**hi** 变量包含在 Enemy 类中,并且只能“存活”到在战斗种发挥作用。
### 更模块化
本例使用与主应用程序相同的文本文档中的类。在一个复杂的游戏中,我们更容易将每个类看作是自己独立的应用程序。当多个开发人员处理同一个应用程序时,你会看到这一点:一个开发人员处理一个类,另一个开发主程序,只要他们彼此沟通这个类必须具有什么属性,就可以并行地开发这两个代码块。
要使这个示例游戏模块化,可以把它拆分为两个文件:一个用于主应用程序,另一个用于类。如果它是一个更复杂的应用程序,你可能每个类都有一个文件,或每个逻辑类组有一个文件(例如,用于建筑物的文件,用于自然环境的文件,用于敌人或 NPC 的文件等)。
将只包含 Enemy 类的一个文件保存为 **enemy.py**,将另一个包含其他内容的文件保存为 **main.py**
以下是 **enemy.py**
```
import random
class Enemy():
    def __init__(self,ancestry,gear):
        self.enemy=ancestry
        self.weapon=gear
        self.hp=random.randrange(10,20)
        self.stg=random.randrange(0,20)
        self.ac=random.randrange(0,20)
        self.alive=True
    def fight(self,tgt):
        print("You take a swing at the " + self.enemy + ".")
        hit=random.randrange(0,20)
        if self.alive and hit &gt; self.ac:
            print("You hit the " + self.enemy + " for " + str(hit) + " damage!")
            self.hp = self.hp - hit
            print("The " + self.enemy + " has " + str(self.hp) + " HP remaining")
        else:
            print("You missed.")
        if self.hp &lt; 1:
            self.alive=False
```
以下是 **main.py**
```
#!/usr/bin/env python3
import enemy as en
# game start
foe=en.Enemy("troll","great axe")
print("You meet a " + foe.enemy + " wielding a " + foe.weapon)
# main loop
while True:
   
    print("Type the a key and then RETURN to attack.")
    action=input()
    if action.lower() == "a":
        foe.fight(foe)
    if foe.alive == False:
        print("You have won...this time.")
        exit()
```
导入模块 **enemy.py** 使用了一条特别的语句,将类文件名称作为引用而不是 **.py** 扩展名,后跟你选择的命名空间指示符(例如,**import enemy as en**)。这个指示符是在你调用类时在代码中使用的。你需要在导入时添加指定符,例如 **en.Enemy**,而不是只使用 **Enemy()**
所有这些文件名都是任意的,尽管在原则上并不罕见。将应用程序的中心命名为 **main.py** 是一个常见约定,和一个充满类的文件通常以小写形式命名,其中的类都以大写字母开头。是否遵循这些约定不会影响应用程序的运行方式,但它确实使经验丰富的 Python 程序员更容易快速理解应用程序的工作方式。
在如何构建代码方面有一些灵活性。例如,使用代码示例,两个文件必须位于同一目录中。如果你只想将类打包为模块,那么必须创建一个名为 **mybad** 的目录,并将你的类移入其中。在 **main.py** 中,你的 import 语句稍有变化:
```
from mybad import enemy as en
```
两种方法都会产生相同的结果,但如果你创建的类足够通用,你认为其他开发人员可以在他们的项目中使用它们,那么后者是更好的。
无论你选择哪种方式,都可以启动游戏的模块化版本:
```
$ python3 ./main.py
You meet a troll wielding a great axe
Type the a key and then RETURN to attack.
a
You take a swing at the troll.
You missed.
Type the a key and then RETURN to attack.
a
You take a swing at the troll.
You hit the troll for 8 damage!
The troll has 4 HP remaining
Type the a key and then RETURN to attack.
a
You take a swing at the troll.
You hit the troll for 11 damage!
The troll has -7 HP remaining
You have won...this time.
```
游戏启动了,它现在更加模块化了。现在你知道了面对对象的应用程序意味着什么,但最重要的是,当你向兽人发起决斗的时候,你要想清楚。
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/7/get-modular-python-classes
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[MjSeven](https://github.com/MjSeven)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_development_programming.png?itok=M_QDcgz5 (Developing code.)
[2]: https://opensource.com/article/19/6/get-modular-python-functions
[3]: https://opensource.com/article/17/4/how-program-games-raspberry-pi
[4]: https://opensource.com/article/19/6/what-java-constructor
[5]: https://opensource.com/sites/default/files/images/orc-buch-opengameart_cc-by-sa.jpg (CC-BY-SA by Buch on opengameart.org)

View File

@ -0,0 +1,137 @@
[#]: collector: "lujun9972"
[#]: translator: "furrybear"
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
[#]: subject: "How to create a pull request in GitHub"
[#]: via: "https://opensource.com/article/19/7/create-pull-request-github"
[#]: author: "Kedar Vijay Kulkarni https://opensource.com/users/kkulkarnhttps://opensource.com/users/fontanahttps://opensource.com/users/mhanwellhttps://opensource.com/users/mysentimentshttps://opensource.com/users/greg-p"
如何在Github上创建一个拉取请求
======
学习如何复刻一个仓库,进行更改,并要求维护人员审查并合并它
![a checklist for a team][1]
所以,你知道如何使用 git。 你有一个 [GitHub][2] 仓库并且可以向它推送。这 一切都很好。 但是你如何为他人的 GitHub 项目做出贡献? 这是我在学习 git 和 GitHub 之后想知道的。在本文中,我将解释如何复刻一个 git 仓库、进行更改并提交一个拉取请求。
当你想要在一个 GitHub 项目上工作时,第一步是复刻一个仓库。
![Forking a GitHub repo][3]
你可以使用[我的演示仓库][4]试一试.
一旦在这个页面,单击右上角的 Fork 复刻按钮。这将在你的GitHub用户账户下创建我的演示仓库的一个新副本其统一资源定位符如下
```
`https://github.com/<你的用户名>/demo`
```
这个副本包含了原始仓库中的所有代码,分支和提交。
接下来,打开你计算机上的终端并运行命令来克隆仓库:
```
`git clone https://github.com/<你的用户名>/demo`
```
一旦仓库被克隆后,你需要做两件事:
1. 通过发出命令创建一个新分支 `new_branch`
```
`git checkout -b new_branch`
```
2. 使用以下命令为上游仓库创建一个新的远程( remote
```
`git remote add upstream https://github.com/kedark3/demo`
```
在这种情况下,“上游仓库”指的是你创建复刻来自的原始仓库。
现在你可以更改代码了。 以下代码创建一个新分支,进行任意更改,并将其推送到 **new_branch** 分支:
```
$ git checkout -b new_branch
Switched to a new branch new_branch
$ echo “some test file” &gt; test
$ cat test
Some test file
$ git status
On branch new_branch
No commits yet
Untracked files:
  (use "git add &lt;file&gt;..." to include in what will be committed)
    test
nothing added to commit but untracked files present (use "git add" to track)
$ git add test
$ git commit -S -m "Adding a test file to new_branch"
[new_branch (root-commit) 4265ec8] Adding a test file to new_branch
 1 file changed, 1 insertion(+)
 create mode 100644 test
$ git push -u origin new_branch
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 918 bytes | 918.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
Remote: Create a pull request for new_branch on GitHub by visiting:
Remote:   <http://github.com/example/Demo/pull/new/new\_branch>
Remote:
 * [new branch]         new_branch -&gt; new_branch
```
一旦你将更改推送到您的仓库后, **Compare &amp; pull request比较和拉取请求** 按钮将出现在GitHub。
![GitHub's Compare & Pull Request button][5]
单击它,你将进入此屏幕:
![GitHub's Open pull request button][6]
单击 **Create pull request创建拉取请求** 按钮打开一个拉取请求。 这允许仓库的维护者们审查你的贡献。 从这个页面,如果你的贡献是好的,他们可以合并它,或者他们可能会要求你做一些改变。
### 太长,别看
总之,如果您想为一个项目做出贡献,最简单的方法是:
1. 找到您想要贡献的项目
2. 复刻它
3. 将其克隆到你的本地系统
4. 建立一个新的分支
5. 进行你的更改
6. 将其推送回你的仓库
7. 单击**Compare &amp; pull request比较和拉取请求**按钮
8. 单击**Create pull request创建拉取请求**以打开一个新的拉取请求
如果审阅者要求更改请重复步骤5和6为你的拉取请求添加更多提交。
快乐编码!
在之前的一篇文章中,我讨论了在...期间针对GitHub的投诉。
Arfon Smith在GitHub工作并在开放的十字路口参与了许多活动......
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/7/create-pull-request-github
作者:[Kedar Vijay Kulkarni][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/kkulkarnhttps://opensource.com/users/fontanahttps://opensource.com/users/mhanwellhttps://opensource.com/users/mysentimentshttps://opensource.com/users/greg-p
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/checklist_hands_team_collaboration.png?itok=u82QepPk "a checklist for a team"
[2]: https://github.com/
[3]: https://opensource.com/sites/default/files/uploads/forkrepo.png "Forking a GitHub repo"
[4]: https://github.com/kedark3/demo
[5]: https://opensource.com/sites/default/files/uploads/compare-and-pull-request-button.png "GitHub's Compare & Pull Request button"
[6]: https://opensource.com/sites/default/files/uploads/open-a-pull-request_crop.png "GitHub's Open pull request button"

View File

@ -0,0 +1,145 @@
[#]: collector: "lujun9972"
[#]: translator: "FSSlc"
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
[#]: subject: "How To Verify ISO Images In Linux"
[#]: via: "https://www.ostechnix.com/how-to-verify-iso-images-in-linux/"
[#]: author: "sk https://www.ostechnix.com/author/sk/"
如何在 Linux 中验证 ISO 镜像
======
![如何在 Linux 中校验 ISO 镜像][1]
刚才为了你最为喜爱的 Linux 发行版,你从它的官方网站或第三方网站下载了它的 ISO 镜像,接下来做啥呢?是[**创建可启动介质**][2]并开始安装系统吗?并不是,请稍等一下。在开始使用它之前,强烈建议你检查一下你刚下载到本地系统中的 ISO 文件是否是下载镜像站点中 ISO 文件的一个精确拷贝。因为在前几年 [Linux Mint 的网站被攻破了][3],并且攻击者创建了一个包含后门的经过修改的 Linux Mint ISO 文件。 所以验证下载的 Linux ISO 镜像的可靠性和完整性是非常重要的一件事儿。假如你不知道如何在 Linux 中验证 ISO 镜像,本次的简要介绍将给予你帮助,请接着往下看!
### 在 Linux 中验证 ISO 镜像
我们可以使用 ISO 镜像的校验和来验证 ISO 镜像。校验和是一系列字母和数字的组合,用来检验下载文件的数据是否有错以及验证其可靠性和完整性。当前存在不同类型的校验和,例如 SHA-0、SHA-1、SHA-2224、256、384、512和 MD5。MD5 校验和最为常用,但对于现代的 Linux 发行版SHA-256 最常被使用。
我们将使用名为 `gpg``sha256` 的两个工具来验证 ISO 镜像的可靠性和完整性。
##### 下载校验和及签名
针对本篇指南的目的,我将使用 Ubuntu 18.04 LTS 服务器 ISO 镜像来做验证,但对于其他的 Linux 发行版应该也是适用的。
在靠近 Ubuntu 下载页的最上端,你将看到一些额外的文件(校验和及签名),正如下面展示的图片那样:
![Ubuntu 18.04 的校验和及签名][4]
其中名为 **SHA256SUMS** 的文件包含了这里所有可获取镜像的校验和,而 **SHA256SUMS.gpg** 文件则是这个文件的 GnuPG 签名。在下面的步骤中,我们将使用这个签名文件来 **验证** 校验和文件。
下载 Ubuntu 的 ISO 镜像文件以及刚才提到的那两个文件,然后将它们放到同一目录下,例如这里的 **ISO** 目录:
```
$ ls ISO/
SHA256SUMS SHA256SUMS.gpg ubuntu-18.04.2-live-server-amd64.iso
```
如你所见,我已经下载了 Ubuntu 18.04.2 LTS 服务器版本的镜像,以及对应的校验和文件和签名文件。
##### 下载有效的签名秘钥
现在,使用下面的命令来下载正确的签名秘钥:
```
$ gpg --keyid-format long --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x46181433FBB75451 0xD94AA3F0EFE21092
```
示例输出如下:
```
gpg: key D94AA3F0EFE21092: 57 signatures not checked due to missing keys
gpg: key D94AA3F0EFE21092: public key "Ubuntu CD Image Automatic Signing Key (2012) <[email protected]>" imported
gpg: key 46181433FBB75451: 105 signatures not checked due to missing keys
gpg: key 46181433FBB75451: public key "Ubuntu CD Image Automatic Signing Key <[email protected]>" imported
gpg: no ultimately trusted keys found
gpg: Total number processed: 2
gpg: imported: 2
```
##### 验证 SHA-256 校验和
接下来我们将使用签名来验证校验和文件:
```
$ gpg --keyid-format long --verify SHA256SUMS.gpg SHA256SUMS
```
下面是示例输出:
```
gpg: Signature made Friday 15 February 2019 04:23:33 AM IST
gpg: using DSA key 46181433FBB75451
gpg: Good signature from "Ubuntu CD Image Automatic Signing Key <[email protected]>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: C598 6B4F 1257 FFA8 6632 CBA7 4618 1433 FBB7 5451
gpg: Signature made Friday 15 February 2019 04:23:33 AM IST
gpg: using RSA key D94AA3F0EFE21092
gpg: Good signature from "Ubuntu CD Image Automatic Signing Key (2012) <[email protected]>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 8439 38DF 228D 22F7 B374 2BC0 D94A A3F0 EFE2 1092
```
假如你在输出中看到 `Good signature` 字样,那么该校验和文件便是由 Ubuntu 开发者制作的,并且由秘钥文件的所属者签名认证。
##### 检验下载的 ISO 文件
下面让我们继续检查下载的 ISO 文件是否和所给的校验和相匹配。为了达到该目的,只需要运行:
```
$ sha256sum -c SHA256SUMS 2>&1 | grep OK
ubuntu-18.04.2-live-server-amd64.iso: OK
```
假如校验和是匹配的,你讲看到 **OK** 字样,这意味着下载的文件是合法的,没有被改变或篡改过。
假如你没有获得类似的输出,或者看到不同的输出,则该 ISO 文件可能已经被修改过或者没有被正确地下载。你必须从一个更好的下载源重新下载该文件。
某些 Linux 发行版已经在它的下载页面中包含了校验和。例如 **Pop!_os** 的开发者在他们的下载页面中提供了所有 ISO 镜像的 SHA-256 校验和,这样你就可以快速地验证这些 ISO 镜像。
![Pop os 位于其下载页面中的 SHA256 校验和][5]
在下载完 ISO 镜像文件后,可以使用下面的命令来验证它们:
```
$ sha256sum Soft_backup/ISOs/pop-os_18.04_amd64_intel_54.iso
```
示例输出如下:
```
680e1aa5a76c86843750e8120e2e50c2787973343430956b5cbe275d3ec228a6 Soft_backup/ISOs/pop-os_18.04_amd64_intel_54.iso
```
![Pop os 的 SHA256 校验和的值][6]
在上面的输出中,以 **680elaa…** 开头的部分为 SHA-256 校验和的值。请将该值与位于下载页面中提供的 SHA-256 校验和的值进行比较,如果这两个值相同,那说明这个下载的 ISO 文件是合法的,与它的原有状态相比没有经过更改或者篡改。万事俱备,你可以进行下一步了!
上面的内容便是我们如何在 Linux 中验证一个 ISO 文件的可靠性和完整性的方法。无论你是从官方站点或者第三方站点下载 ISO 文件,我们总是推荐你在使用它们之前做一次简单的快速验证。希望本篇的内容对你有所帮助。
**参考文献:**
* [**https://tutorials.ubuntu.com/tutorial/tutorial-how-to-verify-ubuntu**][7]
--------------------------------------------------------------------------------
via: https://www.ostechnix.com/how-to-verify-iso-images-in-linux/
作者:[sk][a]
选题:[lujun9972][b]
译者:[FSSlc](https://github.com/FSSlc)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.ostechnix.com/author/sk/
[b]: https://github.com/lujun9972
[1]: https://www.ostechnix.com/wp-content/uploads/2019/07/Verify-ISO-Images-In-Linux-720x340.png
[2]: https://www.ostechnix.com/etcher-beauitiful-app-create-bootable-sd-cards-usb-drives/
[3]: https://blog.linuxmint.com/?p=2994
[4]: https://www.ostechnix.com/wp-content/uploads/2019/07/Ubuntu-18.04-checksum-and-signature.png
[5]: https://www.ostechnix.com/wp-content/uploads/2019/07/Pop-os-SHA256-sum.png
[6]: https://www.ostechnix.com/wp-content/uploads/2019/07/Pop-os-SHA256-sum-value.png
[7]: https://tutorials.ubuntu.com/tutorial/tutorial-how-to-verify-ubuntu