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'\xe9\x80\x86\xe7\x81\xab' string=str(b,'utf-8') b=b'\xe9\x80\x86\xe7\x81\xab' string=b.decode() # 第一参数默认utf8,第二参数默认strict str1='中国' b=bytes(str1, encoding='utf-8') b=b'\xe9\x80\x86\xe7\x81\xab' 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]\t[%(levelname)s]\t[%(thread)d]\t[%(pathname)s:%(lineno)d]\t%(message)s") hdlr.setFormatter(formatter) logger.addHandler(hdlr) return logger if __name__ == '__main__': myLog = CreateLogger(r"C:\Users\xxx\Desktop\myLog") myLog.info("ok!") myLog.info("ok!") myLog.info("ok!") otherLog = CreateOtherLogger(r'C:\Users\xxx\Desktop\otherLog') 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:\Users\10223394\Desktop\report') #runner.run(suite()) #生成HTML fp = open(r'C:\Users\10223394\Desktop\report.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'\xe4\xb8\xad\xe6\x96\x87' 文件和目录的操作: 文件和目录的操作全部都在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')