人生苦短我用Python,本文助你快速入门

友情提示:本文针对的是非编程零基础的朋友,能够帮助咱们快速了解Python语法,接着就能够快乐的投入到实战环节了。若是是零基础,仍是老老实实看书最为稳妥。html

前言

​ 偶然在知乎上看到了一些好玩的Python项目(学 Python 都用来干吗的?),让我对Python产生了些许兴趣。距离北漂实习还有两个月时间,正好能够在这段空闲时间里学一学。若是能作出些小工具,说不定对工做还有帮助,何乐而不为呢?python

​ 关于环境的安装和IDE就很少说了,网上有不少教程。这里贴出一篇博客,你们按里面的步骤安装就行:VSCode搭建Python开发环境。使用VSCode主要是由于免费,并且有大量插件能够下载,你们能够尽情的定制本身的IDE。若是曾经没有使用过VSCode,最好多了解下哪些必须的插件,优化本身的Coding体验。好比:Python插件推荐正则表达式

​ 环境搭建好后,就能够愉快地敲代码了。VSCode须要本身建立Python文件,以.py为后缀。Ctrl+F5运行程序,F5调试程序。算法

Python基础

注释

​ 单行注释:#编程

​ 多行注释:''' (三个英文单引号开头,三个英文单引号结尾)json

# 这是单行注释

'''
这是多行注释
'''

变量

​ Python的变量定义不须要显式指明数据类型,直接【变量名=值】便可。注意变量名分大小写,如Name和name不是同一个变量。缓存

name = "小王"
print(name) # 输出 小王

数据类型

​ Python提供6种基础的数据类型:数字类型(number)、字符串类型(string)、列表(list)、元组(tuple)、字典(dictionary)、集合(set)。其中数字类型还包括三种数值类型:整型(int)、浮点型(float)、复数类型(complex)。安全

​ 列表、元组那些咱们留在容器那一节里面讲,先看看数字类型。数据结构

浮点型

​ 浮点型表示小数,咱们建立一个浮点型变量,再经过type函数看一看它的类型:闭包

pi = 3.1415926
print(type(pi)) # 输出<class 'float'>

int整数型就不说了,其为Integer的缩写。

复数类型

​ 复数类型,所谓复数就是咱们中学学的,实数+虚数,好比:

x = 10+1.2j # 虚数以j或J结尾
print(type(x)) # 输出<class 'complex'>

​ 刚开始接触复数时,很纳闷为啥会有这种类型,到底有啥实际做用,遂百度了一番:

mzy0324:微电子方面的运算基本所有都是复数运算。

hilevel:至少复数用来计算向量的旋转要比矩阵方便多了。科学计算和物理应该会用获得吧。PS:我常常把Python当带编程功能的计算器用,用来调试纯粹的数学算法挺方便的。

morris88:Python 的一大应用领域,主要是科学计算,主要用于太空宇航、银行等。

​ 联想到Python平时在算法、科学研究等领域应用颇多,因此也就明白了,只是本身没使用的需求而已。

字符串

​ 字符串类型的变量定义用一对双引号或者单引号括起来。如:

x = "Hello Python"
y = 'Hello Python'
print(x,y) # 输出Hello Python Hello Python

​ 字符串内置函数:

函数 做用
find(str[,start,end]) 在字符串中查找子串str,可选参数start和end能够限定范围
count(str[,start,end]) 在字符串中统计子串str的个数,可选参数start和end能够限定范围
replace(old,new[,count]) 在字符串中用new子串替换old子串,可选参数count表明替换个数,默认所有替换
split(sep[,maxsplit]) 用指定分隔符sep分割字符,返回一个列表,可选参数maxsplit表明分割几回,默认所有
upper()、lower() 转换大小写
join(序列) 把序列中的元素用指定字符隔开并生成一个字符串。
startwith(prefix[,start,end]) 判断字符串中是否以prefix开头,返回bool类型。还有一个endwith,判断结尾的。
strip([,str]) 去掉字符串开头和结尾的空白字符(包括\n、\t这些),可选参数表明能够去掉指定字符

布尔类型

​ 顺便再说一下布尔类型,不过与Java不一样的是,布尔类型的True和False,首字母必须大写:

x = True
print(type(x)) # 输出<class 'bool'>

类型转换

​ 说完几个基本的数据类型,难免要提到类型转换。Python内置一些类型转换的函数:

函数名 做用
int(x) 将x转换为整型(小数转整型会去掉小数部分)
float(x) 将x转换为浮点型
str(x) 将x转换为字符串
tuple(x) 将x转换为元组
list(x) 将x转换为列表
set(x) 将x转换为集合,并去重

输入与输出

​ 输入函数为input。input函数返回用户输入的信息为字符串类型。因此若是你输入的是数字类型,记得类型转换

x = input("请输入数字")
print(type(x),x) # 输出<class 'str'> 10

​ 输出前面已经演示了不少次了,函数为print,能够直接输出变量与值。一次输出多个变量能够用逗号隔开,就想上面的演示同样,既要输出类型,也要输出值。不换行输出,能够在print函数里加上end=""这个参数,由于print默认end="\n",\n就是换行的意思。若是想输出特殊字符,可能须要用到转义字符:\。

x = 10
y = 20
print(x,y,end="") # 输出10 20 加上end="" 不换行
print("Hello \\n Python") # 输出 Hello \n Python

​ 在输出时,还能够格式化输出内容:%s表明字符串格式、%d表明整型、%f表明浮点型

z = 1.2
print("%f"%z) # 输出 1.200000

​ 除了格式化,%d等还能够看成占位符:

name = "小明"
age = 18
print("姓名:%s,年龄:%d"%(name,age)) # 姓名:小明,年龄:18

​ 若是你闲这个占位符麻烦,还可使用format函数,占位符只用写一对{}:

print("姓名:{},年龄:{}".format(name,age)) # 姓名:小明,年龄:18

运算符

算术运算符

​ 除了加减乘除,还有幂(**)、取模(%)、取整(//)

x = 3 ** 2 # x=9 即3的2次方 
y = 5 % 3 # y=2 即5除以3余2
z = 5 // 2 # z=2 即5除以2,整数部分为2

比较运算符

​ 和其余经常使用编程语言基本如出一辙,不等于(!=)、大于等于(>=)、等于(==)。

赋值运算符

​ Python也支持+=、*=等形式的赋值运算。除此以外,固然也支持前面说到的幂、取模等算术运算符,如取整并赋值(//=)、取模并赋值(%=)。

x = 10
x %= 3
print(x) # 输出1 ,x%=3 意为 x = x%3

逻辑运算符

​ 非(not)、与(and)、或(or)

x = True
print(not x) # 输出 False

if、while、for

​ 这三个和其余编程语言基本没差,就是写法上有点区别。首先没了大括号,条件语句后以冒号开头;代码快有严格的缩进要求,由于没了大括号,缩进就是条件语句判断本身代码快范围的依据。其余的基本同样,好比continue跳过当次循环,break跳出整个循环体。下面看三个简单的例子就明白了:

a = 10
# if或else后面是冒号,代码块还须要缩进
if a >= 10:
    print("你好啊老大")
else:
    print("滚蛋")
    
# 一样的while后面也须要冒号,代码块必须缩进。(Python没有num++,得写成num+=1)
# print想不换行打印,最后得加个end="",由于默认有一个end="\n"
# " "*(j-i),表明j-i个空格
i = 1
j = 4
while i <= j:
    print(" "*(j-i), end="")
    n = 1
    while n <= 2*i-1:
        print("*", end="")
        n += 1
    print("")
    i += 1

# 语法:for 变量 in 序列 ,还没讲序列,暂时用range表示,表明1-21的序列
# continue略过当次循环,break跳出整个循环
for i in range(1, 21):
    if i % 2 == 0:
        if(i % 10 == 0):
            continue
        if(i >= 15):
            break
        print(i)

容器

列表

​ 列表使用一对[]定义,每一个元素用逗号隔开,元素类型不强求相同,经过索引获取列表元素。具体的咱们看下面的代码:

info_list = ["小红", 18, "男"] #能够不是同一类型
info_list[2] = "女" # 修改指定索引位置的元素
del info_list[1] # 删除指定索引位置的元素
info_list.remove("女") # 删除列表中指定的值
for att in info_list:   # 遍历元素
    print(att)

​ 上面的示例代码演示了部分列表的用法,下面再列出一些其余的经常使用函数或语法:

函数或语法 做用
list.append(element) 向列表list结尾添加元素(这个元素也能够是个列表)
list.insert(index,element) 向列表指定位置添加元素
list.extend(new_list) 向列表list添加new_list的全部元素
list.pop([,index]) 弹出最后一个元素,可选参数index,弹出指定位置元素
list.sort([,reverse=True]) 对列表排序,可选参数reverse=True表示降序
list[start:end] 对列表分片,start和end表明起始结束索引
list1+list2 拼接两个列表

元组

​ 元组用一对()定义。元组也是有序的,它和列表的区别就是,列表能够修改元素,元组不行。正是由于这个特色,元组占用的内存也比列表小。

name_list=("小红","小王")

字典

​ 字典使用一对{}定义,元素是键值对。用法示例以下:

user_info_dict = {"name": "小王", "age": "18", "gender": "男"}
name = user_info_dict["name"] # 直接用key获取value
age = user_info_dict.get("age") # 也能够用get(key)获取value
user_info_dict["tel"] = "13866663333" # 当key不存在,就是往字典添加键值对,若是存在就是修改value
del user_info_dict["tel"] # 删除指定键值对

​ 以上就是经常使用语法和函数。字典也能够遍历,只是遍历时,须要指定遍历的是key仍是value,好比:

for k in dict.keys(): # 遍历全部key
for v in dict.values(): # 遍历全部value
for item in dict.items(): # 也能够直接遍历键值对

集合

​ 集合是无序的,也用一对{}定义,但不是键值对了,是单独且不重复的元素。部分用法以下:

user_id_set = {"1111","22222","3333"} # 元素不重复
print(type(user_id_set)) # 输出<class 'set'>
# 除了直接用{}定义,还能够用set函数传入一个序列,其会为list去重,并返回一个集合(若是是字符串,字符串会被拆成字符)
new_user_id_set = set(list)

​ 上面演示了部分用法,下面咱们用一个表格展现一些经常使用的函数或语法:

函数或语法 做用
element in set 判断元素是否在集合中,返回布尔类型
element not in set 判断元素是否不在集合中
set.add(element) 向集合添加元素
set.update(list,.....) 将序列中的每一个元素去重并添加到集合中,若是有多个序列,用逗号隔开
set.remove(element) 删除指定元素,若是元素不存在就会报错
set.discard(element) 删除指定元素,若是元素不存在也不会报错
set.pop() 随机删除集合中的元素,并返回被删除的元素
set1 & set2 或set1 intersection set2 求两个集合的交集,两种用法结果同样
set1 | set2 或set1 union set2 求两个集合的并集
set1 - set2 或set1.difference(set2) 求两个集合的差集,注意顺序。set1-set2表明set1有set2没有的元素

函数

函数的定义

​ Python中函数用def定义,格式为:

def function_name(参数列表): # 参数可为空,多个参数用逗号隔开
	函数体
	return 返回值 #可选

# 函数的调用
function_name(参数列表)

缺省参数

​ 和循环体同样的,由于没有了大括号,因此缩进是严格要求的。除了上面那种比较常见的格式,Python函数的参数中,还有一种缺省参数,即带有默认值的参数。调用带有缺省参数的函数时,能够不用传入缺省参数的值,若是传入了缺省参数的值,则会使用传入的值。

def num_add(x,y=10): # y为缺省函数,若是调用这个函数只传入了x的值,那么y默认为10

命名参数

​ 通常状况下,调用函数传入实参时,都会遵循参数列表的顺序。而命名参数的意思就是,调用函数时,经过参数名传入实参,这样能够不用按照参数定义的顺序传入实参。

def num_add(x, y):
    print("x:{},y:{}".format(x, y))
    return x+y
# 输出:
# x:10,y:5
# 15
print(num_add(y=5, x=10))

不定长参数

​ 不定长参数能够接收任意多个参数,Python中有两种方法接收:1.在参数前加一个*,传入的参数会放到元组里;2.在参数前加两个**,表明接收的是键值对形式的参数。

# 一个*
def eachNum(*args):
    print(type(args))
    for num in args:
        print(num)
# 输出:
# <class 'tuple'>‘
# (1, 2, 3, 4, 5)
eachNum(1,2,3,4,5)

## 两个**。这个other是想告诉你,在使用不定长参数时,也能够搭配普通的参数
def user_info(other,**info):
    print(type(info))
    print("其余信息:{}".format(other))
    for key in info.keys():
        print("{} : {}".format(key,info[key]))
# 传入参数时,不用像定义字典同样,加个大括号再添加键值对,直接当命名参数传入便可
# 输出:
# <class 'dict'>
# 其余信息:管理员
# 略...
user_info("管理员",name="赵四",age=18,gender="男")

​ 上面示例代码中的注释说到了,当使用不定长参数时,不用像字典或者元组的定义那样,直接传入参数便可。但有时候,可能会遇到想把字典、元组等容器中的元素传入到不定长参数的函数中,这个时候就须要用到拆包了。

​ 所谓拆包,其实就是在传入参数时,在容器前面加上一个或两个*。仍是以上面的user_info函数为例:

user_info_dict={"name":"赵四","age":18,"gender":"男"}
user_info("管理员",**user_info_dict) # 效果和上面同样

​ 注意,若是接收方的不定长参数只用了一个 * 定义,那么传入实参时,也只能用一个 *。

匿名函数

​ 匿名函数,即没有名字的函数。在定义匿名函数时,既不须要名称,也不须要def关键字。语法以下:

lambda 参数列表: 表达式

​ 多个参数用逗号隔开,匿名函数会自动把表达式的结果return。在使用时,通常会用一个变量接收匿名函数,或者直接把匿名函数当参数传入。

sum = lambda x,y : x+y
print(sum(1,2)) # 输出3

闭包和装饰器

​ 在Python中,函数内还能够定义函数,外面这个函数咱们就称为外部函数,里面的函数咱们就称为内部函数。而外部函数的返回值是内部函数的引用,这种表达方式就是闭包。内部函数能够调用外部函数的变量,咱们看一个示例:

# 外部函数
def sum_closure(x):
    # 内部函数
    def sum_inner(y):
        return x+y
    return sum_inner # 返回内部函数
# 获取了内部函数
var1 = sum_closure(1)
print(var1) # 输出<function sum_closure.<locals>.sum_inner at 0x000001D82900E0D0>,是个函数类型
print(var1(2)) # 输出3

​ 说完闭包的用法,接着了解一下装饰器。不知道你们了解过AOP没,即面向切面编程。说人话就是在目标函数先后加上一些公共函数,好比记录日志、权限判断等。Python中固然也提供了实现切面编程的方法,那就是装饰器。装饰器和闭包一块儿,能够很灵活的实现相似功能,下面看示例:

import datetime #若是没有这个包,在终端里输入pip3 install datetime
# 外部函数,其参数是目标函数
def log(func):
    #内部函数,参数得和目标函数一致。也可使用不定长参数,进一步提高程序灵活性
    def do(x, y):
        # 伪装记录日志,执行切面函数。(第一次datetime是模块、第二个是类、now是方法。在下一节讲到模块)
        print("时间:{}".format(datetime.datetime.now()))
        print("记录日志")
        # 执行目标函数
        func(x, y)
    return do

# @就是装饰器的语法糖,log外部函数
@ log
def something(x, y):
    print(x+y)
    
# 调用目标函数
# 输出:
# 时间:2021-01-06 16:17:00.677198
# 记录日志
# 30
something(10, 20)

​ 函数相关的就说到这里了,其实还有一些知识没说到,好比变量的做用域、返回值等。这部份内容和其余语言几乎无异,一点区别无非就是返回值不用在意类型了,毕竟定义函数时也没指定函数返回值类型,这一点各位老司机应该也会想到。

包和模块

​ Python中包与普通文件夹的区别就是,包内要建立一个__init__.py文件,来标识它是一个包。这个文件能够是空白的,也能够定义一些初始化操做。当其余包下的模块调用本包下的模块时,会自动的执行__init__.py文件的内容

模块

​ 一个Python文件就是一个模块,不一样包下的模块能够重名,在使用的时候以“包名.模块名”区别。导入其余模块用import关键字,前面的示例代码中也演示过一次。导入多个模块能够用逗号隔开,也能够直接分开写。除了导入整个模块,还能够导入模块中指定的函数或类:

from model_name import func_name(or class_name)

​ 导入函数或类后,就不要使用模块名了,直接调用导入的类或函数便可

面向对象

类和对象

​ Python是一种面向对象的解释型编程语言。面向对象的关键就在于类和对象。Python中类的定义用class关键字,以下:

class 类名:
	def 方法名(self[,参数列表])
	...

​ 定义在类里面的函数叫作方法,只是与类外部的函数作个区分,不用在乎叫法。类里面的方法,参数列表中会有一个默认的参数,表示当前对象,你能够看成Java中的this。由于一个类能够建立多个对象,有了self,Python就知道本身在操做哪一个对象了。咱们在调用这个方法时,不须要手动传入self。示例代码:

class Demo:
    def do(self):
        print(self)
# 建立两个Demmo类型的对象
demo1=Demo()
demo1.do() # 输出<__main__.Demo object at 0x0000019C78106FA0>
demo2=Demo() 
demo2.do() # 输出<__main__.Demo object at 0x0000019C77FE8640>
print(type(demo1)) # <class '__main__.Demo'>

构造方法

​ 构造方法的做用是在建立一个类的对象时,对对象进行初始化操做。Python中类的构造方法的名称是__init__(两边分别两个下划线)。在建立对象时,__init__方法自动执行。和普通方法同样的,若是你想自定义构造方法,也要接收self参数。示例代码:

class Demo:
    # 构造方法,还能够传入其余参数化
    def __init__(self,var1,var2):
        # 把参数设置到当前对象上,即便类中没有属性也能够设置
        self.var1=var1
        self.var2=var2
        print("初始化完成")
    def do(self):
        print("Working...")
# 经过构造方法传入实参
demo1=Demo(66,77)
demo1.do()
# 经过当前对象,获取刚刚设置的参数
print(demo1.var1)
print(demo1.var2)

访问权限

​ Java或C#中有好几种访问权限,在Python中,属性和方法前添加两个下划线即为私有,反之就是共公有。具备私有访问权限的属性和方法,只能在类的内部方法,外部没法访问。和其余语言同样,私有的目的是为了保证属性的准确性和安全性,示例代码以下:

class Demo:
    # 为了方便理解,咱们显示的设置一个私有属性
    __num = 10
    # 公有的操做方法,里面加上判断,保证数据的准确性
    def do(self, temp):
        if temp > 10:
            self.__set(temp)
	# 私有的设置方法,不让外部直接设置属性
    def __set(self, temp):
        self.__num = temp
	# 公有的get方法
    def get(self):
        print(self.__num)

demo1 = Demo()
demo1.do(11)
demo1.get() # 输出 11

​ 一堆self.刚开始看时还有点晕乎,把它看成this就好。

继承

​ 继承是面向对象编程里另外一大利器,好处之一就是代码重用。子类只能继承父类的公有属性和方法,Python的语法以下:

class SonClass(FatherClass):

​ 当咱们建立一个SonClass对象时,直接能够用该对象调用FatherClass的公有方法。Python还支持多继承,若是是多继承就在小括号里把父类用逗号隔开。

​ 若是想在子类里面调用父类的方法,通常有两种方式:1.父类名.方法名(self[,参数列表])。此时的self是子类的self,且须要显示传入;2.super().方法名()。第二种方式由于没有指定父类,因此在多继承的状况下,若是调用了这些父类中同名的方法,Python实际会执行小括号里写在前面的父类中的方法。

​ 若是子类定义了与父类同名的方法,子类的方法就会覆盖父类的方法,这就是重写

异常处理

捕获异常

​ 捕获异常的语法以下:

try: 
    代码快 # 可能发生异常的代码
except (异常类型,...) as err: # 多个异常类型用逗号隔开,若是只有一个异常类型能够不要小括号。err是取的别名
    异常处理 
finally:
    代码快 # 不管如何都会执行

​ 在try代码块中,错误代码以后的代码是不会执行的,但不会影响到try ... except以外的代码。看个示例代码:

try:
    open("123.txt") #打开不存在的文件,发生异常
    print("hi") # 这行代码不会执行
except FileNotFoundError as err:
    print("发生异常:{}".format(err)) # 异常处理

print("我是try except以外的代码") #正常执行

​ 虽然上面的内容和其余语言相差不大,可是刚刚接触Python鬼知道有哪些异常类型,有没有相似Java的Exception异常类型呢?确定是有的。Python一样提供了Exception异常类型来捕获所有异常。

​ 那若是发生异常的代码没有用try except捕获呢?这种状况要么直接报错,程序中止运行。要么会被外部的try except捕获到,也就是说异常是能够传递的。好比func1发生异常没有捕获,func2调用了func1并用了try except,那么func1的异常会被传递到func2这里。是否是和Java的throws差很少?

抛出异常

​ Python中抛出异常的关键字是raise,其做用和Java的throw new差很少。示例代码以下:

def do(x):
    if(x>3): # 若是大于3就抛出异常
        raise Exception("不能大于3") # 抛出异常,若是你知道具体的异常最好,后面的小括号能够写上异常信息
    else:
        print(x)

try:
    do(4)
except Exception as err:
    print("发生异常:{}".format(err)) # 输出 发生异常:不能大于3

文件操做

读写文件

​ 想要操做一个文件,首先得打开它。Python中有个内置的函数:open。使用open打开文件能够有三种模式,分别为:只读(默认的模式,只能读取文件内容,r表示)、只写(会覆盖原文本内容,w表示)、追加(新内容追加到末尾,a表示)。示例以下:

f = open("text.txt","a") # 用追加的方式获取文件对象

​ 由于text.txt和代码在同一目录因此只写了文件名,若是不在同一目录须要写好相对路径或绝对路径。

​ 获取到文件对象后,接下来就能够操做了,反正就是些API,直接看示例:

f = open("text.txt","a",encoding="utf-8") # 以追加的方式打开文件,并设置编码方式,由于接下来要写入中文
f.write("234567\n") # 写入数据,最后的\n是换行符,实现换行
f.writelines(["张三\n","赵四\n","王五\n"]) # write只能写一个字符串,writelines能够写入一列表的字符串
f.close() # 操做完记得关闭

​ 以上是写文件的两个方法。最后记得关闭文件,由于操做系统会把写入的内容缓存起来,万一系统崩溃,写入的数据就会丢失。虽然程序执行完文件会自动关闭,可是实际项目中,确定不止这点代码。Python也很贴心,防止咱们忘了close,提供了一种安全打开文件的方式,语法是 with open() as 别名:,示例以下

with open("test.txt","w") as f: # 安全打开文件,不须要close。
    f.write("123")

​ 写完了,该读一读了。示例以下:

f = open("text.txt","r",encoding="utf-8")
data = f.read() # read会一次性读出全部内容
print(data)
f.close()

​ 除了一次性读取完,还能够按行的方式返回所有内容,并用一个列表装起来,这样咱们就能够进行遍历了。方法是readlines,示例以下:

f = open("text.txt","r",encoding="utf-8")
lines = f.readlines() # lines是个列表
for line in lines:
    print(line)
f.close()

文件管理

​ 在操做文件的时候,确定不止读写这么简单,可能还会涉及文件的删除、重命名、建立等等。在用Python的函数操做文件以前,须要导入os模式:import os 。下面简单的演示一下重命名的函数,其余的函数咱们以表格的形式展示。

import os
os.rename("text.txt","123.txt") # 把text.txt更名为123.txt
函数 做用
os.remove(path) 删除指定文件
os.mkdir(path) 在指定路径下建立新文件
os.getcwd() 获取程序运行的绝对路径
os.listdir(path) 获取指定路径下的文件列表,包含文件和文件夹
os.redir(path) 删除指定路径下的空文件夹(若是不是空文件夹就会报错)

操做JSON

​ 学了前面的容器,会发现JSON的格式和Python的字典有点像,都是键值对形式的。虽然格式很像,但仍是有点小区别,好比:Python的元组和列表在JSON中都是列表、Python的True和Flase会被转换成小写、空类型None会被转换成null。下面咱们来看一些具体的函数把。

​ 在Python中操做JSON格式的数据须要导入json模块。一样的,我这里只演示一个函数,其余经常使用的用表格列出来。

import json
user_info={"name":"张三","age":18,"gender":"男","hobby":("唱歌","跳舞","打篮球"),"other":None} # 建立一个字典
json_str=json.dumps(user_info,ensure_ascii=False) # dumps函数会把字典转换为json字符串
# 输出 {"name": "张三", "age": 18, "gender": "男", "hobby": ["唱歌", "跳舞", "打篮球"], "other": null}
print(json_str)

​ 须要注意若是数据存在中文,须要在dumps函数加上ensure_ascii=False

函数 做用
json.loads(json_str) 把json字符串转换为Python数据结构
json.dump(user_info,file) 把Python数据写入到json文件,要先获取文件,那个file就是文件对象
json.load(file) 把json文件中的数据转为成Python数据结构,一样须要获取文件

​ 关于JSON的操做就说这些。通用的数据格式不止JSON一种,好比还有xml、csv等。为了节约篇幅,就再也不赘述了,你们能够根据本身的需求查对应的API便可。

正则表达式

​ 最后一节讲正则表达式,一是由于这也算个基础知识,在不少地方都有可能用到。二是由于后面的爬虫实战,确定会用到正则表达式来解析各类数据。

​ Python中内置了re模块来处理正常表达式,有了这个模块咱们就能够很方便的对字符串进行各类规则匹配检查。不过正则表达式真正难的是表达式的书写,函数主要就一个:re.match(pattern,string),其中pattren就是正则表达式,stirng就是待匹配字符串。若是匹配成功就会返回一个Match对象,不然就返回None。匹配是从左往右,若是不匹配就直接返回None,不会接着匹配下去。示例以下:

import re
res=re.match("asd","asdabcqwe") # 匹配字符串中是否有asd(若是asd不在开头就会返回None)
print(res) # 输出 <re.Match object; span=(0, 3), match='asd'>
print(res.group()) # 输出 asd 若是想获取匹配的子字符就用这个函数

​ 秉着帮人帮到底的精神,下面就简单的介绍下正则表达式的一些规则。

单字符匹配

​ 单字符匹配,顾名思义就是匹配一个字符。除了直接使用某个具体的字符,还可使用如下符号来进行匹配:

符号 做用
. 匹配除”\n“之外的任意单个字符
\d 匹配0-9之间的一个数字,等价于[0-9]
\D 匹配一个非数字字符,等价于[^0-9]
\s 匹配任意空白字符,如空格、\t、\n等
\S 匹配任意非空白字符
\w 匹配单词字符,包括字母、数字、下划线
\W 匹配非单词字符
[] 匹配[]中列举的字符,好比[abc],只要出现这三个字母中的一个便可匹配

​ 以防有的朋友从未接触过正则表达式,不知道怎么用,下面我来作个简答的演示。假如我想匹配三个字符:第一个是数字、第二个是空格、第三个是字母,一块儿来看看怎么写这个正则表达式吧:

import re
pattern = "\d\s\w" # \d匹配数字、\s匹配空格、\w匹配字母(切记是从左往右依次匹配的,只要有一个字符匹配不上就直接返回None)
string = "2 z你好"
res=re.match(pattern,string)
print(res.group()) # 输出:2 z

​ 看到这你可能会想,非得一个个字符匹配,那多麻烦啊,有没有更灵活的规则?固然有了,接着看。

数量表示

​ 若是咱们只想匹配字母,但不限制有多少个,该怎么写呢?看下面的表格就知道了:

符号 做用
* 匹配一个字符出现0次或屡次
+ 匹配一个字符至少出现一次,等价于{,1}
? 匹配一个字符出现0次或1次,等价于{1,2}
{m} 匹配一个字符出现m次
{m,} 匹配一个字符至少出现m次
{m,n} 匹配一个字符出现m到n次

​ 数量匹配的符号后面若是加上?就会尽量少的去匹配字符,在Python里面叫非贪婪模式,反之默认的就是贪婪模式。好比{m,}会尽量多的去匹配字符,而{m,}?在知足至少有m个的状况下尽量少的去匹配字符。其余的同理。

​ 来看一个例子,我想匹配开头是任意个小写字母,接着是1到5个2-6的数字,最后是至少一个空格:

import re
pat = r"[a-z]*[2-6]{1,5}\s+"
str = "abc423  你好"
res=re.match(pat,str) 
print(res) #输出 abc423

​ 咱们来解析下这个正则表达式,pat字符串开头的r是告诉Python这是个正则表达式,不要转义里面的\,建议写表达式时都加上。[a-z]表明任意小写字母,不用\w的缘由是,\w还包括数字、下划线,没有严格符合咱们的要求。加上个*就表明任意数量。这里强调一下单字符匹配和数量表示之间的逻辑关系,以[a-z]*为例,其表达的是任意个[a-z],而不是某个字母有任意个。明白了这个逻辑后,其余的也好理解了。

​ 前面的例子都是我随意编的,其实学了这些,已经能够写出一个有实际做用的表达式了,好比咱们来匹配一个手机号。首先手机号只有11位,第一个数字必须是1,第二个是三、五、七、8中的一个。知道了这三个个规律,咱们来写一下表达式:1[3578]\d{9}。看上去好像能够,可是仔细一想,前面不是说了正则表达式是从左往右匹配,只要符合了就会返回结果,也不会管字符串匹配彻底没有。若是最后有10个数字,这个表达式也会匹配成功。关于这个问题咱们接着看。

边界表示

​ 边界表示符有两个:开头^和结尾$。使用起来也很简单,仍是以上面的手机号为例,咱们再来完善一下:^1[3578]\d{9}$。其中^1表示以1开头,\d{9}$表示以9个数字结尾。其实这个^1无关紧要,毕竟是从左往右的,字符串不是1开头的话直接就会返回None,可是这个结尾符是必须的。

转义字符

​ 假如咱们想匹配的字符与正则表达式规定的这些字符同样该怎么办?好比咱们想单纯的匹配.这个字符,可是这个字符在正则表达式中表示的是任意字符。这时候就要用到转义字符\了。其实这个转义字符在不少语言里都是同样的。那么前面的例子就能够写出\.。咱们再演示个匹配邮箱的例子:

import re
pat = r"^\w{4,10}@qq\.com" # 若是.前面不加\,就表明任意字符了
str = "1234@qq.com"
res=re.match(pat,str)
print(res)

匹配分组

​ 看到上面的匹配邮箱例子,是否是有个疑问,若是我想不止匹配QQ邮箱该怎么办呢。那就要用到分组了,其能够实现匹配多种状况。分组符号以下:

符号 做用
() 将括号里的内容看成一个分组,每一个分组会有一个编号,从1开始
| 链接多个表达式,表达式之间是“或”的关系,可与()一块儿使用
\num 引用分组,num表明分组编号
(?P ...) 给分组取别名,别名写在表达式前面,name不用打引号
(?P=name) 根据别名使用分组中的正则表达式

​ 那么咱们把上面的例子稍微修改下:^\w{4,10}@(qq|163|outlook|gmail)\.com。这样就能够匹配多种邮箱了。

​ 简单的演示了下|的用法,你们可能对其余的分组符号还有点疑惑,下面咱们再来演示一下这些符号:

import re
pat = r"<(.+)><(.+)>.*<(/\2)><(/\1)>" 
str = "<body><div></div></body>"
res=re.match(pat,str)
print(res)

​ 这个表达式匹配的是由两个标签组成的html字符串。第一眼看上去有点麻烦,实际很简单。再次强调一下,普通字符也能够当表达式来匹配的,好比上面的< >就是普通字符而已。

​ 咱们来分析一下这个表达式,首先一对小括号表示一个分组,里面的.+表示只有一个非\n字符。中间的.*用来匹配标签内的内容。/\2中,第一个斜杠与前面的html标签组成一对,/2表示引用第二个分组的内容。这里为何要使用分组呢?由于咱们还要保证html标签正确匹配。若是后面也使用.+,你们能够试着把/div/body交换位置,表达式依旧匹配成功,但这显然不符合html的语法。

操做函数

​ 正则表达式的一些规则符号终于讲完了,最后再列举几个Python中操做正则表达式的函数:(re为导入的模块)

函数 做用
re.compile(patt) 封装正则表达式,并返回一个表达式对象
re.search(patt,str) 从左往右搜索第一个配正则表达式匹配的子字符串
re.findall(patt,str) 在字符串中查找正则表达式匹配到的全部子字符串,并返回一个列表
re.finditer(patt,str) 在字符串中查找正则表达式匹配到的全部子字符串,并返回一个Iterator对象
re.sub(patt,newstr,str) 将字符串中被正则表达式匹配到的子字符串替换成newstr,并返回新的字符串,原字符串不变

​ Python的第一篇文章就到这里了。接下来会边学边写,作一些好玩的Python项目,再一块儿分享出来。若有错误,感谢指出!

参考资料:《Python 3快速入门与实战》

相关文章
相关标签/搜索