Python基础 - 入门

一、python介绍

Python是当前测试工程师较常用的一门编程语言,相对于Java等其他语言,它更加的灵活易学,没有Java那样复杂固定的书写规范,也不像C一样考验智商。除此以外,Python庞大的第三方库让我们可以快速拿别人已经封装好的东西来用,比如比较出名的pytest测试框架、unittest测试框架、selenium、各种加解密方法等,个人觉得是比较适合测试工程师的一门语言。

1.1优缺点

优点:

  1. 简单易学、能够快速地编写一些脚本来满足使用需求
  2. 第三方库丰富,直接当个调包仔也能写出好用的代码
  3. 在人工智能和数据分析方面好用,如Tensorflow等训练模型、pandas库,都极大的简便了数据分析与机器学习的开发(虽然我从来不用)

缺点:

  1. python是解释性语言,性能相较其他语言比较差
  2. 虽然变量不用强制定义数据类型,但是有时也会因为这个问题而出bug
  3. Python存在GIL锁,使得他在同一时间只会有一个线程拿到控制权,这样虽然避免了多线程的数据争夺问题,但是也使得python的多线程并不是真正的多线程,在IO密集型任务时,由于IO存在时间开销,多线程还能够起到节省时间的作用,但是在面对CPU密集型任务时,由于同一时间只会有一个线程拿到控制权,并不能起到节省时间的作用,反而还增加了线程切换的时间开销

1.2安装

参考以下链接:

安装python详细步骤(超详细,保姆级,一步一图)_python安装-CSDN博客

IDE有很多:pycharm、vscode、jupyter……选择自己喜欢的就好了

1.3能做什么

对于测试来说,python还是一项很有用的技能,能够做以下很多事情

  1. 已经被人说烂了的UI自动化、接口自动化框架
  2. 当面对涉及加解密的需求时,可以使用python编写脚本进行测试
  3. 爬虫,快速爬取网站数据(爬取数据不要商用,容易进去喝茶)
  4. 各种提效用的小工具(例如我以前写过自动生成日报、webhook推送等脚本)
  5. 更高级的有测试平台,不过大多是好看不好用

二、常用基础

2.1数据类型

一般数据类型

int:整形,例如1、2、-1等数字

float:浮点数,也叫小数,1.5、2.55等数字

str:字符串,用双引号或单引号括起来,如’abc123’的字符,要注意’123’这种也算字符串,还可以使用’’’123abc’’’的方式表示字符串,这种方式和单个引号的区别在于,三个引号可以把多行的内容都表示为字符串,单个引号只能表示单行

bool:布尔值,对应值为True和False,用于判断的时候用的比较多,也可以用0或者负数代表False,正数代表True

None:一般代表空

complex:复数,一般用不到,我也没有怎么用过

序列数据类型

序列数据类型有几个特点:

1、他们是可以互相嵌套的,也就是说一个列表里可能放了几个字典、这几个字典里又嵌套几个集合,集合里又放着几个列表

2、序列可以存放任意长度、任意类型的数据

3、可以通过循环的方式按顺序读取序列内的数据

list:列表,用[1,2,3]的方式表示一个列表

dict:字典,很好用的一种数据类型,用{“key”:”value”,”key2”:”value2”}的方式来表示一个字典,要取对应value数据时,通过对应的key名进行访问就可以了,例如value = dict[“key”],虽然看起来和json一样,但是从根本上来说他们是两种数据类型,是不同的

set:集合,用var = set(obj)的方式定义一个集合,集合的特点是自动去重,会把原有obj内相同的元素去除,obj一般传列表或元组等序列,以{1,2}的方式显示

tuple:元组,用(1,2,3)的方式表示一个元组,元组的特点在于元组内的元素不允许更改

range:表示一个数字范围,如range(0,10),代表0到9,常用于数字迭代,本质上是一个迭代器

2.2基础语法

1、python对于缩进有严格的校验,通过缩进来控制代码执行域,可以参考以下gpt生成的代码

global scope (全局作用域)

├── if statement (条件语句)
│   ├── indented block (缩进块)
│   │   ├── code 1
│   │   └── code 2
│   └── else block (else 块)
│       ├── code 3
│       └── code 4

├── for loop (循环语句)
│   ├── indented block (缩进块)
│   │   ├── code 5
│   │   └── code 6
│   └── else block (else 块)
│       ├── code 7
│       └── code 8

└── function definition (函数定义)
    ├── indented block (缩进块)
    │   ├── code 9
    │   └── code 10
    └── return statement (返回语句)
        └── code 11

2、全局变量与局部变量以及执行顺序

如下图所示,在全局作用域定义的变量是可以被直接使用的,因此func函数中直接print(var)可以执行,但是局部变量只能作用于局部的作用域内,因此在全局作用域内print(var2)或者在错误的局部作用域内print(var4)都会报错,而在正确的作用域内pirnt(var2)可以执行,而var3由于定义的顺序在func函数后,因此是找不到var3变量的,所以print(var3)时会报错

var = 'a' #全局变量

def fun():
  var4 = 'd'

def func():
  var2 = 'b' #局部变量
  print(var) #可以访问到外面的var
  print(var2) #可以访问到局部变量
  print(var3) #var3此时还没定义,会报错
  print(var4) #访问不到fun函数内部的var4,会报错

var3 = 'c'
print(var2) #var2是个局部变量,访问不到var2,会报错

关于全局变量和私有变量还有一个内容要讲,可以看下面的代码

可以看到,一开始定义了x=20,然后在函数内部先print了x,这个时候输出的x,访问的是全局的变量,因此输出20

紧接着又在下一句声明了x=10,这时候声明的x,由于是在函数内部声明的,因此是一个局部变量,所以在下一个print中,访问的是在函数内部定义的局部变量x,输出了10

最后的一个print,由于访问不到函数内部的局部变量,因此只能访问全局变量,输出20

x = 20  #全局变量

def func():
  print(x) #输出=20,访问的是全局变量
  x = 10  #局部变量
  print(x) #输出=10,访问的是私有变量

print(x)  #输出=20

但是我们可以换一种写法,让函数内部也能跟全局作用域共同操作一个变量。可以看到,我们在声明x=30前,先写了一行代码:global x,这行代码的意思是声明接下来在这段作用域里,名字为x的变量操作的是全局变量,而不是局部变量,因此当声明x=30的时候,实际上是把全局作用域的x声明值=30,所以两个print都输出了30

x = 20 #全局变量

def func():
  global x  #声明x是全局变量
  x = 30    #声明x的值=30
  print(x)  #输出30,访问的是全局变量

print(x)    #输出30,访问的是全局变量

3、关键字与变量命名规则

变量命名的规则:变量名称只能包含字母(大小写均可)、数字和下划线(_)、不能以数字开头、不能包含空格或其他特殊字符、变量名称区分大小写、不能使用关键字或者内置函数作为变量名。通常命名用以下三种格式:

1、下划线分割,如test_student_name

2、驼峰,如TestStudentName

3、小驼峰,如testStudentName

以下是python的一些关键字

布尔值

True -- 真

False -- 假

空值

None

逻辑运算符

and -- 并

or    -- 或

not  -- 非

条件语句

if  -- 条件语句中的条件判断

elif -- 条件语句中的多个条件判断

else -- 条件语句中的其他情况

循环语句

for -- 循环一个可迭代对象

while -- 用于循环执行一段代码,直到判断条件变为False

break -- 强制结束循环

continue -- 跳过当前循环,继续下一次循环

异常处理

try  -- 没遇到异常时,执行try作用域的代码

expect -- 当捕获指定的异常类型时,执行expect作用域的代码

finally  --  不管有没有异常,最后都执行finally作用域的代码块

raise  --  主动抛出一个异常

函数、类

def -- 定义函数

class -- 定义类

return -- 用于在函数中返回一个值

模块导入

import  -- 导入某个包

from -- 从xx处导入

异步

async -- 声明一个异步函数

await -- 等待某个异步函数执行完毕

其他

global -- 声明一个全局变量

pass -- 什么也不做,可以理解为占位符

yield -- 用于生成器中,代表从生成器函数中生成一个值,暂停并保存当前状态。

lambda -- 声明一个匿名函数

with -- 不知道怎么解释比较好,可以理解为一个上下文管理器,当with中的代码执行完毕会自动关闭/释放资源,防止内存泄露,常见用法 with open(file)

2.4运算符

算术运算符

+ 加号

-  减号

*   乘号

/   除号

%  求余,例如11%10=1,11%3=2

**  幂运算 ,例如2**3=8,3**3=27

//  除数取整,向下取整,例如13//2=6,14//5=2

比较运算符

>    大于

<    小于

==  等于

!=   不等于

>=  大于等于

<=  小于等于

逻辑运算符

and   并且,如果and两边连接的两个条件都为真,返回True,否则返回False

or     或者,如果or两边连接的其中一个条件为真就返回True,都为假返回False

not   非,如果not连接的条件为假,返回True,否则返回False

赋值运算符

赋值(=):将右侧的值赋给左侧的变量。

加法赋值(+=):将左侧变量的值加上右侧的值,并将结果赋给左侧变量。

减法赋值(-=):将左侧变量的值减去右侧的值,并将结果赋给左侧变量。

乘法赋值(*=):将左侧变量的值乘以右侧的值,并将结果赋给左侧变量。

除法赋值(/=):将左侧变量的值除以右侧的值,并将结果赋给左侧变量。

取余赋值(%=):将左侧变量的值除以右侧的值的余数,并将结果赋给左侧变量。

幂运算赋值(=)**:将左侧变量的值提升到右侧变量的次幂,并将结果赋给左侧变量。

取整除赋值(//=):将左侧变量的值除以右侧的值的整数部分,并将结果赋给左侧变量

2.5控制结构

1、条件

如下图代码,当if声明的条件满足if/elif时,就会执行对应作用域的代码,如果所有的if和elif都不满足就会执行else作用域的代码。需要注意的一点是,if中也可以继续嵌套if - elif - else,只需要注意缩进即可。

#声明if时,elif和else不是必须声明的,可以只声明一个if条件

var = 20
if var > 10:
  print('我是if条件')
elif var > 5 and var <= 10:
  print('我是elif条件1')
elif var == 4:
  print('我是elif条件2')
else:
  print('我是else条件')
  if var >= 0:
    print('我是else条件中嵌套的if')
  else:
    print('我是else条件中嵌套的else')

多个if和elif的区别:举个简单的例子,下面这段代码中,func1和func2在执行判断时其实起到了同样的效果,不过if-elif跟多个if判断的区别在于,func1中当判断到x>10的时候,就不会再去判断elif和else了,但是在func2中,第一次判断了x>10,还会再判断一次x是否大于5且小于10,这就造成了一次没有意义的性能开销,因此能用elif解决的尽量不要用多个if

x = 20
def func1():
  global x
  if x > 10:
    pass
  elif x < 10 and x > 5:
    pass
  else:
    pass

def func2():
  global x
  if x > 10:
    pass
  if x < 10 and x > 5:
    pass

2、循环

for循环:for循环会循环一个可迭代对象,直到遍历完对象中的所有元素。例如下面这段代码会按顺序输出0-99

#for循环对象必须是一个可迭代对象,否则会报错

for i in range(0,100):
  print(i)

循环不同的对象时,取到的值是不同的

string = "abcdefg"
obj = {'key1':1,'key2':2,'key3':3}
li = [1,2,3]

for i in string:
  print(i) #循环字符串时,会按顺序打印字符串的每一个字符
for i in obj:
  print(i) #循环字典时,会按顺序拿到字典中的每一个key值
  print(obj[i]) #可以用这种方式按顺序拿到每一个value
for i in li:
  print(i) #循环列表/集合/元组时,会按顺序拿到每一个元素

while循环:while循环会在满足指定条件的情况下,一直重复执行作用域中的代码,例如以下这段代码,在变量x<10时,会循环将x+1并输出,直到x=10的时候,就不会再继续执行了

#要注意不要把条件写成永真造成死循环

x = 0
while x < 10:
  x += 1
  print(x)

结束/跳过循环

如下图代码,第一个循环会输出10-14,第二个循环会从10开始一直不停的加一输出,除了在x=15的时候会跳过一次循环不输出

break是强制结束循环,当x加到15 的时候,不管任何情况,直接结束循环,即使while是个永真循环也一样结束

continue是跳过本次循环,当x加到15的时候,不再执行本次循环剩下的代码,直接开始下次循环

x = 10
while 1:
  x += 1
  if x == 15:
    break #x循环加到15的时候,break结束while循环
  print(x)
  
while 1:
  x += 1
  if x == 15:
    continue #x循环加到15的时候,跳过这次循环
  print(x)

2.6导入

import

导入对象可以是一个文件,也可以是文件中的一个指定对象 例:import test_file /  import test_file.test_obj

from

用 from 文件 import 对象的格式来书写,例:from test_file import test_obj

较常用的包:

requests -- 处理http请求

random  -- 生成随机数

json        -- 处理json格式数据

time       -- 处理跟时间相关的数据

re           -- 正则表达式

jsonpath -- 定位json中的数据

os           -- 跟操作系统相关

yaml       -- 处理yaml文件

openpyxl --处理excel文件

下载第三方包可以用下面这段代码,例如下载requests

pip install requests

在默认没有换源的情况下,很容易下载超时,建议换源后再下载,具体查看下面这个连接,有很多关于pip的操作

https://www.cnblogs.com/chenhuabin/p/10448116.html

2.7异常处理

只要try模块代码没有报错,那么except模块中的代码是不会执行的,但是如果发生了报错,会判断错误类型,去执行对应except模块中的代码。例如下图代码,try中先print了一段语句,然后主动抛出了一个AssertionError类型的异常,这个异常会被对应except捕获到然后执行对应代码,在代码中会再抛出一个异常,由于在except已经没有代码能捕获了,所以会报错。但是如果没有报错的话,就会去执行finally了

try:
  print('我是try模块中的内容,正常执行的话只会执行try')
  raise AssertionError
  print('由于上面抛出了异常,所以不会执行这个print了')
except AssertionError as e:
  print('发生了AssertionError类型异常,轮到我执行了')
  print('我是报错信息:',e)
  raise AssertionError  #再发生AssertionError异常,不会再捕获了,所以会直接报错
except NameError:
  print('抛出的是AssertionError异常,轮不到我执行')
finally:
  print('正常来说不管有没有异常,我都要执行,如果上面的except不抛异常我就能执行了')

2.8文件操作

如下图代码所示,打开文件有两种方式,第一种是通过open函数赋值给一个变量,第二种是通过with open()的方式。两种方法的区别在于,with open中的代码执行完后,文件就自动关闭无法再使用了,但是如果通过赋值的方式,只要不主动关闭文件,就可以一直使用。

f = open('file_path',mode='r')
content = f.read()
f.close()

with open('file_path',mode='r') as f:
  content = f.read()
  

文件模式

可以看到上面的代码中,有一个mode的参数,这代表打开文件后的操作模式

r:只读模式,以字符串的形式读取,常用于文件读取,如果文件不存在,报错

rb:只读模式,以二进制的形式读取,常用于图片读取,如果文件不存在,报错

w:只写模式,以字符串的形式写入,如果文件存在,清空文件内容。如果文件不存在,创建新文件

wb:只写模式,以二进制的形式写入,如果文件存在,清空文件内容。如果文件不存在,创建新文件

a:追加模式,以字符串的形式写入,如果文件存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件。不能读取文件

ab:追加模式,以二进制的形式写入,如果文件存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件。不能读取文件

r+:读写模式,以字符串的形式读写文件,文件指针将会放在文件的开头。如果文件不存在,报错

rb+:读写模式,以二进制的形式读写文件,文件指针将会放在文件的开头。如果文件不存在,报错

w+:写读模式,以字符串的形式读写文件,如果文件存在,清空文件内容。如果文件不存在,创建新文件

wb+:写读模式,以二进制的形式读写文件,如果文件存在,清空文件内容。如果文件不存在,创建新文件

a+:追加读模式,以字符串的形式写入,如果文件存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件。可以读取文件

ab+:追加读模式,以二进制的形式写入,如果文件存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件。可以读取文件

f = open('file_path',mode='a+')
content = f.read() #读取文件的全部内容
line_content = f.readline() #读取当前的内容,读取后指针会走向下一行
all_line_content = f.readlines() #读取所有行的内容,用列表返回
f.write('abc') #向文件写入内容
line = f.tell() #返回文件当前指针所在行
f.seek(10) #将文件指针移动到指定行
f.close() #关闭文件

还有一些关于文件的常用函数

2.9路径

在python中,有着绝对路径和相对路径两个概念

绝对路径是从文件系统的根目录(通常是硬盘的根目录)开始指定文件或目录的路径。它包含完整的路径信息,从根目录一直到目标文件或目录。绝对路径对于文件系统来说是唯一的,无论当前的工作目录在哪里,都可以精确定位到文件或目录。

例如:C:\Users\Username\Documents\example.txt

相对路径是相对于当前工作目录的路径。它描述了目标文件或目录与当前工作目录之间的位置关系。相对路径通常更简洁,但需要参考当前的工作目录来确定目标文件或目录的位置。

例如:如果当前处在Username目录下,想定位上面绝对路径的文件,那么可以写/Documents/example.txt

那么哪个路径比较好用?我个人更推荐使用相对路径,虽然使用绝对路径可以定位到文件,但是这个路径只在当前电脑适用,换一台电脑,就很可能会报错

三、语法糖

语法糖是指能让代码变得更简洁易读却没有额外功能的代码写法,它使得代码更加美观、易于理解,但实际上只是一种语法上的变形,不会改变底层的语言特性

比较经典的便是for循环,for循环的背后本质是迭代器实现的

还有三目运算符:x = 1 if True else 0,这行代码拆开来就是

if True:
  x = 1
else:
  x = 0

他甚至可以写的更长,例如: x = 1 if a ==0 else 2 if a == 1 else 3 if a == 2 else .......

翻译过来就是如果a==0那么设置x=1否则(如果a==1那么x=2否则(如果a==2那么x=3否则......))是可以无限嵌套的表达式

列表生成式:用[x for x in 迭代对象]的形式书写,可以参考下面的代码

#要注意,列表生成式一定是用[]括起来的,如果用()括起来,生成的就不是一个列表,而是一个生成器

obj = {'key1':1,'key2':2,'key3':3}
key_list = [x for x in obj] #所有的key
value_list = [obj[x] for x in obj] #所有的value

#如果想在列表生成式里对循环迭代的x进行一些操作,比如求平方,也可以这么写
value_list2 = [obj[x]**2 for x in obj]

#把key_list的列表生成式拆开来就是下面这段代码
empty_list = []
for x in obj:
  empty_list.append(x)


  

lambda表达式:格式大概是这样的。

number = [1,2,3]
test = lambda x:x*2
print(test(number))  #输出[1,2,3,1,2,3]
print([test(numbers) for numbers in number]) #输出[2,4,6]

关于lambda表达式我用的很少,不是很清楚其他的用法。不过看起来lambda表达式一般是想快速定义一个固定、简单的函数,却又不想用def的方法来写的时候用的。

四、建议

在编程语言里,python算是相对容易入门的语言,学习难度较低。在学习了基础的语法知识后,可以试着做一些练习题来巩固。可以找一些做题网站例如

Learn Python - Free Interactive Python Tutorial

也可以试着做鸡兔同笼的一些简单脚本。或者根据自己的需要,开发一些实用的脚本也是很好的一种方式。

个人觉得对于初学者来说有一些容易踩坑的地方,把这些地方给搞明白了对于接下来的学习是很有用的。

1、各种数据类型的应用以及数据类型之间的转换

2、全局变量/局部变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值