目录
- 第二周内容总结
第二周内容总结
一、剩余的部分数据类型讲解
元组
元组又叫做不能改变数据值的列表,之所以这么叫是因为元组的内部所绑定的数据值的内存地址不能改变,所以对外形成了数据值不能变的形式,但是这里有一个特例,当元组内绑定了一个列表的时候,我们会发现列表的数据值是可以修改的。这里需要结合后面的可变类型和不可变类型的知识点来理解,因为列表是可变类型,数据值改变但是内存地址不会发生改变,所以可以在绑定到元组内部后修改数据值
集合
集合内的数据值跟字典一样没有顺序,但是可以遍历。集合用的较少,主要应用于两组数据的去重和关系运算。
空集合的定义:set()
布尔值
用于判断逻辑结果
只有两个值:True(对)或False(否)
二、用户交互
用户交互有两个方法:
1、input()
用于接收外部的信息输入。比如当我们在登陆的时候需要输入账号密码,我们输入的信息就是通过input()接收的。
2、print()
用于输出数据。依旧是登陆的时候,如果用户输入了信息,正确的时候我们需要给他们返回登陆成功,信息错误的时候也要有相应的提示,我们可以用print()把我们想说的提示打印出来让用户看到。
三、格式化输出
格式化输出的关键符号是%,%后面跟不同的字符有不同的意思,比如我们在%后面跟d是格式化输出整数,%s是格式化输出字符串。由于字符串格式下可以格式化输出所有数据类型所以以后大部分情况都是使用%s。
使用方法:
print('I am %s' % 'jason')
这里我们以%s为例子进行举例,我们可以在想要输出的内容中用%s替代想要插入的输出内容,并在后方跟上%和需要插入的内容就可以得到'I am jason'。当前面的字符串中出现多个%s的时候,后方的数据值也要有相应的个数,并且数据值会根据从左往右的顺序依次插入到前面的字符串中替换%s。
四、运算符号
1、基本运算符之数学运算符
+、-、*、/、**(乘方)、%(取余数)、//(整除)、=(这里跟数学中的意思不一样,是赋值的意思)
由于代码中容易出现a = a + 1的形式,所以我们会吧代码写成a +=1的意思,其他运算符号也是类似的写法。
2、基本运算符之比较运算符
>\>=\<\<=\==(等于号的意思)\!=(不等于)
这里需要注意,当我们使用比较运算符的时候返回的都是布尔值类型的数据值。
3、赋值符号及用法
所谓赋值符号就是'='号,但是它的用法跟我们平时的认知不一样,所谓复制符号就是把符号右边的部分先做计算然后把得到的值赋予给左边的变量名。
用法:
除了上面所出现的表现方式,当我们给复制符号两边的变量名和数据值绑定的关系的时候可以简化过程。
1.链式赋值(同一数据值绑定给不同的变量名)
这里我们可以采用一下形式:
name = name1 = name2 = 'jason'
2.交叉赋值
通过上面的赋值符号的相关知识点我们得知,当我们想给两个变量互换数据值的时候不能用以前的数学中的思维方式来表达了。举例:
# 定义两个变量:a = 11,b = 22,当我们想要把两个变量绑定的数据值互换的时候,需要用一个中间变量临时存储数据值。
cha = a
a = b
b = cha
# 这里是给大家展现运算的时候怎么交换数据值的,实际使用的时候可以采用简写的方式
a,b = b,a
3.解压赋值
解压赋值跟链式赋值有点相似,但不一样。解压赋值是把多个数据值分别赋值给不同的变量名。举例:
# 这里我们定义一个内部有多个数据值的列表,并把内部的数据值分别赋予不同的变量名。
l1 = [1,2,3,4,5]
num1, num2, num3, num4, num5 = l1
# 然后我们拓展一些其他使用方法,当我们使用解压赋值的时候,正常情况下也要做到变量名和数据值的个数相对应,但是当数据值很多的时候我只想要开头或结尾的数据,就可以用变量名前面加*的形式来达成
num6, num7,*num8, num9 = l1
# 当我们运行程序打印结果的时候,我们可以看到num8中有3和4两个数据值。
4、成员运算符
成员运算符返回的值是布尔值类型
in
用于判断一个变量绑定的值或数据值是否在另一个变量绑定的值或数据值内也存在
# 这里我们拿字符串举例
st = 'jason'
st1 = 'j'
st2 = 'ja'
print(st1 in st)
print(st2 in st)
# 运行这些代码
not in
跟in的用法相反,判断数据值是不是不在指定的对象中
5、身份运算符
is
当我们使用is方法把两个数据值进行对比,会返回布尔值的数据值,is方法是比较两个进行对比的数据值内存地址是否相同(这里需要跟上面的号进行区别,号是比较数据值是否一样)。这里需要拓展一个函数:id()可以返回数据值的内存地址。
a= ['jason', 'kevin', 'oscar', 'jerry']
b= ['jason', 'kevin', 'oscar', 'jerry']
print(a == b)
#会返回True
print(a is b)
#会返回False
小整数池
这里我们看到返回的是False,所以有人会好奇什么时候会返回True呢?这里就需要引入一个知识点:小整数池。当我们使用python解释器运行python代码的时候,解释器会进行一些优化,把数据值位数小的一些的,数据值一样的部分数据类型绑定在同一个内存地址。(列表、字典、集合不行)
# 整形:较短的可以
a1 = 11
a2 = 11
print(a1 is a2)
#浮点型:较短的可以
a3 = 11.11
a4 = 11.11
print(a3 is a4)
#字符串:较短的可以
a5 = 'jason'
a6 = 'jason'
print(a5 is a6)
#列表:无论长短都不可以
a7 = [1,2,3]
a8 = [1,2,3]
print(a7 is a8)
#字典:无论长短都不可以
a9 = {'name' : 'zzh','age' : '21'}
a10 = {'name' : 'zzh','age' : '21'}
print(a9 is a10)
#元组:较短的可以
a11 = (1,2,3)
a12 = (1,2,3)
print(a11 is a12)
#集合:无论长短都不可以
a13 = {1,2}
a14 = {1,2}
print(a13 is a14)
ps:当我们使用pycharm的时候我们会发现小整数池的优化范围变得更大了,这是pycharm软件对代码的优化。
not is
作用与is相反,返回的也是布尔值
6、逻辑运算符及优先级
and、or、not的优先级
当我们使用三个逻辑运算符的时候我们需要用小括号来划定运行的先后顺序,但是由于有些情况我们会遇到没有小括号的代码,这时候就会用到优先级。这里的优先级是not > and > or。
and
连接and两边的条件,需要两边都成立的时候才会返回数据值或返回True,如果都不成立就返回第一个不成立的条件。输出的结果时最后一个条件的值或最后一个数据值
or
当or两边有一边的条件成立的时候就会返回对应的数据值或返回True,如果都不成立就返回最后一个不成立的条件,都成立也是返回第一个成立的条件。
not
返回相反的值,主要出现在布尔值的判断中。
is_example = True
print(not is_example)
五、垃圾回收机制
当我们使用变量名绑定数据值后,如果在使用过程中切断了两者的联系,那么就需要把这个数据值从内存空间中清除,节省内存空间。在一些语言中需要程序员自己编写代码删除不需要的数据值,但python中有专门的垃圾回收机制我们只需要了解他是怎么运行的就可以了。
1、引用计数
当我们给一个数据值跟一个变量绑定引用关系后,我们称这个数据值当前的引用计数就变成了一,当中断关系的时候就变成了零,变成零的时候,python解释器中的垃圾回收机制就会删除这个数据值。
2、循环引用(标记清除)
这里说的是一种特殊情况:当两个列表互相添加对方到列表内后,除了绑定变量名获得的一次引用计数,互相引用也给两个列表各自增加了一次引用计数。但是当我们取消两个变量名的绑定后,两个列表仍然有一次引用计数。这时候python解释器不会清楚他们,但是当这样的情况变多了之后,直到内存空间用完了,python代码就会停止运行,并开始检测这些循环引用的数据值,并对他们打上标记,一次性清除,这个过程就叫做标记清除。
3、分代回收
当我们的python解释器根据数据值的引用计数检测并清除的时候,如果频繁检测会非常的消耗内存资源,因此有了分代回收机制。这里我们把所有数据值分成三代:新生代、青春代、老年代。所有的数据值在刚创建的时候都处于新生代中,当中的一些数据值在经过一段时间的检测后引用次数反而变多的就会分配到青春代中,青春代中的数据值检测频率会降低。当青春带中的数据值经过一段时间的检测,引用次数依旧变多的对象,就会分配到老年代中,老年代中的数据值则是很久才会检测一次。
六、流程控制理论和基础知识
流程控制就是控制程序运行方向的东西,用来体现人的逻辑关系的思考。
它主要分成三种流程:顺序结构、分支结构、循环结构
基础知识:
1、在流程结构的运行中,我们使用在代码前面加入空格的形式来表示主从关系,通常我们使用四个空格(一次tab键)来表示主从关系,但是一个空格也是可以达成主从关系的,缩进少的代码或是没有缩进的代码会是下方缩进多的代码的父代码。
2、同一从属关系的代码需要有相同的缩进。
3、不是所有的代码都可以拥有子代码的,通常来说可以拥有子代码的代码,末尾会有一个冒号,并且子代码要根据父代码所表示的流程结构运行,并不再是顺序结构,只有进入对应的流程条件下才会顺序执行条件下的子代码。
break和continue方法
当我们运行代码的时候会出现如果得到了正确的结果就停止循环,或重新开始下一次循环,这时候就会用到break和control方法。
两个方法的生效范围:
虽然两个代码作用强大,但是有各自的生效范围,并不能在出现嵌套循环的时候一次结束所有的循环,两者只能作用到自己所在的那个循环以及那个循环外层的一个循环。
七、流程控制之分支结构
分支结构就是用于达成我们人根据不同条件做不同事情的一种结构,分支结构一次只会走一个分支。分支结构的关键字是if,if有多种表现形式如:单if分支,if...else分支,if...elif...else分支。通常来说if的表达式都是if+条件的形式。
if结构展示:
#这里换个例子
#吃饭
#输入有多少钱
money_have = int(input('请输入数字'))
#判断这些钱能干嘛
if money_have > 15:
print('吃的比较一般')
elif money_have > 30:
print('吃的很好')
else:
print('不够吃饭呐')
if的嵌套
分支结构的嵌套使用相对循环结构更容易看懂,我们只需要记住分支结构的代码一次只能走一个分支就可以根据条件得到正确的执行顺序。
八、流程控制之循环结构
循环结构可以看成流水线工人的工作,当满足条件的情况下会一直重复执行,不满足条件则停止或不运行。
1、while循环结构
while结构下满足条件会一直运行下方的子代码。while循环结构也有多种表现形式如:while、while...else,这里需要对else用法做一个说明,当不满足条件后else下方所属的子代码相当于一组顺序代码,并不会重复。通常来说while的表达式都是while+条件的形式。
# while...else
#依旧是上面的例子,增加一些功能
#先输入拥有的钱的数量
a = int(input('请输入数字'))
#这里就进行判断了,可以看成出去玩一次要花100,不足500就不能去玩了。
while a > 500:
print('我们想去哪就去哪')
a -= 100
else:
print('没钱什么都做不了')
while 的嵌套使用
在while结构中添加while结构我建议把代码模块化,根据主从关系拆解成一块块后再进行仔细研究,能更快的理解代码的运行顺序
while 的死循环
当我们写代码的时候如果出现了while条件一直符合的情况,代码就会永久运行,直到人为干预让他停止,如果内部的代码运行的时候占用的内存资源很多的时候,比如对数据值使用乘法或是乘方的时候,占用的资源会不断变多,直到电脑死机为止,程序才会停止运行,这时候电脑会明显发热,但是当我们重启电脑后一切又会恢复正常。但是当以后我们的代码在服务器中运行的时候,容易出现服务器着火或是爆炸的情况,因此我们要避免出现while 的死循环。
全局标志位
通过上面的知识点我们了解到当出现多层嵌套的时候,需要使用多个break或continue才能达成我们的目的,但是我们也可以使用变量名绑定条件的方式,在内部循环中改变变量名的值来打到直接停止循环的过程。
2、for循环结构
for循环结构跟while 有所不同,当for循环走完一遍会自动停止,不会出现无线循环的情况。根据这个特性,我们也把for循环称作遍历.for循环也有两种表现形式:单for和for...else。工作情况下我们比较容易在爬虫方面使用for循环,例如上课的时候找网页规律用for循环打印出所有的网址。
for循环的结构也和while不同:for 变量名 in 变量名或range():
当我们使用变量名的时候会把变量名中绑定的数据值一个个取出来使用,使用range的时候则是定义一个范围从中取出数据值使用。
for结构展示:
for 变量名 in 需要遍历的对象:
表达式
else:
表达式
range()方法
range方法在上文说了是一个产生一定范围数据值的作用。它的括号内部可以加入参数,当我们只写一个数值的时候表示从零开始到那个数为止的整数,一个个取出来使用,但是末尾的数并不会被取到。同时也可以加入两个参数,中间用逗号隔开,前面表示起始位置后面表示结束位置,结束为止依旧是取不到的。同时还有三种参数的写法,前面两个参数作用一样,但是最后那个参数表示取值的方向和步幅。但是在方向相反的时候需要确保起始为止的数值大于结束为止,方向为正则相反。
python2和3中的range方法区别
python2中有range方法和xrange方法,其中range是直接产生一个列表,内部是取出的一个个数据值,而xrange则是相当于在内存中产生一个工厂,需要使用数据的时候才会产生有数据的列表,比较节约内存空间。python3中只有一个range,并且是跟xrange一个用法
九、数据类型内置方法理论
所谓内置方法就是数据类型内部自带的一些快捷方法,能让我们比较容易的达成某种操作。
两种表现形式:方法名()、需要使用方法的对象.方法名()
十、数据类型内置方法之整形
1、类型转换——int()
把其他类型的数据值转换成整形
需要注意只有浮点型、字符串可以转换成整形,字符串内部不能有除了数字之外的字符。浮点型就是砍了小数点和后面的部分只显示前面的部分。
2、进制转换
int()方法除了转换数据类型的作用外,还可以把其他进制数的数据值转换成十进制,这里也介绍一下转换其他进制数的方法名称。
bin()转换成二进制,并且转换后的数值开头是0b
oct()转换成八进制,并且转换后的数值开头是0o
hex()转换成十六进制,并且转换后的数值开头是0e
如果是整形的数据值互相转换前面必须有代表进制数的符号,如果是字符串的转换过程中可以不写在前面,但是要在后面标出是几进制。代码演示:
x = '1010'
y = '12'
z = 'a'
print(int("0b1100100", 2))
print(int("0o144", 8))
print(int("0x64", 16))
print(int(x, 2))
print(int(y, 8))
print(int(z, 16))
十一、数据类型内置方法之浮点型
1、类型转换——float()
我们可以把整形和字符串形式的数据值转换成浮点型,这里我们需要注意整形转换后只是在后方加了个小数点和零,并且字符串在转换的时候不能出现除了数字和小数点外的字符。
这里需要特别提醒一下,python对于数字的灵敏度其实不高,对于一些小数点后的值计算的并不准确,但是我们在后面使用模块就可以精确计算。
十二、数据类型内置方法之字符串
1、类型转换——str()
字符串可以把所有的类型都变成字符串类型的数据值
2、内置方法
1.索引取值和切片操作
字符串内部的字符排列是有顺序的,从0开始计数,我们可以根据每个字符的位置得到对应的字符。
a = 'strstr'
print(a[0])
# 这里取到第一个字符s
切片操作
我们可以在索引取值的中括号内加入其他数值来达到中间切片或是反着取值或是隔一个字符取一次值的操作
代码演示:
# 升级版本:切片取值
information = 'hello 猪猪男孩康世宏'
print(information[6:]) # 从6取到结尾
print(information[:6]) # 取到第六个就结束,第六个不取
print(information[:]) # 取所有的值
print(information[-1:]) # 从后往前取,从后往前取的时候
print(information[-5:-1]) # 用负的位置坐标取值,需要小的在前大的在后
print(information[6:10]) # 从第六个开始,取到10,但是取不到10的位置,只能到九
print(information[6:10:2]) # 从第六个开始,取到10,但是取不到10的位置,并且两个字符取一次
print(information[10:6:-1]) # 从第10个开始,取到6,但是取不到6的位置,是从后往前取
2.strip
格式:.strip(参数)
默认条件下会删除字符串首尾的空格,当我们输入参数后会在字符串前后查找我们输入的字符并删除。不删除中间的字符。
其他两种形式:.lstrip(参数)和.rstrip(参数)
这两个分别是删除左边和右边的空格或指定字符。
3.split
格式:.split(参数)
根据指定的字符把字符串切割,切割后的结果会放入列表中
4.改变字符串大小写和判断是否是大小写
upper、lower、isupper、islower
5.删除
①del
通用的删除方法
②remove
.remove('字符')
直接删除指定的字符,可以是多个
③pop
跟前面两个删除不同,可以得到被删除的那个数据值
.pop('a')
这里我们可以用变量获得删除的那个a字符
6.改
①索引取值后修改对应的字符
②replace
.replace()
使用的时候有三个参数,第一个参数是需要被替换的字符,第二个是替换进去的字符,第三个是需要替换的个数,默认情况下也就是不写第三个参数的情况下会替换所有的第一个字符
7.len()
统计字符串长度或字符串个数
8.count()
统计指定字符的出现次数
9.format
格式化输出占位符是{}
'字符{}字符'.format(字符,字符)
相对%形式的格式化输出更为方便,可以有多种表现形式如下:
①根据占位符的个数替换指定个数的字符。
'字符{}{}字符'.format(字符,字符)
②根据字符位置添加到指定的位置中,这里是根据索引的位置
'字符{1}{0}字符'.format(字符(位置0),字符(位置1))
③根据关键字替换
'字符{name}{age}字符'.format(name = ''字符'',age = ''字符'')
④关键字替换的简写方式
我们可以在输出格式化代码前获取需要的关键字内容
name = input()
age = input()
f'字符{name}{age}字符'
10.join
字符的拼接,可以跟split形成对比,两者作用相反
'中间用于拼接的字符'.join([字符,字符])
11.index
查找指定字符的索引位置,如果没这个字符会报错
12.find
查找指定字符的索引位置,如果没这个字符会返回None
13.isdigit
判断字符是否纯数字
14.判断字符串的开始或结尾
startswith和endswith
十三、数据类型内置方法之列表
1、类型转换——list()
列表可以把除了整形、浮点型、布尔值以外的类型转换成列表(可以遍历的数据类型),但是在转换字典类型的数据值的时候只能得到字典的key。
2、内置方法
1.索引取值和切片操作
列表跟字符串的索引取值相似,只是列表是以一个个数据值当一项,进行切片操作的时候也是一样的原理和规则
2.内置方法
①len()
统计列表的数据值个数
②count()
统计某个数据值出现的次数
③增
.append()
在括号内写入需要加进去的数据值,加入后数据值是加在最后面
.insert()
指定位置,插入数据值
.extend()
用于合并两个列表,写在括号内的列表会出现在后面
④删
del
通用的删除方法,跟字符串一样指定索引位置然后就可以删除了
.remove()
这里是直接删除指定的数据值,如果有多个就从左往右删除一个
.pop()
跟字符串的用法一样,可以获得那个被删除的值
⑤改
通常我们使用根据索引确定位置然后改当前位置数据值的方式来修改
⑥排序
.sort()
默认情况下会把列表中的数据值升序排列
如果想降序排列需要在括号内写上参数:reverse = True
⑦颠倒列表的前后顺序
.reverse()
⑧查找索引
index和find方法,用法刚字符串中的一样
十四、可变类型与不可变类型
在我们使用代码验证字符串和列表的各种内置方法的时候,我们发现查看结果的时候我们直接打印列表就可以看到结果,但是字符串那边需要连着变化的代码一起放进去打印才能看到变化后的结果,这里就涉及到可变类型和不可变类型了。像列表那样直接改变了数据值的我们叫它可变类型,从内存角度来说,就是内存地址没有变,但是数据值变了。而字符串可以理解成内存地址不发生改变,值也不改变,只是我们在用方法的时候产生了一个新的数据值。
十五、数据类型内置方法之字典
1、类型转换——dict()
字典类型的转换条件比较苛刻,因此通常我们都是自己生成字典
把字符串形式转换成字典
nfo = dict([['name', 'tony'], ('age', 18)])
# 如果我们想用dict方法转换字典,需要在括号内建立一个列表并在列表内建立两个列表分别放入键(key)和值(value),否则就报错。
print(nfo) # 输出结果:{'name': 'tony', 'age': 18}
2、内置方法
1.取值
通过key取值
由于字典内没有顺序,我们需要根据对应的key来得到对应的值,但是当我们的字典中没有这个键值对的时候会报错
通过get()方法取值
当我们查找的时候也可以用get方法取值,同样是在括号内输入key,如果有这个key就返回对应的值,如果没有就返回Nnoe
2.删除
①del
通用方法del,在del后方跟上字典的key就可以删除这对键值对
②pop
使用方法跟字符串相似,只是需要根据key来获得值,这个值也是key拿出来使用的
3.增加
形式跟字典键值对的修改是一样的,但是当键不存在的时候就会变成加入一个新的键值对
4.修改
由于字典是无序的,我们需要通过key来修改对应的值
但是当字典的值是一个列表的时候,我们可以使用append方法往列表中加入数据值
5.统计键值对的个数
count()方法,用法跟字符串一样
6.字典三剑客
三剑客获得的结果都是列表形式
keys
一次性获得所有的key值
values
一次性获得所有的值
items
一次获得所有的键值对
7.fromkeys
用于生成值相同键不同的列表如果值为列表,使用append添加数据值的时候会把所有的键都加上那个值
8.popitem
跟pop用法相似,但是popitem会获得一个键值对,把键和值放到一个元组中展示
十六、数据类型内置方法之元组
1、类型转换——tuple()
转换的数据类型跟列表一样,可以遍历的类型都可以转换
2、内置方法
1.索引取值和切片操作
跟列表的方法一样根据索引取值,括号内加入起始位置、结束位置、方向和步幅来取值、切片。
2.len()
计算元组内的数据值个数
3.count()
统计指定数据值的出现次数
4.index
返回搜索的值的索引位置,如果没有会报错
5.其他注意事项
1、由于元组是不能更改内部绑定的内存地址的,但是绑定一个列表进去的话,我们是可以修改列表的内存地址的
2、如果元组内部只有一个数据则需要在后面跟上逗号,否则就会变成数据值对应的数据类型
十七、数据类型内置方法之集合
1、类型转换——set()
可以把所有的不可变类型数据值转换成集合(元组、字典、字符串、整形),如果列表内部是纯数字也是可以转换的。
2、去重和关系运算
去重
当我们把一个内部有很多重复数据的列表转换成集合后,内部的重复数据值会消失。
关系运算
关系运算是用于两个集合之间的比较,一般是使用比较符号来进行运算,最后返回布尔值或数据值。
&
得到两个集合都有的数据值
得到第一个集合独有的数据值
^
得到两个列表中各自独有的数据值
|
得到两个集合所有的数据值
这些运算符都有对应的内置方法,只是使用运算符比较方便
3、内置方法
1、len
计算集合内的数据值个数
2、添加数据值
add()
在括号内加入需要键入的数据值,就会添加到集合中,由于集合没有顺序,所以这个数据值会随机出现在某个位置
update()
一次性向集合中加入多个数据值,也是没有顺序的
3、删除数据值
1.remove()
在括号内加入想要删除的数据值,可以指定删除
2.pop()
默认情况下会删除最后一个加进来的数据值,也可以自己指定需要删除的数据值,跟其他方法中的一样,可以获得这个数据值。
3.clear()
清空集合
4.discard()
在括号内加入想要删除的数据值,可以指定删除
十八、字符编码
1、概念讲解
字符编码就类似一个翻译本,如果我们需要读懂加密后的电报,就需要用翻译本翻译才能得到内容,计算机读懂我们的语言也需要一个这样的翻译本,我们称它为字符编码表
2、历史
初期
最初电脑是有美国人发明的,为了使用他们发明了ASCII码编码表,这个编码表只有一些字符和字母。其他国家的人如果想使用电脑只能学了ASCII码再使用电脑
中期
后来由于计算机的普及,各个国家都开发出了各自的编码表,比如中国的GBK
后期
为了方便各个国家之间的交流,开发出了全球通用的unicode万国码,并且随着时间一直在优化,产生了很多优化后的版本
3、使用介绍
我们可以在python中使用encode和decode来达成编码和解码的目的,后面的括号内需要加入你想使用的编码表名称,当我们解码的时候需要使用相同类型的编码表,否则会报错
python2和python3中的编码表区别
python3中默认使用的就是utf8编码,而python2中由于当时还没有unicode的出现,所以我们现在编写代码的时候需要在代码的最顶行加上编码类型# encoding:utf8,并且在文本或是字符串的前面需要加上一个字母u。