如果您想获取一个字符串数组并将这些字符串连接成一个大字符串,则可以使用join方法。实例:# 将由'a', 'b', 'c'字符组成的数组合并成一个字符串arr = ['a', 'b', 'c']arr.join# ---- 输出结果 ----"abc"也可以通多传递参数指定字符分隔符。实例:arr = ['a', 'b', 'c']arr.join("-")# ---- 输出结果 ----"a-b-c"
图片是文档中最长出现的媒体文件,是用来表达内容的最好载体之一。一篇文章通常可以增加头部的封面图、尾部的签名图等。实例 4:做一个类似图片预览的效果。#### 拼图九宫格![][img6]![][img5]![][img4]![][img3]![][img2]![][img1]![][img9]![][img8]![][img7][img1]: https://c-ssl.duitang.com/uploads/item/202004/10/20200410101433_eTTNZ.thumb.300_300_c.jpeg[img2]: https://c-ssl.duitang.com/uploads/item/202004/10/20200410101434_iWadw.thumb.300_300_c.jpeg[img3]: https://c-ssl.duitang.com/uploads/item/202004/10/20200410101434_Z3JVy.thumb.300_300_c.jpeg[img4]: https://c-ssl.duitang.com/uploads/item/202004/10/20200410101435_NiLkv.thumb.300_300_c.jpeg[img5]: https://c-ssl.duitang.com/uploads/item/202004/10/20200410101437_CxzYm.thumb.300_300_c.jpeg[img6]: https://c-ssl.duitang.com/uploads/item/202004/10/20200410101437_wdizF.thumb.300_300_c.jpeg[img7]: https://c-ssl.duitang.com/uploads/item/202004/10/20200410101438_J8vff.thumb.300_300_c.jpeg[img8]: https://c-ssl.duitang.com/uploads/item/202004/10/20200410101439_cVcLx.thumb.300_300_c.jpeg[img9]: https://c-ssl.duitang.com/uploads/item/202004/10/20200410101439_yhUv3.thumb.300_300_c.jpeg<style>img { width: 150px !important; height: 150px !important; border: 1px solid #EEE;}</style>渲染结果如下:图片来源于网络,版权归原作者所有
let target = {a: 1, b: 1};let source1 = {b: 2, c: 2};let source2 = {c: 3};Object.assign(target, source1, source2);console.log(target); // {a: 1, b: 2, c: 3}如果后面的源对象上有相同的值,后面的源对象会覆盖前面对象上的值,这一点需要注意。
在前面我们学习了很多种类的变量,每个变量都会有一种类型。但是如果我们需要定义一个变量,可以同时存储不同的类型的变量,那会在很多场合下很方便的使用。比如我们常见的通信录,里面会包含很多信息,比如姓名,电话号码,邮箱地址等信息。这里面就会涉及到整数,字符串等等。如果每个人建立的时候都分别声明一次其中的变量,那么工作量就会非常的大,也很容易出现错误。那么怎么解决这种情况呢?这就是今天我们要讲解的内容。
>>> import re>>> re.search('c$', 'abc')<_sre.SRE_Match object; span=(2, 3), match='c'>>>> re.search('c$', 'abcx')>>>在第 2 行,c$ 表示从字符串 ‘abc’ 的尾部进行匹配在第 3 行,显示匹配结果不为 None在第 4 行,c$ 表示从字符串 ‘xabc’ 的尾部进行匹配在第 5 行,显示匹配结果为 None
函数的定义使用关键字fun,函数参数格式为: “参数:类型”,函数返回值类型 fun(...): Int。这种声明函数参数、函数返回值类型方式正好与 Java 是相反的。//Kotlin定义fun sum(a: Int, b: Int, c: Int): Int { return a + b + c}//Java定义public int sum(int a, int b, int c) { return a + b + c;}
我相信大家都知道经典的多继承问题,俗称 “钻石继承问题”。我们用反证法,假设 Java/Kotlin 中支持类的多继承,一起来看个例子,对于 A 类中有一个 invoke 方法,B,C 两个类都去继承 A 类,然后 D 类去分别去继承 B,C 类。abstract class A { abstract fun invoke()}class B: A { override fun invoke() = println("B invoke")}class C: A { override fun invoke() = println("C invoke")}class D: B,C {//假设支持类的多继承 override fun invoke() = println("C invoke")// B ? C}那么问题就来了 D 类应该是继承 B 类 invoke 方法,还是 C 类 invoke 方法呢?所以这样类的多继承很容易带来歧义。但是我们知道在开发过程中还是可能遇到多继承的问题,我们一般常用的方法是采用接口多继承方式来解决,因为我们知道在 Java 和 Kotlin 中是支持接口的多继承的。
#include <stdio.h>int main(){ for (int i = 0; i < 10; i++) { printf("No. %d: Hello C Language!\n", i); } return 0;}运行结果:No. 0: Hello C Language!No. 1: Hello C Language!No. 2: Hello C Language!No. 3: Hello C Language!No. 4: Hello C Language!No. 5: Hello C Language!No. 6: Hello C Language!No. 7: Hello C Language!No. 8: Hello C Language!No. 9: Hello C Language!我们首先初始化一个用于循环控制的变量 i ,当然你看到的大多数编程书籍都会使用这个变量名,其实你可以使用任意你喜欢的变量名,这个变量名的作用域,也就是变量起作用的范围仅仅是在这个循环语句以及包括在紧挨着的大括号内,也就是我们经常提到的循环体内有效。在初始化用于控制循环的变量后,我们就要判断一下这个变量的初始值是不是满足循环条件,如果你的初始值不满足循环条件,那么后面的循环一次也不会被执行。这个和 do while 语句是完全不同的。如果满足循环条件,那么后面大括号中的语句就会被执行。这里我们执行的语句是输出一句话。在执行完大括号中的内容后,for 语句就会执行前面圆括号中的最后一个部分,也就是根据写入的语句改变循环控制变量的值。Tips:这里需要注意的是,控制循环变量的值不是在判断条件后马上改变,而是在执行完循环体中的内容后才发生改变。这点从上面实例程序中输出的序号中可以清晰地看到。
os.chdir(path) 的功能切换当前工作目录。该函数的使用示例:>>> import os>>> os.chdir('C:\\Windows')>>> os.getcwd()'C:\\Windows'
Set 实例上的数据可以使用 forEach 进行遍历:var set = new Set(['a', 'b', 'c'])set.forEach((item) => { console.log(item)})// a// b// c虽然在 Set 数据结构中没有索引的概念,但是 Set 提供了三个方法用于我们去遍历 Set 数据结构。方法名描述 values 得到 Set 实例中的值作为一个可以遍历的对象 keys 得到 Set 实例中的键作为一个可以遍历的对象,键和值相等 entries 得到 Set 实例中的键值作为一个可以遍历的对象通过这三种方法得到的是一个可迭代对象(后面的迭代器小节会具体介绍),看如下实例:var set = new Set(['a', 'b', 'c'])set.keys(); // SetIterator {"a", "b", "c"}set.values(); // SetIterator {"a", "b", "c"}set.entries(); // SetIterator {"a" => "a", "b" => "b", "c" => "c"}for(var [key, value] of set.entries()) { console.log(key, value)}// a, a// b, b// c, c从上面的代码中,使用这三个方法得到的数据可以被 for...of 进行遍历。而且这三个方法得到的数据是一个可以迭代的对象,对象上的键和值是相等的,这也是为什么 Set 中的数据是唯一的原因。
os.path.isdir(path) 判断文件是否为目录文件,该函数的使用示例:>>> import os>>> os.path.isdir('C:\\Windows\\notepad.exe')False>>> os.path.isdir('C:\\Windows')True
和 C、C++ 等编程语言相比,Python 程序的运行性能很差,这是 Python 语言最主要的缺点。例如,编写一个以数学计算为主的程序,完成相同功能的 Python 程序的运行性能只有 C 程序的千分之一左右。在实际的应用场景中,Python 的缺点并不会成为系统的瓶颈,原因如下:在应用领域中,程序运行时大部分时间进行的是 IO 处理,少部分时间进行数学计算。在 Web 后端开发中,Python 程序接受来自网络的请求,处理请求时读写数据库,最后将处理结果通过网络返回,大量的时间花费在网络 IO 和数据库 IO 上,因此 Python 的数学运算性能对程序的整体影响不大。发挥 C 语言和 Python 语言两者各自的优势,使用 C 语言完成对计算性能要求高的功能,使用 Python 语言封装 C 语言实现的功能模块。Python 的 NumPy (Numerical Python) 库,是一个针对矩阵运算的数学函数库,该库由 Python 语言和 C 语言混合开发而成:底层的数学运算功能由 C 语言实现,面向用户的接口使用 Python 语言实现。用户使用 Python 语言调用底层的 C 语言模块,从而兼顾了开发效率和运行效率。
使用split方法可以很容易地将字符串分割成字符数组:实例:string = "a b c d"string.split# ---- 输出结果 ----["a", "b", "c", "d"]默认情况下,split将使用空格作为分隔符,但是您可以将参数传递给此方法以指定其他分隔符。实例:# 将逗号作为分隔符string = "a,b,c,d"string.split(",")# ---- 输出结果 ----["a", "b", "c", "d"]
>>> x = {'a':'A', 'b':'B', 'c': 'C'}>>> del x['b']>>> x{'a':'A', 'c':'C'}在第 1 行,创建一个具有 3 个键值对的字典;在第 2 行,使用 del 语句从字典 x 中删除键 ‘b’ 对应的键值对;在第 3 行,显示删除后的字典;在第 4 行,删除一个键值对后,字典仅包含 2 个键值对。
interface Temperature { var temperature: Double}class CTemperature(override var temperature: Double) : Temperatureclass FTemperature(var cTemperature: CTemperature) : Temperature { override var temperature: Double get() = convertCelsiusToFahrenheit(cTemperature.temperature) set(temperatureInF) { cTemperature.temperature = convertFahrenheitToCelsius(temperatureInF) } private fun convertFToCelsius(f: Double): Double = (f - 32) * 5 / 9 private fun convertCToFahrenheit(c: Double): Double = (c * 9 / 5) + 32}fun main() { val cTemperature = CTemperature(0.0) val fTemperature = FTemperature(celsiusTemperature) cTemperature.temperature = 36.6 println("${cTemperature.temperature} C -> ${fTemperature.temperature} F") fTemperature.temperature = 100.0 println("${fTemperature.temperature} F -> ${cTemperature.temperature} C")}
os.sep 是 os 模块的导出变量,定义了文件路径名的分割符:在 linux 中,os.sep 等于 /在 windows 中,os.sep 等于 \os.sep 的用法如下:>>> import os>>> os.sep'\\'>>> 'C:\\Windows' + os.sep + 'Readme.txt''C:\\Windows\\Readme.txt'在第 4 行,使用 os.sep 将 ‘C:\Windows’ 和 ‘Readme.txt’ 连接形成一个新的路径。
os.path.join(*args) 接受可变数量的参数,将所有的输入参数使用路径分隔符连接,形成一个新的路径名。参数 *args,args 是可变参数返回值,返回由输入参数组成的新路径该函数的使用示例:>>> import os>>> os.path.join('C:\\Windows', 'Readme.txt')'C:\\Windows\\Readme.txt'>>> os.path.join('C:\\Windows', 'System32', 'Kernel.dll')'C:\\Windows\\System32\\Kernel.dll'在第 2 行,将 2 个字符串连接形成一个路径名在第 4 行,将 3 个字符串连接形成一个路径名
在 Go 语言中判断数组是否相等需要比较两个部分。一个是数组的长度是否相等,另一个是数组中存放的值是否顺序和大小完全相同。只要这两个部分相等,则 Go 语言中的两个数组就是相等的。Tips:Go 语言中只有类型相同的数组才可以互相比较,且数组没有大小的比较,只能比较是否相等。代码示例:package mainimport ( "fmt")func main() { var a [2]int var c = [2]int{1, 2} var d = [...]int{1, 2} fmt.Println("a == c ? ", a == c) fmt.Println("c == d ?", c == d)}第 11 行:比较数组 a 和数组 b 是否相等。两个数组长度相同,是存储的值不同,所以不相等;第 12 行:比较数组 c 和数组 d 是否相等。两个数组长度相同,且存储的值也相通,所以相等。执行结果:
算术运算符顾名思义,其就是进行加减乘除数值运算,在 shell 中,bash 不支持原生的数学运算,需要利用第三方工具来如 let,expr 等来实现。运算符说明举例+加法expr $a + $b 结果为 30。-减法expr $a - $b 结果为 -10。*乘法expr $a \* $b 结果为 200。/除法expr $b / $a 结果为 2。%取余expr $b % $a 结果为 0。=赋值a=$b 将把变量 b 的值赋给 a。==相等用于比较两个数字,相同则返回 true。 [$a == $b] 返回 false。!=不相等用于比较两个数字,不相同则返回 true。 [$a != $b] 返回 true。2.1.1 let可以利用 let 对数值进行运算,let C=$A+$B, 例如:[root@master ~]# A=1[root@master ~]# B=2[root@master ~]# let C=${A}+${B}[root@master ~]# echo $C3注意:let 运算后需要将其赋值给一个变量。2.1.2 expr可以利用 expr 对数组进行运算,C=$(expr $A+$B),例如:[root@master ~]# C=`expr $A + $B`[root@master ~]# echo $C3注意 + 号两边需要有空格,不然会将其当作字符串连接2.1.3 []可以利用 [] 来对数值进行运算,C=[A+B],例如:[root@master ~]# C=$[$A+$B][root@master ~]# echo $C32.1.4 (())利用 (()) 来对数值进行运算,C=$(($A+$B)),例如:[root@master ~]# C=$(($A+$B))[root@master ~]# echo $C3
在对象的解构中也可以使用剩余参数,对对象中没有解构的剩余属性做聚合操作,生成一个新的对象。var {a, c, ...rest} = {a: 1, b: 2, c: 3, d: 4}console.log(a); // 1console.log(c); // 3console.log(rest); // { b: 2, d: 4 }对象中的 b、d 没有被解构,通过剩余参数语法把没有解构的对象属性聚合到一起形成新的对象。
图片来源于网络
返回结果是一个二维数组,数组中的每个元素是一个包含两个元素的数组,第一个元素是属性,第二个元素是属性对应的值。var obj = {a: 1, b: 2, c: 3};console.log(Object.entries(obj))// [['a', 1], ['b', 3], ['c', 3]]如果传入的参数是数字或布尔值时,则返回一个空数组Object.entries(50) // []Object.entries(false) // []对 values() 返回数组的顺序,会按照属性的数值大小,从小到大排序。var obj = {10: 'a', 1: 'b', 7: 'c'};console.log(Object.entries(obj))// [["1", "b"], ["7", "c"], ["10", "a"]]上面的代码中,属性名为数值的属性,是按照数值大小,从小到大遍历的,因此返回值是一个排序后的二维数组。values() 传入的对象如果是一个字符串时,则会把字符拆成数组中的单个项,如下:console.log(Object.entries('abc'))// [["0", "a"], ["1", "b"], ["2", "c"]]
在 Go 语言中,使用 <- 符号来向通道中塞取数据。放在通道右边 chan <-,就是塞数据,放在通道左边 <- chan ,就是取数据。代码示例:func main() { c := make(chan int, 1) c <- 10 //将10塞入通道中 i := <-c //将10从通道中取出,并赋值给变量i fmt.Println(i)}执行结果:
numpy.ravel() 展平的数组元素,顺序通常是"C风格",返回的是数组视图(view),修改会影响原始数组。该函数接收两个参数:numpy.ravel(a, order='C')其中,order 可选:‘C’ – 按行,‘F’ – 按列,‘A’ – 原顺序,‘K’ – 元素在内存中的出现顺序。案例arr_r = np.ravel(arr0, order='C')展开结果为:arr_rout: array([0, 1, 2, 3, 4, 5, 6, 7])通过切片赋值的方法,显式地改变 arr_r 的值,查看 arr0 的变化:arr_r[0] = 100arr0out: array([[100, 1, 2, 3], [ 4, 5, 6, 7]])可以看到,虽然利用 ravel 方法对 arr0 进行了展开,但是对展开后的结果所做的修改,也会对应地出现在 arr0 上。
as 命令是用来重命名的,在使用 import 命令导入时可以使用 as 来更改变量名。// a.jslet a = 1;let b = 2;export { a, b,}// main.jsimport { a, b as y } from './a';console.log(a, y); // 1,2如果模块中同时有 export default 导出和 export 导出时,在导入时可以使用 as 对默认导出进行重命名。// a.jslet a = 1;let b = 2;export { a, b,}export default let c = 3;// main.jsimport { a, b, default as c } from './a'// 等价于下面直接在外面进行使用import c, { a, b } from './a'默认导出的内容也可以放在 export 导出的对象中,但是需要使用 as default 命令:// a.jslet a = 1;let b = 2;let c = 'imooc';export { a, b, c as default, // 相当于 export default 'imooc',给导出的对象增加一个default属性}
Go 语言还能直接在返回值处声明变量,这个变量的作用域是整个函数,并且会在 return 的时候直接返回。代码示例:package mainimport "fmt"func SumAndProduct(a, b int) (c int, d int) { c = a + b //因为c和d函数返回值处已经定义了,可以直接使用 d = a * b return //直接返回,c和d自动传出去}func main() { sum, product := SumAndProduct(1, 2) //接收多返回值的函数时,也需要用逗号隔开变量 fmt.Println("a + b =", sum) fmt.Println("a * b =", product)}执行结果:
ES6 允许按照一定模式,从数组和对象中提取值,并对变量进行赋值,这被称为解构(下节我们会讲到)。 比如如下代码:let array = [1, 2, 3]let [a, b, c] = array;console.log(a); // 1console.log(b); // 2console.log(c); // 3再比如如下代码:let obj = {a:1, b:2, c:3}let {a, b, c} = obj;console.log(a); // 1console.log(b); // 2console.log(c); // 3上面的两个例子,就是数组和对象的解构赋值过程,在解构赋值时,可以使用剩余操作符。剩余操作符所操作的变量会匹配在解构赋值中所有其他变量未匹配到的属性。看如下示例:let {a, b, ...others } = {a: 1, b: 2, c: 3, d: 4, e: 5}console.log(a); // 1console.log(b); // 2console.log(others); // {c: 3, d: 4, e: 5}上面的代码中,a、b 会匹配对象中对应的值,...others 则会收集匹配余下的属性值,并打包起来构造一个新的对象赋值给了 others。数组也可以通过剩余操作符,把剩余的元素打包成一个新的数组赋值给剩余属性,代码如下:let array = [1, 2, 3, 4, 5];let [a, b, ...others] = array;console.log(a); // 1console.log(b); // 2console.log(others); // [3,4,5]在函数传参的时候也可以是和解构一起使用。如下所示。function fun(...[a, b, c]) { return a + b + c;}fun('1') // NaN (b 和 c 都是 undefined)fun(1, 2, 3) // 6fun(1, 2, 3, 4) // 6 多余的参数不会被获取到上面的代码中,a、b、c 会去解构传入参数,加上有剩余语法的作用,对应的值从数组中的项解构出来,在函数内部直接使用解构出来的参数即可。剩余语法看起来和展开语法完全相同,不同点在于,剩余参数用于解构数组和对象。
集合是一个无序、不重复的序列,集合中所有的元素放在 {} 中间,并用逗号分开,例如:{1, 2, 3},一个包含 3 个整数的列表{‘a’, ‘b’, ‘c’},一个包含 3 个字符串的列表集合提供的最基本的操作有:使用 in 关键字检查元素是否在集合中>>> x = {'a', 'b', 'c'}>>> 'b' in xTrue>>> 'd' in xFalse在第 1 行,创建了一个包含 3 个字符串的集合。在第 2 行,检测字符串 ‘b’ 是否在集合中;第 3 行显示结果为 True。在第 4 行,检测字符串 ‘d’ 是否在集合中;第 5 行显示结果为 False。向集合中增加元素>>> x = {'a', 'b', 'c'}>>> x.add('d')>>> x{'a', 'b', 'c', 'd'}在第 1 行,创建了一个包含 3 个字符串的集合 x在第 2 行,向集合 x 增加一个元素 ‘d’在第 3 行,打印集合 x,结果表明集合中新增了一个元素从集合中删除元素>>> x = {'a', 'b', 'c'}>>> x.remove('c')>>> x{'a', 'b'}在第 1 行,创建了一个包含 3 个字符串的集合 x在第 2 行,从集合 x 删除一个元素 ‘c’在第 3 行,打印集合 x,结果表明集合中删除了一个元素
同样以表 course 和 teacher 内连接为例:SELECT c.id AS course_id,c.*,t.* FROM course c INNER JOIN teacher t ON c.teacher_id=t.id;执行结果如下图:Tips:INNER JOIN 为内连接,展示的是左右两表都有对应的数据。