赞
踩
清明节要完成的事情一直拖到了现在,虽然大部分都是基础,但终究是自己学到的!通过学习你会发现python的库真的是很多,就比如我现在正在学的爬虫,只要使用几个库基本上就算是入门了,当然深入还是需要自己的努力。对于我而言,python更多的是一种处理工具,它对很多的事件处理有着相当优秀的表现。希望在这条路上能越走越远,加油!当然了,也欢迎大家指出我的不足,一起学习。在这里奉献上我的个人博客:赵日天的暖心小窝
都是自己平时学习时候的一些总结,欢迎大佬们赐教。
首先在官网下载python版本,我在官网下载的是3.9.2版本。
安装python版本时,如果在最后没有勾选to path选项,则需要后面配置环境变量,我们在这里直接勾选 Add python 3.9.2 to path选项。
python安装好后可以在命令行cmd中输入python检查是否安装好,安装好后我们就可以在python自带的Python IDLE中直接运行python了,如果觉得不方便可以下载一些其它的编译器,比如PyCharm、K0modo、Eclipse、vscode等一些其它的适合自己的编译器。
Python代码的注释分为单行注释和多行注释,Python中单行注释中以#开头,如:
print("茅檐低下,溪上草青青。")
添加注释的目的是解释代码的功能和用途。注释可以出现在代码的任意位置,但是需要注意的是,注释不能分割关键字和标识符。例如:
aaa=float(#这是一个单行注释input("请输入商品的价格:"))
这句话在这里就是错误的。多行注释在python中用单引号 (’’’) 或者三个双引号(""")将注释括起来。
python中要注意代码缩进,如果代码的缩进是不正确的,那么就会产生编译错误。实现代码缩进的方法有两种,包括使用空格和键。通常一个键作为一个缩进量,4个空格代表一个即一个缩进。
在python中编写代码时,需要遵循以下规范:
①不能在行尾加分号;
②每行的字符数最多不超过80个,如果超过,建议使用小括号将多行的内容隐式连接起来;
③每个import语句只导入一个模块,尽量避免一次导入多个模块;
④尽量避免在循环中使用+和+=运算符进行累加字符串。
如果是Linux/UNTX操作系统,换行字符为ASCII LF(linfeed);如果是DOS/windows操作系统,换行字符为ASCII CR LF(return+linefeed);如果是Mac OS操作系统,换行字符为ASCII CR(return)。即我们在windows中操作时只需要像在C语言中换行一样输入 \n 即可。
如果程序代码超过一行,可以在每一行的结尾添加反斜杠(),继续下一行,这与C/C++的语法相同,需要注意的是,在 \ 之后不要加注释文字。
如果要将数行表达式写成一行,只需在原来除最后一行以外的每一行的结尾添加分号(;)即可,例如:
>>>a='苹果';b='香蕉';c='橙子'
>>> a
'苹果'
>>>b
'香蕉'
>>>c
'橙子'
标识符用来识别变量、函数、类、模块及对象的名称。标识符的第一个字符必须是字母表中的下划线或者下划线(_),并且变量名之间不能有空格。
保留字跟关键字都不能当作标识符,我们可以在cmd中查看Python的保留字
>>>import keyword
>>>keyword.kwlist
①变量名必须是一个有效的标识符。
②变量名不能和保留字冲突
③尽量选择有意义的单词作为变量名
④谨慎使用大写字母O和小写字母i
⑤变量赋值与C语言中一样采用(=)赋值
⑥Python的内置函数 type()用来直接查询变量所指的对象类型,与JavaScript中的typeof()用法相同,都可以用来查看变量类型。
python 3.X版本中有两个简单的基本数据类型,数字类型和字符串类型。
数字类型包括 int 、float、bool、complex(复数)。需要注意的是,数值的除法(/)总是会返回一个浮点数,要获取整数则需要使用 // 操作符
在Python中,字符串属于不可变序列,通常使用单引号、双引号或者三引号括起来。使用的方法没有多大差别,但是需要
注意的是单引号和双引号的字符序列必须在一行上,而三引号内的字符序列可以分布在连续的多行上。
数据类型的强制转换与C语言的使用方法相差无几,比如:int()、float()、str()
Python语言支持的运算符包括算术运算符、比较运算符、赋值运算符、逻辑运算符、位运算符、成员运算符和身份运算符
算数运算符有:+ - * / % ** // 其中加减乘模与C语言相同,**指的是幂运算,如:a**b指的是a的b次方,而//运算符则指的是返回相除后结果的整数部分,如 7//3得到2,这个与C语言中的除法相同,而在python中的除法则返回的是浮点数,这里与我们在C语言中所学是不同的,C语言返回的是整数,而在这里除法反水的是浮点数。
比较运算符有: == != > < >= <= 这些比较运算符与C语言中的均相同,它返回的是一个bool类型的值,true或者false
赋值运算符有: = += -= = /= %= **= //= 这里的运算过程与C语言中的基本相同,之前介绍过// 和//**所以在这里就不做过多解释。
逻辑运算符:and or not 这里与数字电路中的与、或、非 相同,取值也相同。
位运算符把数字当作二进制来进行计算。
它支持的运算符有
python语言还支持成员运算符,其测试例中包含了一系列的成员,如字符串、列表、元组。成员运算符包括in 和not in 。例如,x in y表示:若x在y序列中,则返回True;x not in y 表示:若 x 不在y序列中,则返回True。类似于JavaScript中的instanceof,用于判断前者是否属于后者的实例对象。
Python语言支持的身份运算符为is和not is。其中,is判断两个标识符是不是引用自一个对象:is not 判断两个标识符是不是引用自不同的对象。
in与in not 运算符应用于列表(list)。is运算符用于检查两个变量是否属于相同的对象;is not 运算符则用于检查两个变量是否不属于相同的对象。
input()用于输入数据,但是输入的内容都会被当作字符串来处理,所以当我们后面要对字符串的内容进行处理时经常需要对输入的内容进行强制类型转换
print( )函数可以输出格式化的数据,与C/C++语言的printf( )函数功能和格式相似。print( )函数的基本语法格式如下:
print(value,…,stp=’ ‘,end=’\n’) #此处只说明了部分参数。
在这里只介绍两个参数:stp和end。stp是用于设置多个要输出信息之间的分隔符,默认的分割符为一个空格,也就是我们用 ,表示的都会默认按照一个空格输出,当然我们也可以直接在print函数输出时对其进行修改。end参数用于print函数输出完所有信息后添加的符号,默认为换行符,我们也可以直接对其进行修改。这些极大地方便了我们的使用。
print( )在使用时有许多需要注意的地方。我们如果想一次性输出多个内容,而且不换行,可以将要输出的内容使用英文半角逗号隔开。
程序控制主要包括三个:顺序结构、选择结构、循环结构。基本上每种编程语言都有相同的控制结构,在这里就不做过多解释。
选择结构也叫做分支结构,用于处理在程序中出现两条或者跟多执行路径可供选择的情况。选择语句可以用分支语句来实现。分支语句主要为if语句。
if的使用方法与C语言的用法相同。不过需要注意的是if和elif以及else的后面都要加上冒号,以及elif和else不能单独存在,必须配合if语句一起使用。if和else同样也可以结合pass使用,比如当条件符合时我们不对其做任何操作,此时就可以使用pass语句。pass语句的使用主要是为了保持程序结构的完整性,pass不做任何事情,一般用作占位语句。
下面给出一个多重条件判断三角形的例子:
a=int(input("请输入三角形的第一条边:"))
b=int(input("请输入三角形的第二条边:"))
c=int(input("请输入三角形的第三条边:"))
if a==b and a==c:
print("等边三角形")
elif a==b or a==c or b==c:
print("等腰三角形")
elif a*a+b*b==c*c or a*a+c*c==b*b or b*b+c*c==a*a:
print("直角三角形")
else:
print("一般三角形")
bool表达式的结果只有true和false,True等价于1,False等价于0。我们可以使用type( )方法来查看true和false的类型,同样也可以使用bool( ) 函数将其他值转换为布尔类型。其它用法与JavaScript中的boolean用法是相同的,所以在这类不做过多介绍。
循环控制中的几个关键语句主要是:while和 for、continue和break以及else语句。
while语句与C语言中用法相同,但是for循环却不同。
for语句通常由条件控制和循环两部分组成。
for <variable> in <sequence>:
语句
else:
语句
其中 是一个变量名称;是一个列表,经常会搭配range( )函数进行数字遍历使用。else语句执行的时机是当fou语句都没有运行,或者最后一个循环已经运行时。else语句是可以省略的。
else语句在C语言中只可以和if搭配使用,但是在python中可以搭配for、while使用。它的执行时机是当for循环被执行完或者while循环条件为False时,else语句才会被执行。需要特别注意的是,如果循环被break语句提前终止,那么else语句不会被执行。
pass是空语句,主要是为了保持程序结构的完整性,pass不做任何事情,一般用作占位语句。
在这里需要介绍一下range( )函数。在使用range( )函数时,如果只有一个参数,那么表示指定的stop;如果有两个参数,则表示指定的start和stop,范围为[start,stop);如果三个参数都存在时,最有一个参数则是步长step。如果需要遍历数字序列,通常会用到range( )函数,解和循环控制语句,会达到事半功倍的作用。
Python中内置了5个常用的序列,即集合、列表、元组、字典和字符串
序列中的每个元素都有编号,也称为索引,索引从0开始。索引与我们在C语言数组中学到的相同,都是从0开始,使用方法也相同。值得注意的是,这里的索引支持负数,负数则是表示从右往左开始计数。采用负数作为索引时,是从 -1 开始的,也就是最右边的元素的下标为-1
访问序列元素还有另一种方式,那就是切片。它可以访问一定范围内的元素。通过切片操作可以生成一个新的序列。
sname[start,end:step]
sname表示序列的名称;start表示切片开始的位置,如果不指定则默认为0;end表示切片结束的位置,如果不指定,则默认为序列是序列的长度;step表示的是切片的步长,如果省略,则默认为1。
name=['张三','王五','张锋','马六','陈平']
names[1:5] #访问从从左边数第2到第五个
names[0:5:2]
['张三','张锋','陈平']
Python中切片的功能与JavaScript中的slice()方法很相似,在这里列出JavaScript的使用方法
通过 + 操作符,可以将两个序列相加。需要注意的是集合和字典不支持相加。 "+"操作符经常用于字符串和列表元素的组合
>>>x=[100,200,300]+[400,500,600]+[700,800,900]
>>>x
[100,200,300,400,500,600,700,800,900]
>>>y=['数学','英语','语文']
>>>z="我最喜欢的学科是"+y[1]
>>>print(z)
>>>我最喜欢的学科是英语
*号运算符经常用于重复列表中的元素,例如
>>>x=["数学","英语","语文"]*3
>>>x
["数学","英语","语文","数学","英语","语文","数学","英语","语文"]
in运算符通常用于判断一个元素是否存在于序列中,返回的是一个bool值,这个在我们之前的成员运算符中已经介绍过了。
集合(Sets)是一个无序不重复元素的集。它的主要功能是自动清除重复的元素。创建集合时用大括号{ }来包含其元素。如果当我们的集合中有重复元素时,就会将其自动删除。需要注意的是,如果我们想要创建一个空集合,必须使用 set( )函数
books=set{ } #正确创建空集合的方式
books={ } #错误创建集合的方式
列表是写在中括号之间,用逗号分开的元素表,类似于我们C语言中的数组。列表对象属于序数对象,是一群有序对象的集合,并且可以使用数字来作索引。列表对象可以进行新增、修改和删除的操作。这个与JavaScript中的数组属性基本上一样,可以包含不同类型的元素,但是在C语言中并不支持。同时列表对象也支持列表嵌套,即一个元素是另一个列表元素。
获取某个元素的索引值
使用列表对象的index©方法来返回元素的索引值,这在JavaScript中使用方法也相同
改变列表对象的元素值
可以通过索引到列表元素然后对其进行重新赋值
删除列表中的元素
使用del语句可以删除列表对象中的元素,例如:
>>>x=[100,'床前明月光',8.99,4+2j]
>>>del x[1]
>>>x
[100,8.99,(4+2j)]
这里的删除位置同样也支持负数,比如我们要删除最后一个元素,可以直接del x[-1]
如果我们想一次性清除所有元素,可以使用
del a[:]
列表的函数
列表内置的函数有许多,包括len( )、max( )、min( )和list( )……max和min可以直接返回列表中的最小值或最大值,但列表的元素数据类型必须一致才能使用,否则会报错。
列表的方法
想要查看列表有哪些内置的方法时只需要在Python中输入 dir([])就可以查看到了
append(object)
append()方法在列表对象的结尾,加上新对象object,这个方法与JavaScript中的push()方法相同,都是在列表结尾添加一个元素
clear()
clear()方法用于清空列表,类似于del a[:]
copy()
copy()方法用于复制列表,例如:
>>>a = [100,'床前明月光',8.99]
>>>b=a.copy()
>>>b
[100,'床前明月光',8.99]
count(value)
count(value)方法针对列表对象中的相同元素值value计算其数目。比如当我们的列表中有多个重复元素时,通过使用count()方法就可以得到列表中value的个数
extend(list)
extend(list)方法将参数list列表对象中的元素加到此表中,成为此列表的新元素,也就是直接将list中的所有元素全部添加到调用者的列表中。
index(value)
index(value)方法将列表对象中元素值的value的索引值返回。
insert(index,object)
insert(index,object)方法将在列表对象中索引值为index的元素之前插入新元素object
pop([index])
pop([index])方法将列表对象中索引值为index的元素删除。如果没有指定的index值,就将最后一个元素删除。在JavaScript中我们也有pop()方法,不过在JavaScript中一般用于删除最后一个元素,且返回值是被删除的那个元素。
remove(value)
remove(value)方法将列表对象中元素值为value的删除。它与pop()方法的不同在于,pop()删除时只知道所以,但是remove()删除时只知道元素值,但不知道索引。
reserve()
reverse()方法将列表对象中的元素颠倒排列。在JavaScript中也有这个方法,他们都是将列表中的元素进行颠倒。
sort()
sort()方法将列表对象中的元素依照大小顺序排列。在JavaScript中也有sort()方法,但是使用方法却不同。在JavaScript中sort()方法会将数组中的字符串按照字母顺序进行升序排序,如果我们要对数字数组进行排序的话还需要去构造方法。
元组对象属于序数对象,是一群有序对象的集合,并且可以使用数字来作索引。元组对象与列表的对象类型,差别在于元组对象不可以新增、修改和删除,同时元组使用小括号而列表则使用中括号。
元组的创建与使用都和列表中相同,但元组是固定的,即一旦创建就无法对其进行更改。其它的属性都与列表的属性相同。
元组的创建与列表的创建方法是相同的,但是需要注意的是如果想要创建只有一个元素的元组,那么在创建的元组之后必须要加一个逗号
>>> temp = ('我是你爸爸')
>>> type(temp)
<class 'str'>
#我们看到当不加逗号时数据类型为str,即字符串类型
>>> temp2 = ('pk哥',)
>>> type(temp2)
<class 'tuple'>
#加上逗号之后数据类型就变为元组了
之前说到元组一旦创建就是不可变的,所以我们在之后是无法在原元组上进行更改的,但是我们可以通过切片的方法以及拼接字符串的方法返回一个新元组。但是可以通过del()来删除该元组
字典类型在Python中充当着非常重要的作用,但是学过JavaScript的我看着字典这个类型总是十分亲切,因为这个类型与JavaScript中的对象是非常相似的。它们都以键值对的方式存在,但是JavaScript中对象前面的键是没有引号的。后来我发现Python中的对象与Json格式是完全一致的,这个可能会大大的方便python后期与数据进行交换。在同一个字典中,关键字必须互不相同,但是关键字对应的值可以相同。
修改字典中的元组值
只需要我们将字典中想要替换的键值对重新赋值即可
删除字典中的元素
使用del语句可以删除字典中的元素,例如:
>>>x = {'一班':'张小明','二班':'王二狗','三班':'张小明'}
>>>del x["三班"]
>>>x
{'一班':'张小明','二班':'王二狗'}
定义字典键值对时需要注意的问题
字典的内置函数
①len(dict):计算字典中元素的个数,即键值对的总数。
②str(dict):将字典的元素转换为可打印的字符串形式。
③type(variable):返回输入的变量类型,如果变量是字典,就返回字典类型。
字典的内置方法
clear(): 清除字典中的所有元素。
copy():复制字典的所有内容。
get(k,default=None) :k是字典的索引值。如果k存在,就返回其值,否则,返回后面的内容。另外需要注意的是如果字典中嵌套的有另外的字典那么则无法用get直接获取value值例如:
>>>x={'一班':'朱小明','二班':'王明霞'}
>>>x.get("一班")
'朱小明'
>>>x.get("三班","不存在")
'不存在'
items() :使用字典中的元素创建一个由元组对象组成的列表。
keys() :使用字典中的键值创建一个列表对象。也就是将字典中的所有键值存入一个新的列表中。
popitem():删除字典中的最后一个元素。也就是将字典中的最后一个键值对删除,它的返回值是被删除的键值对。Python和其它语言中,如果看到pop或者是其它的一些删除的函数,我们就需要注意它的返回值,返回值一般是被删除的元素。
字符串的重要性不言而喻,在之前学习JavaScript的过程中也有很多字符串的相关问题。在Python中,字符串的作用也非常大,因此需要不断地总结和学习。首先是字符串拼接,使用加号(+)运算符可以将两个字符串拼接起来,成为一个新的字符串。使用方法很简单,我们之前在java和JavaScript中都有接触到字符串的拼接,但是在这里字符串的拼接需要注意的是两者类型必须都是字符串,否则会报错,如果需要将字符串和其它类型的拼接在一起的话则需要对其它类型的变量进行强制类型转换,使用str()函数,让其成为字符串,然后再进行相加。
在Python语言中,数字、英文、小数点、下划线和空格各占1个字节。汉字可能会占2~4个字节,占几字节屈居用采用的编码格式。由于Python语言默认采用UTF-8编码,所以汉字占有3个字节。Python语言通过len( )函数计算字符串的长度,len( )在计算字符串长度时,并不区英文和中文,统统按照一个字符进行计算。如果用户需要获取字符串的实际所占字节数,就需要指定编码。然后才能获取实际的长度。
>>>s1="我今天需要参加English考试。" #包含了英文、中文和标点符号的字符串。
>>>ls=len(s1) #定义字符串的长度
>>> ls
17
#--------------------------
>>>s1="我今天需要参加English考试。" #包含了英文、中文和标点符号的字符串。
>>>ls=len(s1.encode()) #定义字符串的长度
>>> ls
37
在上面这段代码中,字符串共有9个汉字和一个中文标点符号,占30个字节,英文共有7个,所以结果为37。
与列表一样,索引都是从0开始。Python访问子字符串变量,可以使用中括号([])和冒号(:)来截取字符串。使用方法 : a[x,y]
截取的字符串从x索引位置开始,到y结束,它的范围为左闭右开,即[x,y)。如果没有x则代表从0开始,如果没有y,则代表从x开始,到结尾,如果想要截取字符串全部,则x和y都不用给值,者在之前的del中就用到过。
1.在Python语言中,通过split( )方法通过指定分隔符对字符串进行分割(切片),该方法的语法格式如下:
str.split(str="",num=string.count(str))
在JavaScript中也有split( )函数,它的第一个参数是一个分隔符或者是正则表达式,第二个参数表示分割后的数组的最大长度。本质上来说与python中的split效果是一样的。都是对字符串进行分割操作。
2.合并字符串
join( )方法用于将序列中的元素以指定的字符合并生成一个新的字符串,需要注意的是被合并的元素必须是字符串。
>>>s1="*"
>>>e1=('不','破','楼','兰','终','不','还')
>>>print(s1.join(e1))
不*破*楼*兰*终*不*还
在Python中字符串的大小写转换函数是upper( )和low( ),使用方法与JavaScript中的toLowerCase( )和toUpperCase( )的方法相同,所以在这里不做过多解释
strip( )方法
strip( )方法用于删除字符串头尾指定的字符或字符序列。需要注意的是该方法只能删除开头或结尾的字符,不能删除中间的字符。使用方法:str.strip([chars]),参数chars是需要删除的字符序列,默认情况下是空格。该方法的返回值为删除指定字符后生成的新字符串。
>>>str="*****茅檐**低小**,溪上青青草。*****"
>>>print(str.strip('*')) #会删除开头和结尾的'*'.
'茅檐**低小**,溪上草青青。'
lstrip( )方法
lstrip( )方法用于截掉字符串左边的空格或指定字符。如果未指定参数,则默认情况下是空格。这个就相当于strip( )的缩小版,只会删除字符串左边的字符。
rstrip( )方法
通过名字我们也可以看出,这个方法是以 ‘r’ 开头的,所以会删除字符串末尾的指定字符,默认情况下是空格。
有时候需要在字符串内设置单引号、双引号、换行符等,在此时就可以使用转义字符。Python的转义字符是由一个反斜杠()和一个字符组成
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8S8Yiiqt-1619075310151)(C:\Users\86134\AppData\Roaming\Typora\typora-user-images\image-20210402231633558.png)]](https://img-blog.csdnimg.cn/img_convert/c0769076fee50a3e378b0c67b0833d08.png#pic_cente
换行符,\n与我们在C语言中的使用方法相同,在双引号中直接输入就可实现换行。如果要输出双引号,则直接在双引号之前加上反斜杠() 就可以实现。各进制同样也可以使用。
在Python中,有两种常用的字符串类型,分别为str和bytes。其中,str表示Unicode字符;bytes表示二进制数。这两种类型的字符不能拼接在一起使用。一个字符对应若干个字节。如果在网上上传输或者保存在磁盘上,就需要把str转换成bytes类型,即字节型
str类型和bytes类型之间可以通过encode( )和decode( )方法进行转换,这两个方法的转换是可逆的。
#coding:utf-8 s = "你好,中国!" print(s) # Python2输出乱码,Python3正常输出 print(type(s)) # 均输出 <type 'str'> #解码成unicode s1 = s.decode("utf-8") print(s1) # Python2中输出 “你好,中国!”,Python3显示'str'对象没有属性'decode' print(type(s1)) # Python2中输出 <type 'unicode'> Python3中输出 <class 'str'> #编码成gbk 或 utf-8 s2 = s1.encode('gbk') print(s2) # Python2中输出 “你好,中国!” print(type(s2)) # Python2中输出 <type 'str'> s3 = s1.encode('utf-8') print(s3) # Python2输出乱码, print(type(s3)) # 输出 <type 'str'>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mLJ13SMq-1619075310156)(C:\Users\86134\AppData\Roaming\Typora\typora-user-images\image-20210402233012990.png)]
正则表达式是字符串,它包含文本和特殊字符。re模块可以执行正则表达式的功能。文字与特定字符的混合,可以定义复杂的字符串匹配与取代功能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rsjqv6BC-1619075310159)(D:\qq下载\MobileFile\qq_pic_merged_1617410899232.jpg)]
字符 | 描述 |
---|---|
\ | 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,‘n’ 匹配字符 “n”。’\n’ 匹配一个换行符。序列 ‘\’ 匹配 “” 而 “(” 则匹配 “(”。 |
^ | 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 ‘\n’ 或 ‘\r’ 之后的位置。 |
$ | 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 ‘\n’ 或 ‘\r’ 之前的位置。 |
* | 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。 |
+ | 匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。 |
? | 匹配前面的子表达式零次或一次。例如,“do(es)?” 可以匹配 “do” 或 “does” 中的"do" 。? 等价于 {0,1}。 |
{n} | n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。 |
{n,} | n 是一个非负整数。至少匹配n 次。例如,‘o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。‘o{1,}’ 等价于 ‘o+’。‘o{0,}’ 则等价于 ‘o*’。 |
{n,m} | m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,“o{1,3}” 将匹配 “fooooood” 中的前三个 o。‘o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。 |
? | 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 “oooo”,‘o+?’ 将匹配单个 “o”,而 ‘o+’ 将匹配所有 ‘o’。 |
. | 匹配除 “\n” 之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用象 ‘[.\n]’ 的模式。 |
(pattern) | 匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 ‘(’ 或 ‘)’。 |
(?:pattern) | 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 “或” 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 ‘industry|industries’ 更简略的表达式。 |
(?=pattern) | 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,‘Windows (?=95|98|NT|2000)’ 能匹配 “Windows 2000” 中的 “Windows” ,但不能匹配 “Windows 3.1” 中的 “Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern) | 负向预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如’Windows (?!95|98|NT|2000)’ 能匹配 “Windows 3.1” 中的 “Windows”,但不能匹配 “Windows 2000” 中的 “Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始 |
x|y | 匹配 x 或 y。例如,‘z|food’ 能匹配 “z” 或 “food”。’(z|f)ood’ 则匹配 “zood” 或 “food”。 |
[xyz] | 字符集合。匹配所包含的任意一个字符。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。 |
[^xyz] | 负值字符集合。匹配未包含的任意字符。例如, ‘[^abc]’ 可以匹配 “plain” 中的’p’。 |
[a-z] | 字符范围。匹配指定范围内的任意字符。例如,’[a-z]’ 可以匹配 ‘a’ 到 ‘z’ 范围内的任意小写字母字符。 |
[^a-z] | 负值字符范围。匹配任何不在指定范围内的任意字符。例如,’[^a-z]’ 可以匹配任何不在 ‘a’ 到 ‘z’ 范围内的任意字符。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。 |
\B | 匹配非单词边界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。 |
\cx | 匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。 |
\d | 匹配一个数字字符。等价于 [0-9]。 |
\D | 匹配一个非数字字符。等价于 [^0-9]。 |
\f | 匹配一个换页符。等价于 \x0c 和 \cL。 |
\n | 匹配一个换行符。等价于 \x0a 和 \cJ。 |
\r | 匹配一个回车符。等价于 \x0d 和 \cM。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
\t | 匹配一个制表符。等价于 \x09 和 \cI。 |
\v | 匹配一个垂直制表符。等价于 \x0b 和 \cK。 |
\w | 匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’。 |
\W | 匹配任何非单词字符。等价于 ‘[^A-Za-z0-9_]’。 |
\xn | 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,’\x41’ 匹配 “A”。’\x041’ 则等价于 ‘\x04’ & “1”。正则表达式中可以使用 ASCII 编码。. |
\num | 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,’(.)\1’ 匹配两个连续的相同字符。 |
\n | 标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。 |
\nm | 标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。 |
\nml | 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。 |
\un | 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。 |
re模块的主要功能是通过正则表达式来操作字符串。在使用re模块时,需要先引入re包。即 import re。
re模块中常见操作字符串的方法:
匹配字符串
通过re模块的match( )、search( )和findall( )方法可以匹配字符串。
①match( )。
match( )方法用于从字符串的开始处进行匹配,如果在起始位置匹配成功,则返回Match对象;如果不是在起始位置匹配成功,则返回None。match( ) 的语法格式为:
re.match(pattern,string,flags=0)
第一个参数为匹配的正则表达式,第二个参数为需要匹配的字符串,第三个参数哟关于控制正则表达式的匹配方式,如是否区分大小写,多行匹配等。例如我们要检验输入的手机号是否为中国移动的手机号:
第一个参数为匹配的正则表达式,第二个参数为需要匹配的字符串,第三个参数哟关于控制正则表达式的匹配方式,如是否区分大小写,多行匹配等。例如我们要检验输入的手机号是否为中国移动的手机号:
import re
print("欢迎进入中国移动电话号码验证系统")
s1=r'(13[4-9]\d{8})$|(15[01289]\d{8}$)'
s2=input("请输入需要验证的电话号码:")
match=re.match(s1,s2)
if match==None:
print("您输入的号码不是中国移动的号码")
else:
print("您输入的号码是中国移动的号码")
②search( )
search( )方法用于扫描整个字符串并返回第一个成功的匹配。参数与match的参数意义相同。但与match( )不同的是,search( )方法既可以在起始位置匹配,也可以不在起始位置匹配。
需要注意的是match( )方法只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而search( )方法匹配整个字符串,直到找到一个匹配项。
③findall( )
findall( )方法用于在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配项,则返回空列表。match( )和search( )只匹配一次,而findall( )方法匹配所有。findall( )语法格式:
findall(sting[,pos[,endpos]])
参数中string是待匹配的字符串,pos为可选参数,指定字符串的起始位置,默认为0;endpos为可选参数,指定字符串的结束位置,默认为字符串的长度。
替换字符串
通过re模块中的sub( )方法可以替换字符串中的匹配项。语法格式如下:
re.sub(pattern,repl,string,count=0,flags=0)
参数中pattern是正则表达式中的模式字符串;repl是要替换的字符串,也可以为一个函数;参数string要被查找替换的原始字符串;参数count是模式匹配后替换的最大次数,默认为0。
分割字符串
通过re模块中的split( )方法可以分割字符串。split( )方法按照能够匹配的子串将字符串分割后返回列表。语法格式如下:
re.split(pattern,string[,maxsplit=0,flags=0])
参数中pattern是正则表达式中的模式字符串;参数string为要被分割的字符串;参数maxsplit是分割次数,默认为0,不限制次数;参数flags用于控制正则表达式的匹配方式,如是否区分大小写、多行匹配等。
import re
s1="*张三丰*欧阳修*李白*颜真卿*齐白石"
pattern = r'\*'
ls = re.split(pattern,s1) #以*分割字符串
print("您的标星好友是:")
for(im in ls):
if im!=" ":
print(im)
Python语言支持格式化字符串的输出。字符串格式化使用字符串操作符百分号(%)来实现。在百分号左侧放一个代格式化的字符串(格式化字符串),右侧放置希望被格式化的值。可以使用一个值,如一个字符串或数字,也可以使用多个值的元组或字典。
age = 18
print("赵日天已经%d岁了!" % age)
#运行结果:
赵日天已经18岁了!
当然,格式化字符串也可以包含多个转换说明符,这个时候需要提供多个表达式,用以替换对应的转换说明符;多个表达式必须使用小括号( )括起来
name = "赵日天"
age = 18
url = "http://zx529.xyz"
print("%s已经%d岁了,它的网址是%s。" % (name, age, url))
#运行结果是:
赵日天已经18岁了,它的网址是http://zx529.xyz
下面的表中列举出Python语言中字符串格式化符号
其实在这里的格式化字符串与我们在C语言中学的比较接近,同时Python还支持指定最小输出宽度以及指定对齐方式、指定小数精度。
①指定最小输出宽度:
n = 1234567
print("n(10):%10d." % n)
print("n(5):%5d." % n)
url = "http://c.biancheng.net/python/"
print("url(35):%35s." % url)
print("url(20):%20s." % url)
使用表中的转换说明符,可以按照上面的格式指定最小输出宽度 。其中%10d表示输出的整数宽度至少为10.%20s 则表示输出的字符串宽度至少为20
②按照指定的小数精度输出:
f = 3.141592653
# 最小宽度为8,小数点后保留3位
print("%8.3f" % f)
# 最小宽度为8,小数点后保留3位,左边补0
print("%08.3f" % f)
# 最小宽度为8,小数点后保留3位,左边补0,带符号
print("%+08.3f" % f)
#输出的结果:
3.142
0003.142
+003.142
③在Python中可以指定对齐方式。
在默认情况下,print( )输出的数据总是右对齐的。也就是说,当数据的长度不够时,它总是右边对齐,而在左边补充空格来达到指定的宽度。Python允许在最小宽度之前增加一个标志来改变对齐方式,Python支持的标志如下:
整数、小数以及字符串的对齐方式是有区别的。必须要在不改变他们大小以及有意义的前提下进行对齐。对于整数,指定左对齐时,在右边补0是没有效果的,因为会改变它的大小;对于小数,以上三个标志可以同时存在;对于字符串,则只能使用 - 因为符号对于字符串没有意义,而补0则会改变字符串的值。代码举例如下:
n = 123456 # %09d 表示最小宽度为9,左边补0 print("n(09):%09d" % n) # %+9d 表示最小宽度为9,带上符号 print("n(+9):%+9d" % n) f = 140.5 # %-+010f 表示最小宽度为10,左对齐,带上符号 print("f(-+0):%-+010f" % f) s = "Hello" # %-10s 表示最小宽度为10,左对齐 print("s(-10):%-10s." % s) #运行结果为: n(09):000123456 n(+9): +123456 f(-+0):+140.500000 s(-10):Hello
在Python语言中,函数的创建需要使用def关键字,具体语法如下:
def 函数名称(参数1,参数2,……):
"文件字符串"
<语句>
Python语言的函数创建与我们之前在JavaScript中所学到的方法是一致的。def用于声明函数的创建,任何传入的参数和自变量必须放在小括号中间,小括号之间可以用于定于参数。函数的第一行语句可以选择性地使用文档字符串,用于存放函数说明。整体来说,Python的函数与JavaScript中的函数还是很相似的。
说起函数创建,它自然离不开函数的调用。先前一步的函数创建就是为了之后的函数调用准备。函数的调用与其它语言类似,直接使用函数名进行调用。但是在Python语言中,我们可以先将函数名称设置为变量,然后使用该变量运行函数的功能。例如:
>>>x= int
>>>x(3.1415926)
3
从结果中就可以看出,int( )函数是Python语言程序的内置函数,这里直接将函数名称设置为变量x,通过变量x即可直接运行该函数。
形参指的是在函数定义时出现的参数,可以被看作是一个占位符,它没有实际数据,只能等到函数被调用时接受传递进来的数据。
实参则指的是函数在被调用时,被传递进来的参数,是有实际数据的,即在内存中是开辟了地址的。
形参变量只有在函数被调用时参会分配内存,调用结束后立刻释放内存,所以形参变量只在函数内部有效,不能在函数外部使用。而实参在使用时必须要有确定的值,可以是常量、表达式、函数等 。形参和实参在形式和数量以及顺序上必须一致,否则会发生类型不匹配的错误。
参数的传递也分为两种,一种是值传递,另一种是引用传递,也可以理解为地址传递。它们之间的区别是,进行值传递后,如果改变形式参数的值,实参的值不变;进行引用传递后,如果改变形参的值,实参的值也会随着改变。而python中对一个函数可以传递参数,但是如何分辨是值传递还是引用传递,不是程序员手动控制的,而是python根据你传入的数据对象,自动识别的。
如果你传入的参数对象是可变对象:列表,字典,这个时候就是引用传递,如果参数在函数体内被修改,那么源对象也会被修改。
如果你传入的参数对象是不可变的对象:数字,元组,字符串,这个时候就是值传递。那么源对象是不会改变的。下面举例子说明:
import sys
a=2
b=[1,2,3]
def change(x,y):
x=3
y[0]=4
change(a,b)
print a,b
#输出结果是 2 [4, 2, 3]
可以看出数字作为一个不可变对象,a的值没有变化,而b作为列表对象,是可变对象,所以b被改变了。
import sys
a="11111"
b={"a":1,"b":2,"c":3}
def change(x,y):
x="222"
y["a"]=4
change(a,b)
print a,b
#输出结果是 11111 {'a': 4, 'c': 3, 'b': 2}
因为a作为字符串是不可变对象,所以没变化,b作为字典,是可变对象,所以被改变了
import sys
a=(1,2,3)
b={"a":1,"b":2,"c":3}
def change(x,y):
x="222"
y["a"]=4
change(a,b)
print a,b
#输出结果是 (1, 2, 3) {'a': 4, 'c': 3, 'b': 2}
Python中用户可以直接设置参数的名称及其默认值,这种类型的参数属于关键字参数。在设置函数的参数时,可以不按照它们的位置排列顺序,因为Python解释器能够用参数名匹配
fruits("苹果",12.6) #按照参数传入顺序传入
fruits(x="苹果",y=12.6) #按照参数传入顺序,并指定参数名
fruits(y=12.6,x="苹果") #不按照参数顺序传入参数,并指定参数名
以上这三种方法在Python中都是允许的。
调用参数时,若没有传入参数,则会抛出异常。但是可以为参数设置默认值来解决这个问题。例如:
def ns( name,score=660): #设置score的参数默认值为660
print("姓名:",name)
print("高考总分:",score)
return
ns(name="赵日天",score=586) #传递参数,不使用默认值
ns(name="雷军") #没有传递参数,就会使用默认值
""""""程序运行结果如下
姓名: 赵日天
高考总分:586
姓名:雷军
高考总分:660
通过这里例子中可以看到当我们不传入参数时,它就会使用在定义函数时设定的默认参数。如果想要查看当前参数的默认值,可以使用函数名 .defaults 来查看函数参数的当前值,其结果是一个元组。
如果用户在定义函数时不能确定需要定义几个参数时就可以使用可变参数。下面通过举例子说明
def get_sum(*numbers):
sum = 0
for n in numbers:
sum += n
return sum
print (get_sum(1,2,3,4,5))
#程序运行结果为 15
加了星号(*)的变量名会存放所有未命名的变量参数。如果在函数调用时没有指定参数,那么它就是一个空元组。用户也可以不向函数传递未命名的变量。同样的用户也可以为参数设置 ** 类型的变量,即两个星号,两个星号代表的是字典对象
return 语句用于退出函数,有选择性地向调用者返回一个表达式。不带参数值的return 语句返回None 函数的返回值也可以是多个,那么此时就会以元组对象的类型返回。若函数没有返回值,则返回None。
在Python语言中,变量并不是在哪个位置都可以访问。变量的访问权限决定了这个变量在哪里赋值,而变量的作用域决定了该变量在哪一部分程序可以访问哪个特定的变量名称
变量的作用域包括全局变量和局部变量。其中,定义在函数内部的变量拥有一个局部作用域,定义在函数外部的则拥有全局作用域。如果要在函数内改变全局变量的值,则就要使用global关键字。
匿名函数,即是不使用def关键字来声明函数。Python语言中,使用lambda创建一个匿名函数。
def f(x,y)
return x-y
#使用匿名函数
f=lambda x,y:x-y
匿名函数与我们在JavaScript中所学到的箭头函数形式还是很相似的,在使用时两者可以进行参考。
匿名函数在使用时也有许多要注意的地方:
①如果只有一个表达式,则必须有返回值
②可以没有参数,也可以有一个或多个参数
③不能有return
在 lambda语句中,冒号前是参数(可以有多个),用逗号隔开冒号右边的返回值。lambda语句构建的其实是一个函数对象。例如:
import math
r = float(input("请输入圆的半径:"))
area =lambda r:math.pi*r*r
print(area(r))
#程序运行结果为
请输入圆的半径:12.5
490.8738521234052
对象是类的实例化。对象分为静态特征和动态特征两种。静态特征指的是对象的外观、性质、属性等。动态特征则指的是对象具有的功能。在我们之前学习java时基本上都是面向对象编程。所以在这里就很好理解了。对象基本上可以理解为相关变量和方法的软件集。对象主要由两部分组成,一组包含各种类型数据的属性,对属性中的数据进行相关操作的相关方法。
由于Python语言时面向对象的语言,所以再Python语言中,一切都是对象,包括字符串、函数等都是对象。
面向对象中常用的技术术语如下:
面向对象的三大特点:封装性、继承性、多态性
之前我们已经介绍过类是什么。这一步我们将介绍如何定义一个类。类是一个用户定义类型,与大多数计算机语言一样。Python语言使用关键字class来定义类,类的帮助信息可以通过ClassName.__doc__查看。
定义类的语法格式入下:
class <ClassName>:
'类的帮助信息' #类文档字符串
class_suite #类体
下面我们直接定义一个学生类来帮助大家理解:
class Students:
"这是一个定义学生类的例子"
name="赵日天"
def disStudents():
print("这个学生类的名字是:"+name)
其中类名称为Students。name是一个类变量,它的值将在这个类的所有例之间共享。用户可以在内部类或者外部类使用Students.name来进行访问。disStudents是此类的方法,属于方法对象。
构造方法是指创建对象时其本身所运行的函数。Python语言使用 init() 函数作为对象的构造方法。当用户要在对象内指向对象本身时,可以使用self关键字,这与JavaScript以及Java中的this关键字一样,都是代表对象本身。def init(self)语句定义Goods类的构造方法,self时必要的参数且为第一个参数。用户可以在里面加入许多参数,在创建类时同时设置类的属性值。
#类定义 class Goods: #定义基本属性 name = ' ' factory= ' ' #定义私有属性,私有属性在类外部无法直接进行访问 __price= 0 #定义构造方法 def __init__(self,n,f,p): self.name = n self.factory = f self.__price = p def disGoods (self): print("%s生产的%s质量非常不错。最新款的价格是%s元。" %( self. factory,self.name, self.__price)) # 实例化类 g = Goods ('小米11pro','小米',5557) g.disGoods()
所有的Python都具有下面的内置属性
要创建一个类例,只需要指定变量与类名即可。使用id( )内置函数,可以返回类的识别码;使用type( )内置函数,额可以返回类的对象类型。下面我们通过创建一个简单类,并设置类的三个属性:
class Goods:
def __init__(self, name=None, factory =None, price= None):
self.name = name
self.factory = factory
self.price = price
#创建一个类的实例变量
g = Goods ("小米11pro", "小米", 5860)
print(g.name, g.factory, g.price)
d = Goods("小米汽车", "小米", 188600)
print(d.name, d.factory, d.price)
在这个类的构造方法中,设置name、factoort与price的默认值均为None。
在创建类的时候,可以不必声明属性。等到创建类的实例后,在动态创建类的属性。例如:
>>> classs myGoods:
pass
>>> x = myGoods()
x.name="电脑"
如果想测试一个类例 y 是否是类 x 的例,可以使用内置函数instance( y,x)。这与JavaScript中的instanceof作用一样,都是测试前者是否是后者的实例化对象,返回值是一个Boolean值。
用户也可以在类内定义类变量,同时这些类变量可以被所有该类的例变量所共享。下面创建一个类,并定义类变量
>>> class Vegetables:
default_price = 3.66
def _init _(self):
self.price = Vegetables.default_price #例变量的变量
所有的Python语言程序的类例都具有下面内置属性
obj._ dict_:类例内的属性是以字典对象的方式存储的。
obj._class _: _class _属性返回创建此类例所用的类名称
>>>class Goods:
def _init_(self,name=None,city=None,price=None):
self.name = name
self.city = city
self.price = price
>>> g = Goods()
>>> g._dict_
{'name':None,'city':None,'price':None}
>>> g._class_
<class '_main_.Goods'
类的继承就是新类继承旧类的属性与方法,这种行为称为派生子类。继承的新类称为派生类,被继承的旧类则称为基类。当用户创建派生类后,就可以在派生类内新增或改写基类的任何方法。这里的继承与Java中的继承类似,但是语句却略有不同。
class <类名称> [(基类1,基类2,……)]:
["文件字符串"]
<语句>
一个派生类可同时继承自多个基类,即一个子类可以同时有多个父类,基类直接用逗号(,)隔开。下面举例说明:
先定义一个基类:
class Cars:
def __init__(self, name, price, city):
self.name = name
self.price = price
self.city = city
def printData(self):
print ("名称: ", self.name)
print ("价格: ", self.price)
print ("产地: ", self. city)
下面创建一个Cars类的派生类:
class bk(Cars):
def _init_(self,name,price,city): #派生类的构造方法
Cars_init_(self,name,price,city) #调用基类的构造方法
下一步创建一个派生类bk的例变量,并且调用基类Cars的函数printData( )打印出数据。
>>>b=bk("别克",128000,上海)
>>> b.printData()
运行结果如图所示:
当用户在类内编写函数时,要记得类函数名称空间的搜索顺序是类的实例——>类——>基类。
类继承时同样也有多继承,下面列举出代码:
#类定义 class people: #定义基本属性 name = '' age = 0 #定义私有属性,私有属性在类外部无法直接进行访问 __weight = 0 #定义构造方法 def __init__(self,n,a,w): self.name = n self.age = a self.__weight = w def speak(self): print("%s 说: 我 %d 岁。" %(self.name,self.age)) #单继承 class student(people): grade = '' def __init__(self,n,a,w,g): #调用父类的构函 people.__init__(self,n,a,w) self.grade = g #覆写父类的方法 def speak(self): print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade)) #定义类speaer class speaker(): topic = '' name = '' def __init__(self,n,t): self.name = n self.topic = t def speak(self): print("我是%s,我是一名新来的学生,我想学的技术是:%s"%(self.name,self.topic)) #多重继承 class sample(speaker,student): a ='' def __init__(self,n,a,w,g,t): student.__init__(self,n,a,w,g) speaker.__init__(self,n,t) test = sample("李元",20,59,6,"大数据分析") test.speak() #方法名同,默认调用的是在括号中排前的父类的方法 #运行结果: 我是李元,我是一名新来的学生,我想学的技术是: 大数据分析
所谓多态,就是指类可以有多个名称相同、参数类型却不同的函数。Python中给并没有明显的多态特性,因为Python函数的参数不必声明数据类型。但是Python利用动态数据类型仍然可以处理对象的多态。
因为是动态数据类型,所以Python必须等到运行该函数时,才能知道该函数的类型,这种特性称为运行期绑定。像C++以及Java语言允许类内有多个名称相同、参数却不同的函数存在。但是在Python语言中却不允许这样做,如果用户在Python的类内声明多个名称相同、参数却不同的函数,那么Python语言程序会使用类内最后一个声明的函数。要解决这个问题必须使用下面的方法,即我们之前学到的可变参数。代码如下:
class myClass: def _init_(self): pass def handle(self,*arg): if len(arg)==1: self.handle1(*arg) elif len(arg)==2: self.handle2(*arg) elif len(arg)==3 self.handle3(*arg) else: print("Wrong arguments") def handle(self,x): print("1 arguments") def handle2(self,x,y): print("2 arguments") def handle3(self,x,y,z): print("3 arguments") >>> x=myClass() >>>x.handle() Wrong arguments >>>x.handle(1) 1 arguments >>>x.handle(1,2) 2 arguments >>>x.handle(1,2,3) 3 arguments >>>x.handle(1,2,3,4) Wrong argument
类的封装是指将其属性(变量与方法)封装在该类内,只有该类中的成员,才可以使用该类中的其它成员。这种被封装的变量与方法,称为该类的私有变量与私有方法。Python语言中所有变量与方法都是公用的。只要知道该类的名称与该变量或方法的名称,任何外部对象都可以直接存取类中的属性与方法。
要做到类的封装,必须做到以下几点:
① 如果属性名称的第一个字符是下划线,那么该属性视为类的内部变量,外边的变量不可以引用该变量。
②如果属性名称前两个字符都是单下划线,那么在编译时属性名称_arrtibuteName会被改成 _className _attributeName,className是该类的名称。由于属性名称之前加上了类的名称,因此与类中原有的属性名称有差异。
以上两个原则只是作为参考,Python语言程序类中的所有属性仍然是公用的,只要知道类与属性的名称,就可以存取类中的所有属性。
Python使用了引用计数这一简单技术来跟踪和回收垃圾。在Python内部有一个跟踪变量,记录着所有使用中的对象各有多少引用,称为一个引用计数器。
当对象被创建时,就同时创建了一个引用计数。当这个对象不再需要,其引用计数变为0 时,就被垃圾回收了。但回收不是"立即"的,而是由解释器在适当的时机将垃圾对象占用的内存空间回收。例如:
class Vegetables: def __init__( self, name="西红四", price=6.88): self.name = name self. price = price def __del__(self): class_name = self.__class__.__name__ print (class_name, "销毁对象") v= Vegetables () g = v s= v print (id(v), id(g), id(s)) # 打印对象的id del v del g del s # 运行结果 1838495355848 1838495355848 1838495355848 # Vegetables 销毁对象
在Python中,模块是一个扩展名为 .py 的文件。
将实现某一特定功能的代码放置在一个文件夹中可以作为一个模块,从而方便其他程序直接调用。同时,使用模块还可以避免函数名和变量名冲突的问题。例如,下面代码的功能是检查敏感字,将代码保存在savestring.py,则该文件就是一个模块。
def savestring(s):
import re
print("欢迎进入敏感字过滤系统")
s1 = r'(渗透)|(攻击)|(脚本)' #模式字符串
match = re.match(s1,s) #进行模式匹配
if match==None:
print("您输入的文字安全通过!")
else:
print("警告!您输入的文字存在敏感字,请重新整理后输入!")
自定义的模块不仅可以规范代码,还可以方便其它程序直接调用,从而提高开发效率。
将模块中的代码编写在一个单独的文件中,然后将其命名为模块名.py 即可。 需要注意的是模块名不能和标准模块重名,如果出现重名的问题,在导入标准模块时就会把这些定义的文件当成模板来加载,通常会引起错误。比如说我们下面新建一个文件名为friends.py的模块:
def makeFriends( par ):
print "Hello : ", par,"My name is 赵日天, I want to make friends with you!"
return
模块创建完毕之后,就可以在其它程序中使用该模块了。导入模块可以通过import 语句来实现。
import modulename [as alias]
modulename为导入的模块名称;[as alias ]为给模块起的别名,可以省略。现在我们就可以直接导入上面的模块 ,并且使用其中的函数。我们也可以导入其具体的一个函数,使用from……import……语句进行。这一点类似于Java中的import,比如我们要导入某一个具体的函数,但是完全可以将整个包导入,或者是直接 *,虽然结果都一样,但是个人的习惯因人而异。
import frieds
#也可以导入具体的函数
#from makeFriends import friends
friends.makeFriends("赵日地")
#打印结果为 Hello: 赵日地,My name is 赵日天 ,I want to make friends with you!
上面我们创建的后缀为py的文件我们就直接将它当作包的名字导入,然后就可以直接使用其中的函数。当解释器遇到import时,会在当前路径下搜索该模块。需要注意的是在调用模块中的变量、函数或类时,需要在变量名、函数名或者类的前面添加模块名称作为前缀。同样的,使用一个import语句可以一次加载多个模块,模块名称之间可以逗号隔开。
当import有一个模块时,如果我们想要查找到一个模块的位置有三种方法,我们以hello.py为例:
在当前目录中查找hello.py模块
若没有找到,则继续从环境变脸PYTHNONPATH中查找
若没有PYTHONPATH变量,则可以到安装目录中进行查找。实际上要查找目录的信息存放到sys模块的path变量,可以打印该变量来查看Python的查找目录。可以在命令窗口进行查找
import sys
sys.path
包是一组模块的集合,而模块是一个Python文件,所以包就可以理解为存放着若干个模块的集合。并且在该目录下有一个_init _.py的文件(包的初始化文件) ,可以在该文件里导入包里的所有模块。
掌握了包是什么之后,接下来学习如何定义包。定义包更简单,主要有两步:
创建一个文件夹,该文件夹的名字就是该包的包名。
在该文件夹内添加一个 init.py 文件即可。
下面定义一个非常简单的包。先新建一个 first_package 文件夹,然后在该文件夹中添加一个 init.py 文件,该文件内容如下:
'''这是学习包的第一个示例'''
print('this is first_package')
上面的 Python 源文件非常简单,该文件开始部分的字符串是该包的说明文档,接下来是一条简单的输出语句。
下面通过如下程序来使用该包:
# 导入first_package包(模块)
import first_packageprint('==========')
print(first_package.__doc__)
print(type(first_package))print(first_package)
再次强调,包的本质就是模块,因此导入包和导入模块的语法完全相同。因此,上面程序中第 2 行代码导入了 first_package 包。程序最后三行代码输出了包的说明文档、包的类型和包本身。
运行该程序,可以看到如下输出结果:
这是学习包的第一个示例
<class 'module'>
<module 'first_package' from 'G:\\publish\\codes\\09\\9.3\\first_package\\__init__.py'>
从上面的输出结果可以看出,在导入 first_package 包时,程序执行了该包所对应的文件夹下的 init.py;从倒数第二行输出可以看到,包的本质就是模块;从最后一行输出可以看到,使用 import
first_package 导入包的本质就是加载井执行该包下的 init.py 文件,然后将整个文件内容赋值给与包同名的变量,该变量的类型是 module。
与模块类似的是,包被导入之后,会在包目录下生成一个 pycache 文件夹,并在该文件夹内为包生成一个 init.cpython-36.pyc 文件。
由于导入包就相当于导入该包下的 init.py 文件,因此我们完全可以在 init.py 文件中定义变量、函数、类等程序单元,但实际上往往并不会这么做。想一想原因是什么?包的主要作用是包含多个模块,因此 init.py 文件的主要作用就是导入该包内的其他模块。
下面再定义一个更加复杂的包,在该包下将会包含多个模块,并使用 init.py 文件来加载这些模块。
新建一个 fk_package 包,并在该包下包含三个模块文件:
fk_package 的文件结构如下:
fk_package
┠──arithmetic_chart.py
┠──billing.py
┠──print_shape.py
┗━━__init__.py
其中,arithmetic_chart.py 模块文件的内容如下:
def print_multiple_chart(n):
'打印乘法口角表的函数'
for i in range(n):
for j in range(i + 1):
print('%d * %d = %2d' % ((j + 1) , (i + 1) , (j + 1)* (i + 1)), end=' ')
print('')
上面模块文件中定义了一个打印乘法口诀表的函数。
billing.py 模块文件的内容如下:
class Item: '定义代表商品的Item类'
def __init__(self, price):
self.price = price def __repr__(self):
return 'Item[price=%g]' % self.price
print_shape.py 模块文件的内容如下:
def print_blank_triangle(n):
'使用星号打印一个空心的三角形'
if n <= 0:
raise ValueError('n必须大于0')
for i in range(n):
print(' ' * (n - i - 1), end='')
print('*', end='')
if i != n - 1:
print(' ' * (2 * i - 1), end='')
else:
print('*' * (2 * i - 1), end='')
if i != 0:
print('*')
else:
print('')
tk_package 包下的 init.py 文件暂时为空,不用编写任何内容。
上面三个模块文件都位于 fk_package 包下,总共提供了两个函数和一个类。这意味着 fk_package 包(也是模块)总共包含 arithmetic_chart、 billing 和 print_shape 三个模块。在这种情况下,这三个模块就相当于 fk_package 包的成员。
如果需要使用 arithmetic_chart、 billing 和 print_shape 这三个模块,则可以在程序中执行如下导入代码:
# 导入fk_package包,实际上就是导入包下__init__.py文件
import fk_package
# 导入fk_package包下的print_shape模块,
# 实际上就是导入fk_package目录下的print_shape.py
import fk_package.print_shape
# 实际上就是导入fk_package包(模块)导入print_shape模块
from fk_package import billing
# 导入fk_package包下的arithmetic_chart模块,
# 实际上就是导入fk_package目录下的arithmetic_chart.py
import fk_package.arithmetic_chart
fk_package.print_shape.print_blank_triangle(5)
im = billing.Item(4.5)
print(im)
fk_package.arithmetic_chart.print_multiple_chart(5)
上面程序中第 2 行代码是“import fk_package”,由于导入包的本质只是加载并执行包里的 init.py 文件,因此执行这条导入语句之后,程序只能使用 fk_package 目录下的 init.py 文件中定义的程序单元。对于本例而言,由于 fk_package_init_.py 文件内容为空,因此这条导入语句没有任何作用。
第 5 行导入语句的本质就是加载并执行 fk_package 包下的 print_shape.py 文件,并将其赋值给 fk_package.print_shape 变量。因此执行这条导入语句之后,程序可访问 fk_package\print_shape.py 文件所定义的程序单元,但需要添加 fk_package.print_shape 前缀。
第 8 行导入语句的本质是导入 fk_package 包(也是模块)下的 billing 成员(其实是模块)。因此执行这条导入语句之后,程序可使用 fk_package\billing.py 文件定义的程序单元,而且只需要添加 billing 前缀。
第 11 行代码与第 5 行代码的导入效果相同。
该程序后面分别测试了 fk_package 包下的 print_shape、billing、arithmetic_chart 这三个模块的功能。运行上面程序,可以看到三个模块的功能完全可以正常显示。
上面程序虽然可以正常运行,但此时存在两个问题:
想一想就知道,包内的 init.py 文件并不是用来定义程序单元的,而是用于导入该包内模块的成员,这样即可把模块中的成员导入变成包内成员,以后使用起来会更加方便。
将 fk_package 包下的 init.py 文件编辑成如下形式:
# 从当前包导入print_shape模块
from . import print_shape
# 从.print_shape导入所有程序单元到fk_package中
from .print_shape import *
# 从当前包导入billing模块
from . import billing
# 从.billing导入所有程序单元到fk_package中
from .billing import *
# 从当前包导入arithmetic_chart模块
from . import arithmetic_chart
# 从.arithmetic_chart导入所有程序单元到fk_package中
from .arithmetic_chart import *
该程序的代码基本上差不多,都是通过如下两行代码来处理导入的:
# 从当前包导入print_shape模块
from . import print_shape
# 从.print_shape导入所有程序单元到fk_package中
from .print_shape import *
上面第一行 from…import 用于导入当前包(模块)中的 print_shape(模块),这样即可在 tk_package 中使用 print_shape 模块。但这种导入方式是将 print_shape 模块导入了 fk_package 包中,因此当其他程序使用 print_shape 内的成员时,依然需要通过 fk_package.print_shape 前缀进行调用。
第二行导入语句用于将 print_shape 模块内的所有程序单元导入 fk_package 模块中,这样以后只要使用 fk_package.前缀就可以使用三个模块内的程序单元。例如如下程序:
# 导入fk_package包,实际上就是导入包下__init__.py文件
import fk_package
# 直接使用fk_package前缀即可调用它所包含的模块内的程序单元。
fk_package.print_blank_triangle(5)
im = fk_package.Item(4.5)
print(im)
fk_package.print_multiple_chart(5)
上面第 2 行代码是导入 tk_package 包,导入该包的本质就是导入该包下的 init.py 文件。而 init.py 文件又执行了导入,它们会把三个模块内的程序单元导入 tk_package 包中,因此程序的下面代码可使用 tk_package.前缀来访问三个模块内的程序单元。
运行上面程序,同样可以看到正常的运行结果。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。