0.注释
# 单行注释
''' ''' 多行注释:是一个没有名称的字符串变量
1.数据类型
# Number(数字)
int
long
float 1.23e9
complex 1 + 2j
# String(字符串)
单引号或是双引号包含的字符串
双引号可以包含单引号
使用转义字符
用r'xxx'表示'xxx'内部的字符串默认不转义
多行字符 '''xxx'''
字符串使用的是UTF-8编码,支持中英文
str以字符为单位
每一个str都有自己的编码格式
Python采用的格式化方式和C语言是一致的,用%实现
print("%s %d" % ("ceshi", 2))
# Bytes
Bytes以字节为单位
int和bytes的转换:
to_bytes()
from_bytes()
str和bytes的转换:
b=b'xe9x80x86xe7x81xab'
string=str(b,'utf-8')
b=b'xe9x80x86xe7x81xab'
string=b.decode() # 第一参数默认utf8,第二参数默认strict
str1='中国'
b=bytes(str1, encoding='utf-8')
b=b'xe9x80x86xe7x81xab'
b=str1.encode('utf-8')
print(b)
注意:
bytes只是内存中的一串二进制数据,str是在二进制的基础上加入了解析的方式,本质都是一样的,只是处理的方式不相同
bytes中的x只是一个python的标示符,无实际意义
# Bool(布尔值)
True
False
# None(空值)
# List(列表)
[xxx, yyy ...]
list是一种有序的集合,可以随时添加和删除其中的元素
当索引超出了范围时,Python会报一个IndexError错误,所以要确保索引不要越界,最后一个元素的索引是len(xxx) - 1
下标为-1表示最后一个字符
取出列表的部分元素:
x = ["a", "b", "c", "d"]
y = x[0, 2]; print(y) #["a", "b"] 包左不包右
# Tuple(元组)
(xxx, xxx)
() 空元组
(xxx, )一个元素的元组,必须加逗号,否则就是数学表达式中的小括号,有歧义,单个元素的元组在打印时也会带有逗号
tuple和list非常类似,但是tuple一旦初始化就不能修改
# Dictionary(字典)
使用键-值(key-value)存储,具有极快的查找速度
{k1:v1, k2:v2, ...}
插入:
d[xxx] = yyy xxx存在,后面的值会把前面的值覆盖;xxx不存在,会报错
取值:
yyy = d[xxx] xxx不存在,会报错
通过in判断key是否存在 xxx in d
get(xxx) xxx不存在,返回None
删除:
d.pop(xxx)
# Set(集合)
也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key
{xxx, yyy, ...}
重复元素在set中自动被过滤
add(key)方法添加元素到set中
remove(key)方法删除元素
set和dict的唯一区别仅在于没有存储对应的value,但是set的原理和dict一样
2.计算符号
+ 加
- 减
* 乘
/ 除
// 整除
% 取余
** 乘方
> 大于
< 小于
== 等于
and 与
or 或
not 非
3.条件判断
只有if语句,没有switch语句
if cond1:
xxx
elif cond2:
xxx
else:
xxx
4.循环语句
while语句
while cond:
xxx
for语句
for i in xxx
yyy
使用for循环时,只要作用于一个可迭代对象,for循环就可以正常运行,而我们不太关心该对象究竟是list还是其他数据类型
from collections import Iterable
>>> isinstance('abc', Iterable) # str是否可迭代
注意:range(n)函数,可以生成[0. n)一个整数序列
5.函数
函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”
函数也可当做参数使用
python中,根据实际参数的类型不同,函数参数的传递方式可分为2种,分别为值传递和引用(地址)传递:
值传递:适用于实参类型为不可变类型(字符串、数字、元组);
引用(地址)传递:适用于实参类型为可变类型(列表,字典);
值传递和引用传递的区别是:
函数参数进行值传递后,若形参的值发生改变,不会影响实参的值;而函数参数继续引用传递后,改变形参的值,实参的值也会一同改变。
内置函数:
abs() 求绝对值
max() 接收任意多个参数,并返回最大的那个
数据类型转换函数:
int('123')
int(12.3)
float("13.2")
str(100)
bool(1)
函数定义:
格式:
def funcName():
xxx
默认参数:
def funcName(x = 1):
xxx
必选参数在前,默认参数在后
默认参数是在函数定义的时候产生的,且不会丢失,多次调用使用的是同一块内存,因此会出现如下陷阱:
def addList(l = []):
l.append(""End)
return l;
addList() 返回["End"]
addList() 返回["End", "End"]
可变参数:
def funcName(*numbers)
xxx
函数内部处理时,就是把numbers当做Tuple处理,和传入元组作为参数流程相同,就是语法不一样
关键字参数:
关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict
def funcName(x, y, **param):
xxx
funcName(2, 4, name = 'aaa', age = 20)
命名关键字参数: 解决关键字参数无法限制关键字的缺陷
def person(name, age, *, city, job):
print(name, age, city, job)
和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数
调用方式:person('Jack', 24, city='Beijing', job='Engineer') city和job参数不能少
混合必选参数、可变参数、命名关键字参数,此时命名关键字参数的*可以省略,因为可以通过*args区分
def person(name, age, *args, city, job):
print(name, age, args, city, job)
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用
参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数
虽然可以组合多达5种参数,但不要同时使用太多的组合,否则函数接口的可理解性很差
递归函数:
函数的返回值就是函数的调用,不涉及任何计算
尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环
Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题
列表生成式:
格式:
[expr for i in xxx]
[x * x for x in range(1, 11)] # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
[x * x for x in range(1, 11) if x % 2 == 0] # [4, 16, 36, 64, 100]
[m + n for m in 'ABC' for n in 'XYZ'] # ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
d = {'x': 'A', 'y': 'B', 'z': 'C' }; [k + '=' + v for k, v in d.items()] #['y=B', 'x=A', 'z=C']
生成器:
格式:
g = (expr for i in xxx)
调用:
next(g)
next(g)
next(g) #每次调用都计算出下一个值
lambda表达式:
通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数
lambda表达式就是一个简单的函数,编写更加简单,如果太复杂就不使用lambda表达式,直接定义函数
lambda argument_list: expression 输入是传入到参数列表argument_list的值,输出是根据表达式expression计算得到的值
f = lambda x, y, z : x+y+z
print f(1,2,3) # 6
6.作用域
正常的函数和变量名是公开的(public),可以被直接引用,比如:abc,x123,PI等
一个下划线看头的变量和方法可以被访问,但是不建议访问
两个下划线开头的变量和方法不可以被访问,直接报错
两个下划线开头和两个下划线结尾的变量和方法是特殊的,有特殊用途
7.面向对象编程
class Test:
def __init__(self):
xxx
类是创建实例的模板,而实例则是一个一个具体的对象,各个实例拥有的数据都互相独立,互不影响
成员函数和普通函数的区别是:成员函数的第一个参数永远是self,且调用时不需要显示填入
访问限制:
一个下划线看头的变量和方法可以被访问,但是不建议访问
两个下划线开头的变量和方法不可以被访问,直接报错
两个下划线开头和两个下划线结尾的变量和方法是特殊的,有特殊用途
继承和多态:
class Base:
def def __init__(self):
pass
def func(self):
print("Base")
class Drived(Base):
def __ init__(self):
Base.__ init__()
pass
def func(self):
print("Drived")
pass
子类可以定义和父类相同的方法,此时叫复写,也可实现多态
可以使用Base.func()显式调用父类的同名方法
Python中没有方法重载,成员方法也是对象的属性,当方法名相同时,直接覆盖
获取对象信息:
type() 返回的是Class类型
type库中有很多常量,用于和type()的返回值做对比
types.FunctionType 自定义函数
types.BuiltinFunctionType 内建函数
types.LambdaType lambda表达式
...
isinstance() 判断继承关系
dir()函数获得一个对象的所有属性和方法,它返回一个包含字符串的list
类属性和实例属性:
class Test:
xxx = yyy 类属性
def __init__(self):
self.xxx 实例属性
调用类属性的方式:Test.xxx
给实例单独绑定的属性,只影响实例自身,不影响其它实例
限制给单个实例添加属性的方法:
class Test():
__slots__ = ('name', 'age') #用tuple定义允许绑定的属性名称
使用@property
class Test():
@property #设置属性
def name(self):
return self._name
@name.setter #设置setter
def name(self, other):
print("setter")
self._name = other
if __name__ == '__main__':
t = Test()
t.name = "abc"
print(t.name)
功能:可以用于参数检查
经典类和新式类的区别在于:
经典类是默认没有派生自某个基类的,而新式类是默认派生自object这个基类的,Python3默认是新式类
经典类在类多重继承的时候是采用从左到右深度优先原则匹配方法的.而新式类是采用C3算法(不同于广度优先)进行匹配的
不建议使用多重继承
初始化的时候,建议使用super(),不建议使用 类名.__init__() 的方式
类中的一些特殊方法:
__str__ 打印时调用,打印的内容就是函数的返回值
__slots__ 限制给实例对象单独添加属性
__len__ 执行len()函数时调用
__iter__ 如果一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,
然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1 # 初始化两个计数器a,b
def __iter__(self):
return self # 实例本身就是迭代对象,故返回自己
def __next__(self):
self.a, self.b = self.b, self.a + self.b # 计算下一个值
if self.a > 100000: # 退出循环的条件
raise StopIteration()
return self.a # 返回下一个值
__getitem__ 让类对象可以向访问列表的方式使用
__getattr__ 当访问的类属性不存在时,就会调用该方法
__call__() 直接对实例进行调用
class Student(object):
def __init__(self, name):
self.name = name
def __call__(self):
print('My name is %s.' % self.name)
>>> s = Student('abc')
>>> s() # self参数不要传入
My name is abc.
枚举类:
枚举类中,不应该存在key相同的枚举项(类变量)
不允许在类外直接修改枚举项的值
enum模块是系统内置模块,可以直接使用import导入
# 导入枚举类
from enum import Enum
# 继承枚举类
class color(Enum):
YELLOW = 1
BEOWN = 1
RED = 2
GREEN = 3
PINK = 4
可以再class上加@unique,可以帮助我们检查保证没有重复值
8.错误处理
try:
xxx #有可能抛出异常的代码
except xxx as e: #捕获特定异常的分支
yyy
finally: #最后一定会执行的分支,一般做善后处理
zzz
记录错误信息:
Logging模块主要是python提供的通用日志系统,使用的方法其实挺简单
import logging
import logging.handlers
def CreateLogger(logFile = 'batch'):
#RotatingFileHandler回滚logging的方式来控制LOG文件的个数和每个LOG文件的上限大小
handler = logging.handlers.RotatingFileHandler(str(logFile) + '.LOG', maxBytes = 1024 * 1024 * 500, backupCount = 5)
#初始化日志的格式
fmt = '%(asctime)s - %(filename)s:%(lineno)s - %(name)s - %(message)s'
formatter = logging.Formatter(fmt)
handler.setFormatter(formatter)
#新增一个日志,每调用一次都可以新增一个日志文件
logger = logging.getLogger(str(logFile))
#设置handler,包括文件路径,处理方式等
logger.addHandler(handler)
#设置日志级别
logger.setLevel(logging.INFO)
return logger
def CreateOtherLogger(testName):
logger = logging.getLogger(testName)
logger.setLevel(logging.INFO)
hdlr = logging.FileHandler(testName + '.LOG')
hdlr.setLevel(logging.INFO)
formatter = logging.Formatter("[%(asctime)s] [%(levelname)s] [%(thread)d] [%(pathname)s:%(lineno)d] %(message)s")
hdlr.setFormatter(formatter)
logger.addHandler(hdlr)
return logger
if __name__ == '__main__':
myLog = CreateLogger(r"C:UsersxxxDesktopmyLog")
myLog.info("ok!")
myLog.info("ok!")
myLog.info("ok!")
otherLog = CreateOtherLogger(r'C:UsersxxxDesktopotherLog')
otherLog.info("Also ok!")
otherLog.info("Also ok!")
otherLog.info("Also ok!")
9.单元测试
和CPP的CppUnit思想相同
import unittest
import xmlrunner #需要单独安装
import HTMLTestRunner #需要单独安装
#https://www.cnblogs.com/puresoul/p/7490881.html
class Test1(unittest.TestCase): #测试类
def test_1(self):
self.assertEqual(1, 1)
def test_2(self):
self.assertEqual(2, 3)
class Test2(unittest.TestCase): #测试类
def test_3(self):
self.assertEqual(3, 3)
def test_4(self):
self.assertEqual(4, 4)
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(Test1)) #添加一个测试类
suite.addTest(Test2("test_3")) #添加一个测试类中的一个用例
suite.addTest(Test2("test_4"))
return suite
if __name__ == '__main__':
#生成XML
#runner = xmlrunner.XMLTestRunner(output=r'C:Users10223394Desktop
eport')
#runner.run(suite())
#生成HTML
fp = open(r'C:Users10223394Desktop
eport.html', "wb")
runner = HTMLTestRunner.HTMLTestRunner(stream=fp,
title=u'接口自动化测试报告,测试结果如下:',
description=u'用例执行情况:')
runner.run(suite())
fp.close()
10.IO编程
常用函数:
open() 打开文件
read() 读取文件
close() 关闭文件
readline() 可以每次读取一行内容
readlines() 一次读取所有内容并按行返回list
常见用法:
with open('/path/to/file', 'r') as f: #try ... finally的用法相同,自己关闭文件,更简洁安全
print(f.read())
内存读写:
StringIO:在内存中读写str
from io import StringIO
f = StringIO()
f.write('hello')
f.write(' ')
f.write('world!')
print(f.getvalue()) #打印hello world!
BytesIO:在内存中读写bytes
from io import BytesIO
f = BytesIO()
f.write('中文'.encode('utf-8'))
print(f.getvalue()) #打印b'xe4xb8xadxe6x96x87'
文件和目录的操作:
文件和目录的操作全部都在os模块中
常用接口:
os.path.abspath('.') # 查看当前目录的绝对路径:
os.path.join('/Users', 'testdir') #拼接目录
os.mkdir('/testdir') # 然后创建一个目录
os.rmdir('/testdir') # 删掉一个目录
os.path.split() # 把一个路径拆分为两部分,后一部分总是最后级别的目录或文件名
os.path.splitext() # 直接获取文件扩展名
os.rename() # 对文件重命名
os.remove() # 删掉文件
shutil.rmtree(path) # 递归删除文件夹,shutil库
os.system(command) # 用来运行shell命令
os.path.isfile()
os.path.isdir() # 函数分别检验给出的路径是一个文件还是目录
os.path.exists() # 用来检验给出的路径是否真地存在
os.path.getsize(name) # 获得文件大小
例子:编译文件夹
for parent,dirnames,filenames in os.walk(rootdir): #三个参数:分别返回1.父目录 2.所有文件夹名字(不含路径) 3.所有文件名字
for dirname in dirnames: #输出文件夹信息
print "parent is:" + parent
print "dirname is" + dirname
for filename in filenames: #输出文件信息
print "parent is": + parent
print "filename is:" + filename
print "the full name of the file is:" + os.path.join(parent,filename) #输出文件路径信息
序列化:
把变量从内存中变成可存储或传输的过程称之为序列化
pickle模块实现序列化(同是python语言之间的传递)
pickle.dumps() # 把任意对象序列化成一个bytes
pickle.load() # 反序列化出对象
不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML或JSON
json模块提供Python对象到JSON格式
[] () {} 和 JSON之间的转换
json.dumps() #把Python序列化为JSON格式
json.loads() #把JSON格式反序列化为Python
python对象和JSON之间的转换
class Student(object):
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
def student2dict(std):
return {
'name': std.name,
'age': std.age,
'score': std.score
}
json.dumps(s, default = student2dict) #把Python对象序列化为JSON格式
def dict2student(d):
return Student(d['name'], d['age'], d['score'])
json.loads(json_str, object_hook=dict2student) #把JSON格式反序列化为Python对象
11.多进程和多线程
多进程:
multiprocessing模块实现跨平台版本的多进程模块
Process(target = run_proc, args = ('test',)) # 创建一个新进程
p.start() # 启动进程
进程池:
p = Pool(4) # 创建进程池,共4个
for i in range(5):
p.apply_async(long_time_task, args=(i,)) # 依次启动一个进程
进程之间通信:
Queue通信:
from multiprocessing import Process, Queue
import os, time, random
# 写数据进程执行的代码:
def write(q):
print('Process to write: %s' % os.getpid())
for value in ['A', 'B', 'C']:
print('Put %s to queue...' % value)
q.put(value) # 写入数据
time.sleep(random.random())
# 读数据进程执行的代码:
def read(q):
print('Process to read: %s' % os.getpid())
while True:
value = q.get(True) # 读取数据
print('Get %s from queue.' % value)
if __name__=='__main__':
q = Queue() # 父进程创建Queue,并传给各个子进程
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
pw.start() # 启动子进程pw,写入
pr.start() # 启动子进程pr,读取
多线程:
Python的标准库提供了两个模块:_thread和threading,_thread是低级模块,threading是高级模块,对_thread进行了封装,一般使用threading模块
t = threading.Thread(target = loop, name = 'LoopThread') # 创建一个线程
t.start() # 启动一个线程
Lock
lock = threading.Lock() # 初始化互斥锁
lock.acquire() # 获取互斥锁
lock.release() # 释放互斥锁
Python解释器由于设计时有GIL全局锁,导致了多线程无法利用多核。多线程的并发在Python中就是一个美丽的梦
12.正则表达式
用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的。
re模块提供了全部的正则表达式功能
match()方法判断是否匹配,如果匹配成功,返回一个Match对象,否则返回None
除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用()表示的就是要提取的分组(Group)
m = re.match(r'^(d{3})-(d{3,8})$', '010-12345')
m.group(0) # '010-12345'
m.group(1) # '010'
m.group(2) # '12345'
# group(0)永远是原始字符串,group(1)、group(2)……表示第1、2、……个子串
当我们在Python中使用正则表达式时,re模块内部会干两件事情:
1.编译正则表达式,如果正则表达式的字符串本身不合法,会报错;
2.用编译后的正则表达式去匹配字符串。
如果一个正则表达式要重复使用几千次,出于效率的考虑,我们可以预编译该正则表达式,接下来重复使用时就不需要编译这个步骤了,直接匹配
import re
# 编译:
re_telephone = re.compile(r'^(d{3})-(d{3,8})$')
# 使用:
re_telephone.match('010-12345').groups()
('010', '12345')
re_telephone.match('010-8086').groups()
('010', '8086')