python基础知识点

一 数据类型

  1. Number   数字
  2. String 字符串
  3. Tuple 元组
  4. List 列表
  5. Dict 字典
  6. Set 集合

不可变:number string tuple

可变:list dict set

number 数据类型下的数值类型:int float bool complex

类的深拷贝和浅拷贝?

变量的赋值:只是形成两个变量,实际上还是指向同一个对象。

浅拷贝:拷贝时,对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象。

深拷贝:使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同。

1 列表操作

lst.append(x) 在列表lst最后增加一个元素

lst.insert(index, x) 在列表中第index位置增加一个元素

lst.clear() 清除列表lst中所有元素

lst.pop(index) 将列表中第index位置的元素取出,并从列表中将其删除

lst.remove(x) 将列表中出现的第一个元素x删除

lst.reverse(x) 将列表lst中的元素反转

lst.copy() 拷贝列表中的所有元素,生成一个新的列表

列表生成式

lst = [ex for item in range]

lst = [ex for item in range if condition]

lst = [random.randint(1, 100) for _ in range(10)

lst = [i for i in range(10) if i%2 == 0]]

二维列表

lst2 = [ [ j for j in range(5)] for i in range(4)]

citys = ["jinan", "qingdao", "yantai", "zibo"]
 

extend() 函数、append()函数、+ 与 += 功能比较? 

append()是向列表尾部追加一个新元素,列表中只占一个索引位,在原有列表上增加。 

extend()向列表尾部追加一个列表,将列表中的每个元素都追加进来,在原有列表上增加。 

+=与extend()在效果上具有相同的功能,但是实际上生成了一个新的列表来存放这两个列表的和,只能用在两个列表相加上,+=与extend()效果一样。

元祖操作

t = ( i for i in range (1,4))  生成器对象,必须下面tuple 强转一下(generater object)

t= tuple(t) 知识点 __next__ 取出后就没有了

t = (i for i in range(4))

print(t.__next__())

在Python中,拆包(unpacking)和解包(unpacking)是指将一个可迭代对象(如列表、元组等)的元素分解成独立的变量。

解包(Packing)将多个变量的值组合成一个元组

a = 1
b = 2
c = 3
packed = a, b, c
print(packed)  # 输出(1, 2, 3)

使用星号表达式展开列表中的子列表

list_example = [1, 2, 3]
other_list = [*list_example, 4, 5]
print(other_list)  # 输出[1, 2, 3, 4, 5]

拆包(Unpacking)将迭代对象元素赋值给变量

# 列表
list_example = [1, 2, 3]
a, b, c = list_example
print(a)  # 输出1
print(b)  # 输出2
print(c)  # 输出3
 
# 元组
tuple_example = (4, 5, 6)
x, y, z = tuple_example
print(x)  # 输出4
print(y)  # 输出5
print(z)  # 输出6

list_example = [1, 2, 3, 4, 5]
a, b, *rest = list_example
print(a)  # 输出1
print(b)  # 输出2
print(rest)  # 输出[3, 4, 5]

3 字典操作

d.keys() 获取所有的key数据

d.values() 获取所有的value数据

d.pop(key,default)  key存在获取相应的value,同时删除key-value 对,否则获取默认值

d.popitem() 随机从字典中取出一个key-value对,结果为元祖类型,同时将该key-value从字典中删除

d.clear()   清空字典中所有的key-value对

字典生成式

d= {key:value for key,value in zip(lst1,lst2)}

# 创建一个示例字典
student_grades = {"Alice": 95, "Bob": 88, "Charlie": 92, "David": 78}

# 遍历字典的键
for name in student_grades:
    print(name)

# 遍历字典的值
for grade in student_grades.values():
    print(grade)

# 遍历字典的键值对
for name, grade in student_grades.items():
    print(f"{name}: {grade}")

集合操作

s.add(x) 如果x不在集合s中,则将x添加到集合s

s.remove(x) 如果x在集合中,将其删除,如果不在集合中,程序报错。

s.clear() 清除集合中所有元素

序列的相关操作

x in s 如果x是s的元素,结果为True,否则为False

x not in s

len(s)

max(s)

min(s)

s.index(x) 序列s中第一次出现元素x的位置

s.count(x) 序列s中出现x的总次数

类型转换函数

int(x) 将x转换为整数类型

float(x) 将x转换为浮点类型

str(x) 将x转换为字符串

chr(x) 将整数x转换为一个字符unicode表

ord(x) 将一个字符x转换为其对应的整数值 unicode表

十进制与其他进制的转换

hex(x) 将一个整数x转换为一个十六进制字符串

oct(x) 将一个整数x转换为一个八进制字符串

bin(x) 将一个整数x转换为一个二进制字符串

什么是大端和小端?

一般操作系统都是小端,而通讯协议是大端的。

以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value:

Big-Endian: 低地址存放高位,如下:

高地址

        ---------------

        buf[3] (0x78) -- 低位

        buf[2] (0x56)

        buf[1] (0x34)

        buf[0] (0x12) -- 高位

        ---------------

        低地址

Little-Endian: 低地址存放低位,如下:

高地址

        ---------------

        buf[3] (0x12) -- 高位

        buf[2] (0x34)

        buf[1] (0x56)

        buf[0] (0x78) -- 低位

        --------------

低地址

字符串的编码和解码 str-》bytes

str.encode(encoding = ‘utf-8’,errors=‘strict/ignore/replace’)

bytes.decode(encoding = ‘utf-8’,errors=‘strict/ignore/replace’)

errors 编码过程出错的解决方案,strict直接报错ingore 忽略 replace ??

json.dumps(obj) 将python数据类型转成json格式过程,编码过程

json.loads(s) 将json格式字符串转成python数据类型,解码过程

json.dump(obj, file) 将python数据类型转成json格式,将转换结果存储到文件file中

json.load(file) 将json格式字符串转成python数据类型,从文件file中读入数据

数据的验证

数据的验证是指程序对用户输入的数据进行“合法”性验证

str.isdigit() 所有字符都是数字(阿拉伯数字)

str.isnumeric()  所有的字符都是数字

str.isalpha() 所有的字符都是字母(包含中文字符)

str.isalnum() 所有的字符都是数字或字母(包含中文字符)

str.islower() 所有的字符都是小写

str.isupper() 所有的字符都是大写

str.istitle() 所有的字符都是首字母大写

str.ispace() 所有的字符都是空白字符(\n \t等)

字符串的常用操作

str.lower() 将str字符串全部转成小写字母,结果为一个新的字符串

str.upper() 将str字符串全部转成大写字母,结果为一个新的字符串

str.split(sep=None) 把str按照指定的分隔符sep进行分割,结果为列表类型

str.count(sub) 结果为sub这个字符串在str中出现的次数

str.find(sub) 查询sub这个字符串在str中是否存在,如果不存在的结果为-1,如果存在,结果为sub首次出现的索引。

str.index() 功能与find()相同,区别在于要查询的子串sub不存在,程序报错。

str.startswith(s) 查询字符串str是否以子串s开头

str.endswith(s) 查询字符串str是否以子串结尾

str.replace(old, news) 使用news替换字符串str中所有的old字符串,结果为一个新的字符串。

str.center(width, fillchar) 字符串str在指定的宽度范围居中,可以使用fillchar进行填充

str.join(iter) 在iter中的每个元素的后面都增加一个新的字符串str

str.strip(chars) 从字符串中去掉左侧和右侧chars中列出的字符串

str.lstrip(chars) 从字符串中去掉左侧chars中列出的字符串

str.rstrip(chars) 从字符串中去掉右侧chars中列出的字符串

9 字符串的拼接和去重

1.使用str.join() 方法进行拼接字符串

s1 = ‘hello’ s2 = ‘world’

‘’.join([s1, s2])

‘*’.join([s1, s2])

2.直接拼接

Print(‘hello’,’word’)

Print(‘%s%s’%(s1,s1))

3.使用格式化字符串进行拼接

str = 'hi'

print('tom, %s' %str)

new_s2 = ''

for i in range(len(s)):

        if s[i] not in new_s2:

                new_s2 += s[i]

print(new_s2)

new_s3 = set(s)

lst = list(new_s3)

lst.sort(key=s.index)

print(''.join(lst))

10 运算符的优先级

幂运算 》取反 》算数运算符 》位运算符 》 比较运算符 》赋值运算符

11 格式化字符串的三种方式

占位符:%s 字符串格式  %d 十进制整数格式 %f 浮点数格式

f-string:比{}标明被替换的字符

str.format():模版字符串。format{,逗号分隔的参数}

: 引导符号 ,千位分隔符 .精度 类型

print(‘{0:*<20}’.format(s)) 字符串的显示宽度为20,左对齐,空白部分使用*号填充

print(‘{0:*>20}’.format(s)) 右对齐

print(‘{0:*^20}’.format(s)) 居中对齐

千位分隔符

print(‘{0:,}.format(98776666655)’)

print(‘0:.2f’.format(7.888)) 保留两位小数,浮点数小数部分的精度

print(‘0:.5’.format(‘helloword’)) 字符串类型,。表示是最大的显示长度

整数类型

s = 88

print(‘二进制:{0:b}’, ‘十进制:{0:d}’, 八进制:{0:o}’, 十六进制:{0:x}’, 十六进制:{0:X}’)。format(s)

浮点数类型 b=3.14556

print(‘{0:.2f}, {0:.2E}, {0:.2e},{0:.2%}’.format(b))

12 生成器

在python中,这种一边循环一边计算的机制,称为生成器。

列表内存长度固定,有限,访问前面元素,后面元素用不到浪费。,

1、元组生成式

2、定义一个函数,函数中使用yield关键字,调用函数,接收调用的结果,得到的结果就是生成器,借助于next(),__next__()得到元素;

class FibIterator(object):
    def __init__(self):
        self.num1 = 1
        self.num2 = 1

    def __iter__(self):
        """迭代器的__iter__返回自身即可"""
        return self

    def __next__(self):
        """被next()函数调用来获取下一个数"""
        try:
            temp_num = self.num1
            self.num1, self.num2 = self.num2, self.num1 + self.num2
            return temp_num
        except StopIteration as e:
            raise e


fib = FibIterator()
while True:
    print(next(fib))

# for i in fib:
#     print(i)
#     time.sleep(1)
def generator_test():
    while True:
        print("-----1-----")
        num = yield 100
        print("----2----", "num=", num)


g = generator_test()

print(g.send(None))
# print(g.send(11))
print(g.send(22))

def fib_generator():
    num1 = 1
    num2 = 1
    while True:
        temp = num1
        num1, num2 = num2, num1 + num2
        yield temp


fib = fib_generator()

while True:
    print(next(fib))

13 迭代器

迭代器是一个可以记住遍历的位置的对象,迭代器对象从第一个元素开始访问,直到所有元素被访问完毕,迭代器只能往前不会往后。

可迭代的对象,1、生成器 2、元组 列表 集合 字典 字符串

迭代器:可以被next()函数调用并不断返回下一个值的对象称为迭代器。iterator

生成器是迭代器,元组 列表 集合 字典 字符串通过iter()函数转换成为迭代器

from collections.abc import Iterable, Iterator

class Mylist(object):
    def __init__(self):
        self.container = []
        self.current = 0

    def add(self, item):
        self.container.append(item)

    def __iter__(self):

        return self

    def __next__(self):
        if self.current < len(self.container):
            item = self.container[self.current]
            self.current += 1
            return item
        else:
            self.current = 0
            raise StopIteration

mylist = Mylist()
mylist.add('1')
mylist.add('2')
mylist.add('3')
mylist.add('4')

# for num in mylist:
#     print(num)
#
# for num in mylist:
#     print(num)
#
# for num in mylist:
#     print(num)
print('mylist是否是可迭代对象', isinstance(mylist, Iterable))
print('mylist_iter是迭代器', isinstance(mylist, Iterator))

# stu_list = [x for x in mylist]
while True:
    print(next(mylist))

二、相关

python运行常见异常

1、ZeroDivisionError 当除数为0时,引发的异常。 

2、IndexError 索引超出范围所引发的异常

3、KeyError 字典取值时key不存在的异常 

4、NameError 使用一个没有声明的变量时引发的异常 

5、SyntaxError python中的语法错误 

6、ValueError 传入的值错误 

7、AttributeError 属性或方法不存在的异常 

8、TypeError 类型不合适引发的异常 

9、IndentationError 不正确的缩进引发的异常

抛出异常

Python 使用 raise 语句抛出一个指定的异常。

raise语法格式如下:

raise [Exception [, args [, traceback]]]

raise Exception('x 不能大于 5。x 的值为: {}'.format(x))

# 捕获所有异常
try:
    f = open("D:/123.txt", "r", encoding="UTF-8")
except Exception as e:
    print("出现异常了")
    f = open("D:/123.txt", "w", encoding="UTF-8")
else:
    print("好高兴,没有异常。")
finally:
    print("我是finally,有没有异常我都要执行")
    f.close()

2 正则表达式

元字符:具有特殊意义的字符,例如:^ 和 $ 分别表示匹配的开始和结束

. 匹配任意字符(除\n)

\w 匹配字母、数字、下划线

\W 匹配非字母数字下划线

\s 匹配任意空白字符

\S 匹配任意非空白字符

\d 匹配任意十进制数

限定符:用于限定匹配的次数

? 匹配前面的字符0次或1次

+ 匹配前面的字符1次或多次

* 匹配前面的字符0次或多次

{n}匹配前面的字符n次

{n,} 匹配前面的字符最少n次

{n,m} 匹配前面的字符最小n次,最多m次

其他字符:

区间字符[]  匹配[]中所指定的字符

排除符号^ 匹配不在「」中指定的字符

选择字符 | 用于匹配|左右的任意字符

转义字符 \. .不再是元字符,作为普通字符使用

[\u4e00-\u9fa5] 匹配任意一个汉字

分组() 改变限定符的作用

Python中的内置模块,用于实现python中正则表达式操作

re.match(pattern, string, flags=0)

   用于从字符串的开始位置进行匹配,如果起始位置匹配成功,结果为Match对象,否则结果为None

re.search(pattern, string, flags=0)

   用于在整个字符串中搜索第一个匹配的值,如果匹配成功,结果为Match对象,否则结果为None

re.findall(pattern, string, flags=0)

   用于在整个字符串搜索所有符合正则表达式的值,结果是一个列表类型

re.sub(pattern, repl,string, count,flags=0)

   用于实现对字符串中指定子串的替换

re.split(pattern, string, maxsplit,flags=0)

   字符串中的split()方法功能相同,都是分隔符字符串

"""
演示Python正则表达式使用元字符进行匹配
"""
import re

# s = "itheima1 @@python2 !!666 ##itccast3"
#
# result = re.findall(r'[b-eF-Z3-9]', s)   
# 字符串前面带上r的标记,表示字符串中转义字符无效,就是普通字符的意思
# print(result)

# 匹配账号,只能由字母和数字组成,长度限制6到10位
# r = '^[0-9a-zA-Z]{6,10}$'
# s = '123456_'
# print(re.findall(r, s))
# 匹配QQ号,要求纯数字,长度5-11,第一位不为0
# r = '^[1-9][0-9]{4,10}$'
# s = '123453678'
# print(re.findall(r, s))
# 匹配邮箱地址,只允许qq、163、gmail这三种邮箱地址
# abc.efg.daw@qq.com.cn.eu.qq.aa.cc
# abc@qq.com
# {内容}.{内容}.{内容}.{内容}.{内容}.{内容}.{内容}.{内容}@{内容}.{内容}.{内容}
r = r'(^[\w-]+(\.[\w-]+)*@(qq|163|gmail)(\.[\w-]+)+$)'
# s = 'a.b.c.d.e.f.g@qq.com.a.z.c.d.e'
s = 'a.b.c.d.e.f.g@126.com.a.z.c.d.e'
print(re.match(r, s))
"""
演示Python正则表达式re模块的3个基础匹配方法
"""
import re

s = "1python itheima python python"
# match 从头匹配
result = re.match("python", s)
print(result)
# print(result.span())
# print(result.group())
# search 搜索匹配

result = re.search("python2", s)
print(result)
# findall 搜索全部匹配
result = re.findall("python", s)
print(result)

内置模块 logging

logging的四大组件:

1、日志器 Logger --->入口

2、处理器 Handler---》执行者 决定日志在不同端进行输出 ( 日志文件 控制台)

3、格式器 Formatter---》日志输入的内容

4、过滤器 Filter----》输出感兴趣日志信息,过滤掉不感兴趣的日志信息

关系:1个日志器可以有多个处理器,

每个处理器可以各自的格式器及过滤器

4、logging模块的应用

从低到高日志级别:

debug 调试信息

info 关键事件描述

warning 警告信息

error 错误信息

critical 严重错误信息

import logging
import os
import time
import colorlog


log_colors_config = {
    'DEBUG': 'white',
    'INFO': 'green',
    'WARNING': 'yellow',
    'ERROR': 'red',
    'CRITICAL': 'bold_red',
}


class LoggerUtil:
    def create_log(self, logger_name='log'):
        # 创建一个日志对象
        self.logger = logging.getLogger(logger_name)
        # 设置全局的日志级别(critical > error > warning > info > debug)
        self.logger.setLevel(logging.DEBUG)
        # 防止日志重复
        if not self.logger.handlers:
            # ---------文件日志------------
            # 获得日志文件的名称
            self.file_log_path = os.path.abspath(os.getcwd().split('common')[0])+'/logs/' + 'logs_' +str(int(time.time()))+".log"
            # 创建文件日志的控制器
            self.file_handler = logging.FileHandler(self.file_log_path, encoding='utf-8')
            # 设置文件日志的级别
            self.file_handler.setLevel(logging.DEBUG)
            # 设置文件日志的格式
            self.file_handler.setFormatter(logging.Formatter('[%(asctime)s] %(filename)s->%(funcName)s line:%(lineno)d [%(levelname)s] %(message)s'))
            # 将控制器加入到日志对象
            self.logger.addHandler(self.file_handler)
            # ------------控制台日志--------------
            # 创建控制台日志的控制器
            self.console_handler = logging.StreamHandler()
            # 设置控制台日志的级别
            self.console_handler.setLevel(logging.DEBUG)
            # 设置控制台日志的格式
            console_formatter = colorlog.ColoredFormatter(
                fmt='%(log_color)s[%(asctime)s.%(msecs)03d] %(filename)s -> %(funcName)s line:%(lineno)d [%(levelname)s] : %(message)s',
                datefmt='%Y-%m-%d  %H:%M:%S',
                log_colors=log_colors_config
            )
            self.console_handler.setFormatter(console_formatter)
            # 将控制器加入到日志对象
            self.logger.addHandler(self.console_handler)
        return self.logger


# 函数:输出info日志
def info_log(log_message):
    LoggerUtil().create_log().info(log_message)


# 函数:输出debug日志
def debug_log(log_message):
    LoggerUtil().create_log().debug(log_message)


# 函数:输出错误日志
def error_log(log_message):
    LoggerUtil().create_log().error(log_message)
    raise Exception(log_message)


if __name__ == '__main__':
    info_log("aaaa")
    debug_log("bbbb")
    error_log("cccc")

4 保留字和标识符

35个保留字print(keyword.kwlist):指在python中被赋予特定意义的一些单词,在开发程序时,不可以把这些保留字作为变量,函数,类,模块和其他对象的名称来使用。 

标识符:就是一个名字,为变量,函数,类,模块和其他对象来命名的

5 变量的作用域

是指变量起作用的范围,根据范围作用的大小可分为局部变量和全局变量

局部变量:在函数定义处的参数和函数内部定义的变量

局部变量作用范围:仅在函数内部,函数执行结束,局部变量的生命周期也结束。

全局变量:在函数外定义的变量或函数内部使用global关键字修饰的变量。

作用范围:整个程序,程序运行结束,全局变量生命周期才结束。

6 文件和os模块

文件的概述:存储在计算机的存储设备中的一组数据序列就是文件,不同类型的文件通过后缀名进行区分

文本文件:由于编码格式的不同,所占磁盘空间的字节数不同

二进制文件:没有统一的编码,文件直接由0和1组成,需要使用指定的软件才能打开

os.getcwd() 获取当前.py文件所在的项目路径

os.path.dirname(path) 获取file_path上一级路径

os.path.join(path1,path2) 路径拼接

os.path.split(path1) 路径拆分 目录+文件

os.mkdir(path_A)  在已存在目录下的最后一级创建新的文件夹,如果上级目录中有不存在的路径, 则会抛出异常

makedirs() : 传入一个path路径,生成一个递归文件夹(多层级文件夹)(E:\java文件\cesi_fuck\hua_wei) 这就是一个多层级文件夹

os.path.abspath() 返回指定目录的“绝对路径”

with语句又称上下文管理器,在处理文件时,无论是否产生异常,都能保证with语句执行完毕后关闭已经打开的文件,这个过程是自动的,无需手动操作。

class File(object):
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def __enter__(self):
        print('entering file')
        self.f = open(self.filename, self.mode)
        return self.f

    def __exit__(self, *args):
        print('exiting file')
        self.f.close()


with File('text.txt', 'w') as f:
    print('writting')
    f.write('hello world')


from contextlib import contextmanager

@contextmanager
def my_open(path, mode):
    f = open(path, mode)
    yield f
    f.close()


with my_open('text.txt', 'w') as f:
    print('writting')
    f.write('hello world 222222')

import os
import os.path


def mkdirs(path, num):
    for item in range(1, num+1):
        os.mkdir(path + '/' + str(item))


if __name__ == '__main__':
    path = './newdir'
    if not os.path.exists(path):
        os.mkdir(path)

    num = eval(input('请输入创建文件个数:'))
    mkdirs(path, num)
# 打开文件,以读取模式打开
f = open("D:/word.txt", "r", encoding="UTF-8")
# 方式1:读取全部内容,通过字符串count方法统计itheima单词数量
# content = f.read()
# count = content.count("itheima")
# print(f"itheima在文件中出现了:{count}次")
# 方式2:读取内容,一行一行读取
count = 0       # 使用count变量来累计itheima出现的次数
for line in f:
    line = line.strip()     # 去除开头和结尾的空格以及换行符
    words = line.split(" ")
    for word in words:
        if word == "itheima":
            count += 1      # 如果单词是itheima,进行数量的累加加1
# 判断单词出现次数并累计
print(f"itheima出现的次数是:{count}")
# 关闭文件
f.close()

"""
演示文件操作综合案例:文件备份
"""

# 打开文件得到文件对象,准备读取
fr = open("D:/bill.txt", "r", encoding="UTF-8")
# 打开文件得到文件对象,准备写入
fw = open("D:/bill.txt.bak", "w", encoding="UTF-8")
# for循环读取文件
for line in fr:
    line = line.strip()
    # 判断内容,将满足的内容写出
    if line.split(",")[4] == "测试":
        continue        # continue进入下一次循环,这一次后面的内容就跳过了
    # 将内容写出去
    fw.write(line)
    # 由于前面对内容进行了strip()的操作,所以要手动的写出换行符
    fw.write("\n")

# close2个文件对象
fr.close()
fw.close()      # 写出文件调用close()会自动flush()

7 time和datetime模块

获取时间元组 time.localtime()

获取时间戳 time.time()

把时间元组转化成时间戳:time.mktime(时间元组)

把时间戳转化时间元组:time.localtime(时间戳)

字符串与时间元组相互转化

时间元组-》字符串:time.strftime()

字符串--》时间元组:time.strptime()

timestr=time.strftime("%Y/%m/%d %H:%M:%S",time.localtime())

ttup2=time.strptime(timestr,"%Y/%m/%d %H:%M:%S")

Python time gmtime()方法

描述

Python time gmtime() 函数将一个时间戳转换为 UTC 时区(0 时区)的 struct_time 对象,可选的参数 sec 表示从 1970-1-1 以来的秒数。

struct_time 对象包含有关时间的各种信息,如年、月、日、小时、分钟等。

datetime.timetuple()

参数

返回值

time.struct_time对象

dt=datetime.datetime(2018,6,24,16,56,45,13) #(年、月、日、时、

分、秒、微秒) #以时间元祖创建

dt=datetime.datetime.today() #获得当前时间datetime

dt=datetime.datetime.now() #获得当前时间datetime

把datetime转换成时间戳

datetime.datetime.now().timestamp()

把时间戳转换成datetime

datetime.datetime.fromtimestamp(时间戳)

按datetime转换成字符串:

dt.strftime("%Y-%m-%d")

dt.strftime("%Y-%m-%d %H:%M:%S")

把字符串转换成datetime

datetime.datetime.strptime('2015-6-1 18:19:59.10', '%Y-%m-%d

%H:%M:%S.%f')

截取时间元组中的部分:

dt.year #年

dt.month #月

dt.day #日

dt.date() #日期

dt.time() #时间

dt.weekday() #星期

dt.isoweekday() #星期

(1)datetime.timedelta()日期间隔 返回类型为 datetime.timedelta

(2)两个datetime.datetime类型相减或者两个datetime.date类型相减的结果就是daftetime.timedelta类型

8 模块导入

"""
演示自定义模块
"""

# 导入自定义模块使用
# import my_module1
# from my_module1 import test
# test(1, 2)

# 导入不同模块的同名功能
# from my_module1 import test
# from my_module2 import test
# test(1, 2)
# __main__变量
# from my_module1 import test

# __all__变量
from my_module1 import *
test_a(1, 2)
# test_b(2, 1)
"""
演示Python的包
"""
# 创建一个包
# 导入自定义的包中的模块,并使用
# import my_package.my_module1
# import my_package.my_module2
#
# my_package.my_module1.info_print1()
# my_package.my_module2.info_print2()

# from my_package import my_module1
# from my_package import my_module2
# my_module1.info_print1()
# my_module2.info_print2()

# from my_package.my_module1 import info_print1
# from my_package.my_module2 import info_print2
# info_print1()
# info_print2()

# 通过__all__变量,控制import *
from my_package import *
my_module1.info_print1()
my_module2.info_print2()

​​​​​​​9 引用和参数

形参和实参区别

形参和实参是编程中用于函数调用的两个重要概念,它们在函数定义和调用时扮演不同的角色:

形参(Parameter)。形参是函数声明或定义中指定的变量,用于接收调用函数时传递的参数,形参在函数定义时创建,但不占用内存空间,只在函数被调用时分配内存单元,并在函数执行结束后立即释放这些内存单元,因此,形参只在定义它的函数内部有效。

实参(Argument)。实参是在调用函数时传递给形参的具体值,可以是常量、变量、表达式,或者其他更复杂的数据类型,实参在调用函数之前必须具有确定的值,以便将该值传递给形参,实参的生命周期独立于函数调用,它在函数外部定义,并在整个主调函数的执行过程中存在。

总结来说,形参是函数内部的占位符,用于接收数据,而实参是函数外部提供的具体值,用于初始化形参。

10 GC python的垃圾回收机制

有三种情况会触发垃圾回收:

  1. 当gc模块的计数器达到阀值的时候,自动回收垃圾;
  2. 调用gc.collect(),手动回收垃圾;
  3. 程序退出的时候,python解释器来回收垃圾;
# Author : ZCH
import gc
class ClassA():
    def __init__(self):
        print('object born ,id : %s' % str(id(self)))
def f2():
    while True:
        c1 = ClassA()
        c2 = ClassA()
        c1.t = c2
        c2.t = c1
        del c1
        del c2

# python默认开启垃圾回收的, 可以通过下面代码来将其关闭
gc.disable()
f2()

11 数据维度

12 struct()模块

将某些特定的结构体类型打包成二进制流的字符串然后再网络传输,而接收端也应该可以通过某种机制进行解包还原出原始的结构体数据。

struct.pack(fmt,v1,v2,…) 

返回的是一个二进制串,是参数按照fmt数据格式组合而成

struct.unpack(fmt,string)

按照给定数据格式解开(通常都是由struct.pack进行打包)数据,返回值是一个tuple

两个方法的第一个参数都是fmt,fmt就是上面的两个表格,我们根据实际内容(具体需求)写出fmt串,读取或写入文件

文中我们的fmt串是5s6si,具体含义对照下面表格:

4s表示4字节的字符串(可能我们会遇到整数计数,例如5h,意思是5个相同的h,意思和4s并不一样) 

5s含义同4s 表示5字节的字符串, i表示整数(有符号)

具体解释官方文档也有

返回类型:此方法返回一个表示指定路径名的根和扩展部分的元组。

代码:os.path.splitext()方法的使用

dict(zip(key,value))拼接key value俩列表拼接字典

1.u:表示unicode字符串

字符串中存在中文的字符,在前面加上u
  1. r:表示非转义的原始字符串
    字符串中存在\,要让它失效,要在前面加上r
  2. 3.f:表示在字符串内支持大括号内的python 表达式
    字符串中存在{},要在前面加上f

Unicode 虽然包罗万象,但它只是一个符号集

  • 如何区分 Unicode 和 ASCII?计算机如何知道三个字节表示一个字符还是表示三个字符
  • 对于英文字母,一个字节就够了,如果 Unicode 规定统一符号用 3 个字节或 4 个字节来表示,那么英文字母前面的字节必然都是 0,这对存储是极大的浪费。

所以急需一个统一的编码方式。

13 yaml

YAML有两种数据: -开头的代码list 键值对:key:value

YAML的格式:

-

  name: 获取token接口

  description: 接口描述

​​​​​​​

一、后缀名.ini  用于存储项目全局配置变量
比如:接口地址  项目地址....输出文件路径

"""
import configparser

config=configparser.ConfigParser()
config.read("config.ini",encoding="utf-8")
# 获取ini文件中所有的节点
sections=config.sections()
# 获取ini文件中某个节点下所有选项
options=config.options(section="database")    
# 获取某个节点下某个选项的选项值
value=config.get(section="database",option="username")
# 获取某个节点下的所有选项及选项值  ---》元组列表
values=config.items(section="database")
print(sections)
print(options)
print(values)
print(value)

"""
ini文件编辑:
1、写入一个节点
2、写入选项及选项值
3、删除节点
4、删除选项及选项值
"""
# 写入一个节点
new_section="userinfo1"
if new_section not in sections:
    config.add_section("userinfo1")
# 给某个节点添加选项及选项值
    config.set(section="userinfo1",option="username",value="hefan")
    config.set(section="userinfo1",option="passwd",value="hefan")
    # file=open("config.ini","w+")
    # config.write(file)
    # file.close()
    with open("config.ini","w+") as file:
        config.write(file)

# 删除节点
del_section="userinfo1"
print(sections)
if del_section in sections:
    config.remove_section(section=del_section)
    with open("config.ini","w+") as file:
        config.write(file)
# 删除选项及选项值
config.remove_option(section="userinfo",option="passwd")
with open("config.ini","w+") as file:
    config.write(file)
import yaml

with open("yaml_3.yaml","r+") as file:
    data= yaml.load(stream=file, Loader=yaml.FullLoader)
print(data)
# username=data[0]["sucesslogin"]["username"]
# print(username)

"""
序列化:python对象转换为数据文件进行存储及传输
"""
modules=["中文","pytest","unittest","requests","requests"]
with open("modules.yaml","w+") as file:
    yaml.dump(data=modules,stream=file,allow_unicode=True,encoding="utf-8")
def clear_extract_file():
    with open(get_object_path()+"/extract.yaml", encoding='utf-8', mode='w') as f:
        f.truncate()

14 excel

import os
import time

import openpyxl

"""
Excel的处理:
1、创建Excel文件

"""

def createExcel():
    """
    创建创建Excel文件,并写入数据
    :return:
    """
    # 创建工作簿
    wk=openpyxl.Workbook()
    # 获取当前工作表
    sheet=wk.active
    # 写数据到单元格
    sheet.cell(1,1).value="username"
    sheet.cell(1, 2).value = "class"
    sheet.cell(1, 3).value = "adress"
    wk.save("userinfo.xlsx")

"""
2、读取Excel文件

"""
def readExcel(filepath):
    # 获取工作簿
    wk=openpyxl.load_workbook(filepath)
    # 方式一:获取工作表
    # sheet1=wk.get_sheet_by_name("Sheet")
    # 方式二:获取工作表
    sheet1=wk["Sheet"]
    # 获取单元格坐标
    location=(sheet1.cell(5,1))
    # 获取单元格值
    value=sheet1.cell(5,1).value
    print(location,value)
    #获取工作表行数及列数
    rows=sheet1.max_row
    cols=sheet1.max_column
    print(f"行数:{rows},列数:{cols}")
    datalist=[]
    #读取工作表中所有数据?
    # 循环excel每一个行
    for row in range(1,rows+1):
        #循环列数,并取值
        for col in range(1,cols+1):
            value=sheet1.cell(row,col).value
            datalist.append(value)
    return datalist


def printDataExcel(filepath):
    data=readExcel(filepath)
    print(data)

"""
2、编辑Excel文件
    1、添加一个新的sheet
    2、修改某个单元格数据
"""
def editExcel(filepath):
    # 加载工作簿
    wk=openpyxl.load_workbook(filepath)
    #创建新的工作表
    mysheet=wk.create_sheet("mysheet")
    mysheet.cell(1,1).value="username"
    mysheet.cell(2, 1).value = "DD"
    # 编辑后记得保存
    wk.save(filepath)

def deletesheet(filepath):
    # 哪个对象的方法 openpyxl模块  三大组件
    # 删除工作表  操作对象工作簿    对象行为  删除工作表
    wk=openpyxl.load_workbook(filepath)
    # 删除工作表
    wk.remove(wk["mysheet"])
    # del wk["mysheet"]
    wk.save(filepath)

"""
一次性插入多个数据:往某个工作表一次性插入多个数据
"""
def add_manydata(filepath):
    wk=openpyxl.load_workbook(filepath)
    mysheet=wk.create_sheet()
    datalist=["cn","hefan","米格","123456"]
    mysheet.append(datalist)
    wk.save(filepath)

if __name__ == '__main__':
    filepath=os.path.join(os.path.dirname(__file__),"userinfo.xlsx")
    add_manydata(filepath=filepath)
import time
import xlrd
import xlwt
from xlutils.copy import copy

from common.yaml_util import get_object_path


class ExcelUtil:

    # 读取excel数据
    @staticmethod
    def read_excel(excel_path, sheet_name):
        xls = xlrd.open_workbook(excel_path, formatting_info=True)    # 先打开已存在的表,formatting_info=True表示保留原表格的样式
        sheet = xls.sheet_by_name(sheet_name)   # 通过sheet名称获得sheet对象
        datalist = []
        for rows in range(1, sheet.nrows):       # 循环行
            templist = []
            for cols in range(0, sheet.ncols):   # 循环列,因为最后一列备注所以减1
                templist.append(sheet.cell_value(rows, cols))
            datalist.append(templist)
        return datalist

    # 向excel中写入数据
    @staticmethod
    def write_excel(excel_path, sheet_name, rows, cols, value):
        # 获得当前系统时间
        current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        # 打开已存在的表,formatting_info=True表示保留原表格的样式
        book = xlrd.open_workbook(excel_path, formatting_info=True)
        wb = copy(book)  # 复制excel
        sheet = wb.get_sheet(sheet_name)  # 通过sheet名称获得sheet对象
        if value == 'fail':
            sheet.write(rows, cols, value, style=xlwt.easyxf('pattern: pattern solid,fore_colour red;'))     # 引用样式
        elif value == 'skip':
            sheet.write(rows, cols, value, style=xlwt.easyxf('pattern: pattern solid,fore_colour yellow;'))  # 引用样式
        else:
            sheet.write(rows, cols, value)
        # 设置时间列的宽度和值
        sheet.col(cols-1).width = 5000
        sheet.write(rows, cols-1, current_time)
        # 保存
        wb.save(excel_path)


if __name__ == '__main__':
    eu = ExcelUtil()
    print(eu.read_excel(get_object_path()+"data/smoke_case_data.xls", "购物流程数据"))
    # eu.write_excel(get_object_path()+"data/smoke_case_data.xls","查询火车票",1,6,"pass")
    # eu.write_excel(get_object_path()+"data/smoke_case_data.xls","查询火车票",2,6,"ignore")
    # eu.write_excel(get_object_path()+"data/smoke_case_data.xls","查询火车票",3,6,"fail")

15 pymysql

# @File : add_test.py
import pymysql

def main():
    conn = pymysql.connect(host='192.168.199.200', port=3306, user='root', password='ZCH@lebao', db='school', charset='utf8')
    try:
        with conn.cursor() as cursor:
            result = cursor.execute("insert into tb_student values ('1008', '乐宝', 1, '2023-6-17', '河南', '2');")
            if result == 1:
                print('添加成功')
            conn.commit()
    except pymysql.MySQLError as error:
        print(error)
        conn.rollback()
    finally:
        conn.close()
if __name__ == '__main__':
    main()
# @File : delete_test.py
import pymysql

def main():
    conn = pymysql.connect(host='192.168.199.200', port=3306, user='root', password='ZCH@lebao', db='school', charset='utf8')
    try:
        with conn.cursor() as cursor:
            result = cursor.execute("delete from tb_student where stuid=%s", '1008')
            if result == 1:
                print('删除成功')
            conn.commit()
    except pymysql.MySQLError as error:
        print(error)
        conn.rollback()
    finally:
        conn.close()
if __name__ == '__main__':
    main()
# @File : select_test.py
import pymysql
class School(object):
    def __init__(self, number, name):
        self.number = number
        self.name = name

    def __str__(self):
        return f'{self.number}\t{self.name}\t'
def main():
    conn = pymysql.connect(host='192.168.199.200', port=3306, user='root', password='ZCH@lebao', db='school', charset='utf8', cursorclass=pymysql.cursors.DictCursor)
    try:
        with conn.cursor() as cursor:
            cursor.execute("select stuid as number, stuname as name from tb_student")
            # print(cursor.fetchone())
            # print(cursor.fetchall())
            # print(cursor.fetchmany(2))
            # conn.commit()
            for row in cursor.fetchall():
                # print(row['stuid'], end='\t')
                # print(row['stuname'], end='\t')
                # print()
                school = School(**row)
                print(school)
    except pymysql.MySQLError as error:
        print(error)
        conn.rollback()
    finally:
        conn.close()
if __name__ == '__main__':
    main()
# @File : update_test.py
import pymysql

def main():
    name = input('学生姓名')
    number = input('学生编号')
    conn = pymysql.connect(host='192.168.199.200', port=3306, user='root', password='ZCH@lebao', db='school', charset='utf8')
    try:
        with conn.cursor() as cursor:
            result = cursor.execute("update tb_student set stuname = %s where stuid=%s", (name, number))
            if result == 1:
                print('更新成功')
            conn.commit()
    except pymysql.MySQLError as error:
        print(error)
        conn.rollback()
    finally:
        conn.close()
if __name__ == '__main__':
    main()

16 CSV

def get_object_path():
    # 绝对路径
    return os.path.abspath(os.getcwd().split('common')[0])

# 读取CSV数据文件
def read_csv_file(csv_path):
    csv_data_list = []
    with open(str(get_object_path()) + "/" + csv_path, 'r', encoding='utf-8') as f:
        csv_reader_data = csv.reader(f)
        for row in csv_reader_data:
            csv_data_list.append(row)
    return csv_data_list

三、函数

1 匿名函数

lambda 是指没有名字的函数,这种函数只能使用一次,一般是在函数的函数体只有一句代码且只有一个返回值时,可以用匿名函数来简化。

语法结构:

Result=lambda 参数列表中;表达式

s = lambda a,b:a+b
print(type(s))
print(s(10, 20)

for i in range(len(lst)):
    result = lambda x:x[I] # 根据索引取值,result 类型是function,x是形式参数
    print(result(lst)) # lst 是实际参数
student_scores = [
    {'name':'陈梅梅‘, 'score':98},
    {'name':'王一一‘, 'score':95},
    {'name':'张天乐‘, ’score’:100},
    {'name':'白雪儿‘, 'score': 65}
]

# 对列表进行排序,排序的规则是字典的成绩

student_scores.sort(key=lambda x:x.get('score'),reverse=True) # 降序

2 递归函数

在一个函数的函数体内调用该函数本身,该函数就是递归。

一个完整的递归操作有两部分组成:

  1. 递归调用
  2. 递归终止条件:一般可使用if-else结构来判断递归的调用和递归的终止
"""
演示Python递归操作
需求:通过递归,找出一个指定文件夹内的全部文件

思路:写一个函数,列出文件夹内的全部内容,如果是文件就收集到list
如果是文件夹,就递归调用自己,再次判断。

"""
import os

def test_os():
    """演示os模块的3个基础方法"""
    print(os.listdir("D:/test"))        # 列出路径下的内容
    # print(os.path.isdir("D:/test/a"))   # 判断指定路径是不是文件夹
    # print(os.path.exists("D:/test"))    # 判断指定路径是否存在


def get_files_recursion_from_dir(path):
    """
    从指定的文件夹中使用递归的方式,获取全部的文件列表
    :param path: 被判断的文件夹
    :return: list,包含全部的文件,如果目录不存在或者无文件就返回一个空list
    """
    print(f"当前判断的文件夹是:{path}")
    file_list = []
    if os.path.exists(path):
        for f in os.listdir(path):
            new_path = path + "/" + f
            if os.path.isdir(new_path):
                # 进入到这里,表明这个目录是文件夹不是文件
                file_list += get_files_recursion_from_dir(new_path)
            else:
               file_list.append(new_path)
    else:
        print(f"指定的目录{path},不存在")
        return []

    return file_list

if __name__ == '__main__':
    print(get_files_recursion_from_dir("D:/test"))

3 内置函数

1、类型转换函数

bool(obj) 获取指定对象obj的布尔值

str(obj) 将指定对象obj转成字符串类型

int(x) 将x转成int类型

float(x) 将x转成float类型

list(sequence) 将序列转成列表类型

tuple(sequence) 将序列转成元组类型

set(sequence) 将序列转成集合类型

2、数学函数

abs(x) 获取x的绝对值

divmod(x,y) 获取x与y的商和余数

max(sequence) 获取sequence的最大值

min(sequence) 获取sequence的最小值

sum(iter) 对可迭代对象进行求和运算

pow(x,y) 获取x的y次幂

round(x,d) 对x进行保留d位小数,结果四舍五入

3、迭代器操作函数

sorted(iter) 对可迭代对象进行排序

reversed(sequence) 反转序列生成新的迭代器对象

zip(iter1, iter2) 将iter1 与 iter2 打包成元组并返回一个可迭代的zip对象

enumerate(iter) 根据iter对象创建一个enumerate 对象

all(iter) 判断可迭代对象iter中所有元素的布尔值是否都为True

any(iter) 判断可迭代对象iter中所有元素的布尔值是否都为False

next(iter) 获取迭代器的下一个元素

fifter(function, iter) 通过指定条件过滤序列并返回一个迭代器对象

map(function, iter) 通过函数function对可迭代对象iter的操作返回一个迭代器对象

def upper(x):
    return x.upper()


new_lst2 = ['hello', 'world', 'python']
obj2 = map(upper, new_lst2)
print(list(obj2))


def fun(num):
    return num%2==1

obj=filter(fun, range(10))
print(list(obj))

​​​​​​​

4 其他函数

format(value, format_spec) 将value以format_spec格式进行显示

len(s) 获取s的长度或s元素的个数

id(obj) 获取对象的内存地址

type(x) 获取x的数据类型

eval(s) 执s这个字符串所表示的python代码

5 函数参数

"""
演示多种传参的形式
"""
def user_info(name, age, gender):
    print(f"姓名是:{name}, 年龄是:{age}, 性别是:{gender}")
# 位置参数 - 默认使用形式
user_info('小明', 20, '男')

# 关键字参数
user_info(name='小王', age=11, gender='女')
user_info(age=10, gender='女', name='潇潇')    # 可以不按照参数的定义顺序传参
user_info('甜甜', gender='女', age=9)

# 缺省参数(默认值)
def user_info(name, age, gender):
    print(f"姓名是:{name}, 年龄是:{age}, 性别是:{gender}")

user_info('小天', 13, '男')


# 不定长 - 位置不定长, *号
# 不定长定义的形式参数会作为元组存在,接收不定长数量的参数传入
def user_info(*args):
    print(f"args参数的类型是:{type(args)},内容是:{args}")

user_info(1, 2, 3, '小明', '男孩')

# 不定长 - 关键字不定长, **号
def user_info(**kwargs):
    print(f"args参数的类型是:{type(kwargs)},内容是:{kwargs}")
user_info(name='小王', age=11, gender='男孩')

"""
演示函数作为参数传递
"""

# 定义一个函数,接收另一个函数作为传入参数
def test_func(compute):
    result = compute(1, 2)  # 确定compute是函数
    print(f"compute参数的类型是:{type(compute)}")
    print(f"计算结果:{result}")

# 定义一个函数,准备作为参数传入另一个函数
def compute(x, y):
    return x + y
# 调用,并传入函数
test_func(compute)

6 装饰器函数

闭包:外部函数中定义了内部函数,外部函数的返回值是内部函数名,内部函数引用了外部函数的变量;

# 使用闭包实现ATM小案例
def account_create(initial_amount=0):

    def atm(num, deposit=True):
        nonlocal initial_amount
        if deposit:
            initial_amount += num
            print(f"存款:+{num}, 账户余额:{initial_amount}")
        else:
            initial_amount -= num
            print(f"取款:-{num}, 账户余额:{initial_amount}")

    return atm

atm = account_create()

atm(100)
atm(200)
atm(100, deposit=False)

装饰器函数

1、函数A是作为参数出现的(函数B就接收函数A作为参数)

2、要有闭包的特点
"""
函数可以有多个装饰器函数
注意:
多个装饰器函数执行顺序是:
    从里到外(就近原则)

"""

# 需求:统计每个函数的耗时多久
import time

"""
"""
# 装饰器函数
# 其他函数只要被装饰器函数装饰即可
def runTime(func):
    """
    装饰函数
    原来功能+扩展的功能:统计每个函数的耗时多久
    :return:
    """
    def wrapper(*args,**kwargs):
        start = time.time()
        # 原来功能
        func(*args,**kwargs)     # 原来功能
        end = time.time()
        cost = end - start
        print(f"统计函数[{func.__name__}]总共耗时{cost}秒")
    return  wrapper

@runTime
def welcome_vip():
    """被装饰器函数"""
    print("欢迎来到码尚学院VIP课堂")
    time.sleep(1)

@runTime
def sum(*args):
    sum=0
    for num in args:
        sum+=num
    print(f"求和:{sum}")
    return sum

welcome_vip()    #实质:执行装饰函数的内置方法
sum(1,2,3,4,5,6,7,8,9,10)

四、面向对象

1、面向对象特征之一封装:提高代码复用性

封装:面向对象编程的第一步,将属性和方法封装到一个抽象的类中, 外界使用类创建对象,然后让对象调用方法,对象方法的细节都被封装在类的内部。

2、面向对象特征之二:继承 

在python中一个子类可以继承N多个父类,一个父类也可以拥有N多个子类。

如果一个类没有继承任何类,那么这个类默认继承的是object类

继承:实现代码的重用,相同的代码不需要重复的写,子类继承父类及父类的父类的属性和方法 

基类:父类 

派生类:子类 

继承:分为单继承和多继承

注意:

1、子类调用方法,先找自己,然后再去找父类,再找父类的父类,依次类推

2、子类不能继承父类及父类的父类的私有属性及方法

3、能写父类方法

  1、覆盖父类方法 子类中重写父类的方法

  2、扩展父类方法

4、父类名.方法名(self) 调用父类的方法

3、面向对象第三大特征:多态

多态:不同的子类对象调用相同的方法,产生不同的执行结果(呈现出多态的形态)。只要不同的类中有同名的方法,即可实现多态。

4、object类

所有类直接或者间接的父类

所有类都拥有object类的属性和方法

__new__() 由系统调用,用于创建对象

__init__() 创建对象时手动调用,用于初始化对象属性值

__str__() 对象的描述,返回值时str类型,默认输出对象的内存地址

创建对象时候,系统自动调用,先执行父类当中的__new__()方法去创建对象,开辟内存空

间,创建完成之后,再由__init__()方法去给实例属性赋值。

5 类相关

property

​​​​​​​

7 反射 

把字符串映射到实例的变量或者实例的方法, 然后可以去进行调用、修改操作

反射四个重要的方法:
1、getattr 获取对象属性/方法

2、hasattr 判断对象是否有对应的属性

3、delattr 删除指定属性
4、setattr 为对象设置内容

五、网络编程

1 并发并行

并发:是指两个或多个事件同一时间间隔发生,多个任务被交替轮换着执行

并行:是指两个或多个事件同一时刻发生,多个任务在同一时刻在多个处理器上同时执行

1、 进程则是指启动后的程序,系统会为进程分配内存空间,进程与进程之间不共享内存;

2、 同一进程下的不同的多个线程,共享父进程的地址空间;

3、 一个进程中可以拥有N多个线程并发执行,而每个线程并行执行不同的任务; 

4、 线程之间数据共享,进程之间数据不共享,可以通过队列进行通信。

5、 线程是CPU可调度的最小单位,被包含在进程中,是进程中实际运作单位。

​​​​​​​

  1. CPU逻辑地址 内存物理地址,地址空间分为物理地址空间和逻辑地址空间。
  1. 地址空间分为物理地址空间和逻辑地址空间。
  2. 物理地址空间和硬件直接对应,如内存条代表的主存,硬盘代表的磁盘 ,都是物理内存,其管理由硬件完成
  3. 逻辑地址空间是运行的程序看到的地址空间,是一维的线性的地址空间。

逻辑地址空间依赖物理地址空间而存在。

内存条和磁盘的区别

内存条和磁盘(硬盘)是电脑中两种不同的存储设备,它们的主要区别在于:

作用不同。内存条是CPU与硬盘之间的桥梁,用于临时存储CPU运算的中间数据和计算结果,以便CPU能够快速访问这些数据。硬盘则是用于长期存储数据的设备,它能够保存数据,即使电源关闭。123456

空间大小不同。内存条的容量通常较小,常见的有4GB至64GB,而硬盘的容量则更大,常见的有500GB至数TB,甚至更大。1245

速度不同。内存条的读写速度非常快,而硬盘的读写速度相对较慢。1356

存储类型不同。内存条属于易失性存储器,一旦断电,存储在其中的数据会丢失。硬盘则属于非易失性存储器,即使断电,数据也不会丢失。467

技术不同。内存条是半导体存储器,而硬盘是机械式存储设备。3

综上所述,内存条和硬盘在电脑系统中扮演着不同的角色,内存条用于临时数据存储,而硬盘用于长期数据存储。

TCP三次握手

客户端请求建立连接,服务端同意建立连接,客户端进行数据请求,服务端进行数据响应。客户端请求关闭连接,服务端关闭连接。​​​​​​​

TCP协议即传输控制协议,是建立在IP协议基础之上的。TCP协议负责两台计算机之间建立可靠连接,保证数据包按顺序发送到。它是一种可靠的,一对一的,面向有连接的通信协议。

UDP协议又被称为用户数据包协议,它是面向无连接的协议,只要知道对方的IP地址和端口,就可以直接发送数据包,由于是面向无连接的,所以无法保证数据一定会到达接收方。

2 协程

import time

import gevent
from gevent import monkey

monkey.patch_all()


def f1(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        time.sleep(1)


def f2(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        time.sleep(1)

def f3(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        time.sleep(1)


gevent.joinall([
    gevent.spawn(f1, 5),
    gevent.spawn(f2, 5),
    gevent.spawn(f3, 5)
])

3 线程锁

import threading
import time


mutex = threading.Lock()

g_num = 0


def task1(num):
    global g_num

    for i in range(num):

        mutex.acquire()

        g_num += 1
        print(f'task1: {threading.current_thread().name} sell {g_num}')

        mutex.release() # 释放锁
    print(f'task1-all: {threading.current_thread().name} sell {g_num}')


def task2(num):
    global g_num

    for i in range(num):
        mutex.acquire()

        g_num += 1
        print(f'task2: {threading.current_thread().name} sell {g_num}')

        mutex.release()  # 释放锁

    print(f'task2-all: {threading.current_thread().name} sell {g_num}')


if __name__ == '__main__':

    t1 = threading.Thread(target=task1, args=(20000,))
    # t2 = threading.Thread(target=task2, args=(20000,))
    t1.daemon = True
    t1.start()

    # t1.join()
    print('1*******')
    # t2.start()
    print('2*******')

4 进程

# 函数式进程
import os,time
from multiprocessing import Process

def test(name):
    print(f'sub {os.getpid()}, f-pro {os.getppid()},name{name}')
    time.sleep(1)

def test2(name):
    print(f'sub2 {os.getpid()}, f-pro2 {os.getppid()},name2{name}')
    time.sleep(1)


if __name__ == '__main__':
    print('主进程开始')
    lst = []
    for i in range(5):
        p1 = Process(target=test, args=('lebao', ))
        p2 = Process(target=test2, args=('lebao',))
        p1.start()
        p2.start()
        print('alive:', p1.name, p1.is_alive())
        print('alive:', p2.name, p2.is_alive())
        lst.append(p1)
    for item in lst:
        item.join() # 阻塞主进程
    print('主进程结束')
    print('alive:', p1.name, p1.is_alive())
    print('alive:', p2.name, p2.is_alive())
# 继承式进程
import os
import time
from multiprocessing import Process

class SubProcess(Process):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print(f'sub {os.getpid()}, f-pro {os.getppid()},name {self.name}')


if __name__ == '__main__':
    start = time.time()
    print('F-start')
    lst = []
    for i in range(1, 6):

        p1 = SubProcess(f'sub {i}')
        p1.start()
        lst.append(p1)

    for item in lst:
        item.join()

    print('F-stop')
    end = time.time() - start
    print('end', end)
# 进程池
from multiprocessing import Pool
import time

import os

def task(name):
    print(f'sub {os.getpid()}, f-pro {os.getppid()},name {name}')
    time.sleep(1)

if __name__ == '__main__':
    start = time.time()
    print('F-start')
    p = Pool(3)

    for i in range(10):
        # p.apply_async(func=task, args=(str(i), ))
        p.apply(func=task, args=(str(i),))

    p.close()
    p.join()
    print('F-stop')
    end = time.time() - start
    print('end', end)

5 队列

from queue import Queue
import time
from threading import Thread


class Producer(Thread):
    def __init__(self, name, queue):
        Thread.__init__(self, name=name)
        self.queue = queue
    def run(self):
        for i in range(10):
            print(f'{self.name} 将产品{i} 放入队列')
            self.queue.put(i)
            time.sleep(1)
        print('生产者完成了所有数据的存放')


class Consumer(Thread):
    def __init__(self, name, queue):
        Thread.__init__(self, name=name)
        self.queue = queue
    def run(self):
        for i in range(10):
            value = self.queue.get()
            print(f'{self.name} 取出产品{value}')

            time.sleep(1)
        print('消费者完成了所有数据的取出')


if __name__ == '__main__':
    queue = Queue()
    p = Producer('Producer', queue)
    c = Consumer('Consumer', queue)

    p.start()
    c.start()

    p.join()
    c.join()
    print('f-stop')

6  线程

import threading
from threading import Thread

import time


def test():
    for i in range(3):
        time.sleep(1)
        print(f'thread {i} : {threading.current_thread().name}')


if __name__ == '__main__':
    start = time.time()
    print('f-start')

    lst = [Thread(target=test) for i in range(2)]

    for item in lst:
        item.start()

    for item in lst:
        item.join()

    print('time:', time.time() - start)
import threading
from threading import Thread

import time

class SubThread(Thread):
    def run(self):
        time.sleep(1)
        for i in range(3):
            print(f'thread {i} : {threading.current_thread().name}')

if __name__ == '__main__':
    start = time.time()
    print('f-start')

    lst = [SubThread() for i in range(2)]

    for item in lst:
        item.start()

7 TCP通信

from socket import socket, AF_INET, SOCK_STREAM
import threading
# AF_INET 用于internet之间的进程通信
# SOCK_STREAM # 表示的是TCP协议编程


class HandleData(threading.Thread):

    def __init__(self, client_socket):
        super().__init__()
        self.client_socket = client_socket

    def run(self):
        # (5) 接收来自客户端的数据
        data = self.client_socket.recv(1024)
        print('Received:', data.decode('utf-8'))  # 要求客户端发送过来的数据是使用utf-8进行编码的

        client_data_thread = TCPClient(data)
        client_data_thread.start()

    def __del__(self):
        self.client_socket.close()



class TCPServer(threading.Thread):
    def __init__(self, port):
        super().__init__()
        # (1) 创建socket对象
        self.server_socket = socket(AF_INET, SOCK_STREAM)
        # (2) 绑定IP地址和端口
        ip = '192.168.199.242'

        self.server_socket.bind((ip, port))
        # (3) 使用listen()开始监听
        self.server_socket.listen()

    def run(self):

        print('Waiting for connection...')
        while True:
            # (4) 等待客户端的连接
            client_socket, addr = self.server_socket.accept()  # 系统解包赋值
            print(client_socket, 'client_socket')
            print(addr, 'addr')
            handle_data_thread = HandleData(client_socket)
            handle_data_thread.start()

    def __del__(self):
        self.server_socket.close()


class TCPClient(threading.Thread):
    def __init__(self, data):
        super().__init__()
        import socket
        # (1) 创建socket对象
        self.client_socket = socket.socket()
        # (2) 绑定IP地址和端口
        ip = '192.168.199.199'
        port = 7890
        self.client_socket.connect((ip, port))
        self.data = data

    def run(self):

        self.client_socket.send(self.data)

    def __del__(self):
        self.client_socket.close()


tcp_server = TCPServer(7788)
tcp_server.start()

六、接口自动化

1 分层设计

cases:测试执行逻辑层,用于存放所有的测试用例类

configs:配置层,用于存放当前框架中的所有配置信息

data:测试数据层,用于存放所有的测试数据,测试参数

csv libs:自定义文件层,用于存放自定义或二次开发的库文件 logs:日志层,用于保存运行框架过程中产生的所有有效的日志信息 

reports:报告层,用于保存所有的测试报告文件

scripts:脚本封装层,用于保存所有的操作封装模块

all.py:用例启动文件,使用套件加载用例,批量执行并生成报告。

common:封装函数,提高代码复用性

2 常见的接口协议

TCP 网络控制协议 IP 互联网协议 UDP 用户数据协议 HTTP 超文本传输协议 HTTPS 安全超文本传输协议 FTP 文件传输协议

  1. session,cookie,token的相同点和不同点? 相同点:都是在服务器产生,都是用于鉴权,只是保存在不同的地方; 不同点:cookie保存在客户端,所以不安全,一般情况下用cookie保存一些非重要的数据,通过session去保存一些重要的数据,session保存在服务器的内存中,token是独立的鉴权,和session和cookie无关。
  2. 响应码? 1XX信息 2XX请求成功 3XX重定向 4XX客户端错误 5XX服务器错误 302:临时重定向到某个页面 403:权限不够,鉴权未通过 404:请求失败,请求所希望的资源未在服务器上发现 401:请求身份认证 429:请求频率受限
  3. get和post的区别? get获取数据,post提交数据; 安全性:post比get安全,get参数暴露在URL上,不能用来传敏感信息; 传输方式不一样:get在URL?后传参,多参数之间用&,post通过body表单传参; 参数长度有限制:get在URL中传参参数长度是有限制的,post参数长度不会限制; 参数的数据类型:get只接受ascii字符,post没限制; 编码:get请求只能进行URL编码,post支持多种编码格式; get产生一个TCP包,post产生两个TCP包,get请求浏览器会把data和header一并发出去,服务器响应200,返回数据。post请求浏览器先发送header,服务器响应100 continue 再发送data,服务器响应200返回数据。
  4. Python参数传递采用的肯定是“传对象引用”的方式。这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值--相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象--相当于通过“传值’来传递对象。
  5. 1、OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向Web服务器发送的请求来测试服务器的功能; 2、HEAD:向服务器索与get请求相一致的响应,只不过响应体将不会被返回。这一方法可以再不必传输整个响应内容的情况下,就可以获取包含在响应小消息头中的元信息。 3、get:向特定的资源发出请求 4、post 想指定资源提交数据进行处理请求,数据被包含在请求体中,post请求可能会导致新的资源的建立和/或已有资源的修改。 5、put 向指定资源位置上传其最新内容 6、delete 请求服务器删除request-url所标识的资源 7、trace 回显服务器收到的请求,主要用于测试或诊断 8、connect http/1.1 协议中预留给能够将连接改为管道方式的代理服务器。

3 requests

import json
import traceback
import jsonpath as jsonpath
import requests

from common.logger_util import error_log, debug_log, info_log
from debug_talk import DebugTalk


class RequestsUtil:
    session = requests.session()

    def __init__(self):

        self.name = None
        self.base_url = ""
        self.last_method = None
        self.last_headers = {}
        self.kwargs = None

    # 统一发送请求的方法
    def send_request(self, name, base_url, method, url, headers=None, **kwargs):
        # noinspection PyBroadException
        try:
            # 1、处理method
            self.last_method = str(method).lower()
            # 2、处理基础路线url
            self.base_url = self.replace_load(base_url) + self.replace_load(url)
            # 3、处理请求头headers
            if headers and isinstance(headers, dict):
                self.last_headers = self.replace_load(headers)
            # 4、请求数据替换,可能是params、data、json
            for key, value in kwargs.items():
                if key in ['params', 'data', 'json']:
                    value = self.replace_load(value)
                    kwargs[key] = value
            # 5、请求接口名称name
            self.name = name
            # 收集日志
            debug_log("\n----------接口请求开始-----------")
            debug_log("接口名称:%s" % self.name)
            debug_log("请求方式:%s" % self.last_method)
            debug_log("请求路径:%s" % self.base_url)
            debug_log("请求头:%s" % self.last_headers)
            # 6、请求参数
            self.kwargs = kwargs
            if 'json' in self.kwargs.keys():
                debug_log("请求参数:%s" % self.kwargs['json'])
            elif 'data' in self.kwargs.keys():
                debug_log("请求参数:%s" % self.kwargs['data'])
            elif 'params' in self.kwargs.keys():
                debug_log("请求参数:%s" % self.kwargs['params'])
            elif 'files' in self.kwargs.keys():
                debug_log("文件上传:%s" % self.kwargs['files'])

            # 发送请求
            res = RequestsUtil.session.request(method=self.last_method, url=self.base_url, headers=self.last_headers, **kwargs)
            return res
        except Exception as _:
            error_log("发送请求异常:异常信息:%s" % traceback.format_exc())

Requests库常用的方法 

1.requests.get(url, params=None, **kwargs)
2.requests.post(url, data=None, json=None, **kwargs) 和json传参

请求头:

1.请求正文格式:multipart/form­data 

文件上传 Content­Type:multipart/form­data 一般用于传价值对和文件

2.请求正文格式:application/x­www­form­urlencoded 

键值对 Content­Type:application/x­www­form­urlencoded 以表单的方式传参,数据格式:

key1=value1&key2=value2

3.请求正文格式“:raw

Content-Type:application/json

Content-Type:text/plain

Content-Type:application/javascript

Content-Type:text/html

Content-Type:application/xml

4.请求正文格式:binary

Content-Type:application/octet­stream 二进制流的数据 

5.requests.put() 发送put请求

6.requests.delete() 发送delete请求

7.requests.request()

method,
url, params=None, data=None,

headers=None,

cookies=None, files=None,

request()执行之后返回response对象 

print(res.text) 响应的字符串格式的数据

print(res.content) 响应的bytes类型格式的数据

print(res.json()) 响应的字典数据格式

print(res.status_code)响应的状态码

print(res.reason)响应的状态信息
print(res.cookies)响应的cookie信息
print(res.headers)响应头

print(res.request.headers) 请求头

实战(发送get,post<data传参,json传参,传文件>)

 json.dumps(data) 序列化,把字典转换成str字符串

json.loads(data) 反序列化,把字符串转换成字典

post:

data (键值对的字典)

默认:Content­Type:application/x­www­form­urlencoded 数据格式: key1=value1&key2=value2

当使用json.dumps(data)转换之后,那么默认:'Content­Type': 'application/json' json(有嵌套的字典):

默认:'Content­Type': 'application/json'

files:(文件上传)
默认:Content­Type': 'multipart/form­data;

boundary=50dcca52ed21a4b55651353785ca905a'​​​​​​​

4 Allure

1.史诗(项目名称): @allure.epic("项目名称:接口自动化测试项目")

2.特性(模块名称):@allure.feature("模块名称:用户管理模块")

3.分组(接口名称):@allure.story("接口名称:查询商品")
4.测试用例标题:

(1)@allure.title("测试用例标题:输入正确的条件查询成功1"),适用于一个方法对 应一个用例。

@allure.description("测试用例描述1")

@allure.link(name="接口地址",url="https://api.weixin.qq.com/cgi‐ bin/token")

@allure.issue("Bug连接")

(2)allure.dynamic.title("测试用例标题:输入正确的条件查询成功2"),适用于一个 方法对应多个用例。也就是有数据驱动的情况。

@allure.testcase("测试用例地址")

@allure.severity(allure.severity_level.BLOCKER) 注意:这个装饰器可以修饰方法也可以修饰类。

allure中的数据驱动装饰器 

@pytest.mark.parametrize(参数名,数据(list,tuple,字典列表,字典元祖))

pytest结合allure-pytest实现生成allure报告

1.官网下载allure文件:https://github.com/allure-framework/allure2/releases 

2.下载之后解压到非中文的目录

3.把bin路径配置到系统变量path中:E:\allure-2.13.7\bin (注意分号不要是中文的)

第二步:安装allure报告:pip install allure-pytest

验证:allure --version 注意:可能需要重启pycharm。

pytest.ini文件如下:

  1. addopts = ‐vs ‐‐alluredir=reports/temps ‐‐clean‐alluredir

  2. 加上--clean-alluredir表示:每执行一次把原来的清除。

  3. os.system("allure generate reports/temps ‐o reports/allures ‐‐clean")

  4. 加上--clean表示:每执行一次把原来的清除。

5 pytest

1 运行方式

1.主函数方式。

常见参数:

-v:输出更加详细的信息。比如文件和用例名称等。

-s:输出调试信息。打印信息等。
可以合并成:-vs
--reruns 数字:失败重跑

-x:出现1个失败就停止测试。
--maxfail=2 出现N个失败就终止测试。

--html=report.html 生成html的测试报告

-n:多线程。

-k:运行测试用例名称中包含指定字符串的用例。 pytest.main(['-vs','-k','weiwei or baili']) pytest.main(['-vs','-k','weiwei and baili'])

2.指定模块运行。

if __name__ == '__main__':
 pytest.main(['‐vs','testcases/test_api2.py'])

3.指定文件夹

if __name__ == '__main__':
pytest.main(['‐vs','testcases/'])

4.通过node id的方式运行测试用例。

if __name__ == '__main__':

pytest.main(['‐vs','testcases/test_api.py::TestApi::test_product_manage_ weiwei'])

5.命令行方式。

pytest

6.通过pytest.ini的配置文件运行。(不管是命令行还是主函数都会读取这个配置文件)

[pytest] 用于标记这个文件是pytest的配置文件

addopts = -vs
testpaths = testcases/
python_files = test_*.py
python_classes = Test*
python_functions = test_* 改变默认的测试用例的搜索规则。 #用例分组
markers =

smoke:冒烟用例

productmanage:商品管理模块

addoptions

命令行参数,多个参数之间用空格分隔。
配置搜索测试用例的范围
改变默认的文件搜索规则
改变默认的类搜索规则
特别提示:
此文件中最好不要出现中文, 如果有中文的情况下,比如使用notpad++改成GBK的编码。

2 标记

  1. @pytest.mark.smoke

  2. 执行的时候通过-m参数指定标记

  3. addopts = ‐vs ‐m smoke

3 pytest执行测试用例的顺序

从上到下。

改变默认用例的执行顺序:在用例上加标记: @pytest.mark.run(order=1)

跳过测试用例@pytest.mark.skip(reason="粒度不需要")

有条件跳过@pytest.mark.skipif(age>2,reason="以后的版本都不执行")

4 前后置

使用fixture实现部分前后置 

setup/teardown

setup_class/teardown_class

语法: @pytest.fixture(scope="作用域",params="数据驱动",autouser="自动执行",ids="自定 义参数名称",name="别名")

scope="作用域"

functioin:在每个方法(测试用例)的前后执行一次。

class:在每个类的前后执行一次。

module:在每个py文件前后执行一次。

package/session:每个package前后执行一次。

注意:如果加入autouse=True参数,那么表示自动使用,那么和setup、 teardown功能一致。


@pytest.fixture(scope="function")
def execute_sql():
print("执行数据库的验证,查询数据库。") 
yield
print("关闭数据库的连接")

def test_baili(self,execute_sql): 
    print("百里老师"+execute_sql)
@pytest.fixture(scope="class")
def execute_sql():
print("执行数据库的验证,查询数据库。") 
yield
print("关闭数据库的连接")

@pytest.mark.usefixtures("execute_sql")
class TestApi2:
def test_duo_class(self): print("多个类的情况")
# module级别:在每个模块的前后执行一次。和setup_module和teardown_module效果 一样。
@pytest.fixture(scope="module",autouse=True)
def execute_sql():
print("执行数据库的验证,查询数据库。") 
yield "1"
print("关闭数据库的连接")

​​​​​​​

4.package、sesion级别,一般是和connftest.py文件一起使用。

当fixture的级别为package,session时,那么一般和conftest.py文件一起使用。 

1.名称是固定的conftest.py,主要用于单独的存放fixture固件的。

2.级别为package,sesion时,那么可以在多个包甚至多个py文件里面共享前后置。

3.发现conftest.py文件里面的fixture不需要导包可以直接使用。

4.conftest.py文件,可以有多个。

注意:多个前置同时存在的优先级。

1.conftest.py为函数级别时优先级高于setup/teardown

2.conftest.py为class级别时优先级高于setup_class/teardown_class

3.conftest.py为session级别时优先级高于setup_module/teardown_module

七 pycharm工具基本使用

八 python环境搭建

1 windows+python安装

python环境搭建

       Python中文网 官网

1、安装和配置环境变量

        安装到C:\python37目录

2、配置环境变量:

        在Path的最前面输入:C:\Python37;C:\Python37\Scripts;

         目录:C:\Python37;是为了找python.exe这个文件。

         目录:C:\Python37\Scripts;是为了找pip.exe这个文件。

3、验证:在dos中输入python验证是否安装和配置成功。

4、pycharm工具的安装

       官方下载地址

http://www.jetbrains.com/pycharm/download/#section=windows 

       安装:就按默认方式,一直点下一步,到安装成功

2 下载Anaconda环境包

安装版本:https://www.anaconda.com/distribution/#download-section

Python3.8.8版本:Anaconda3-2021.05-Linux-x86_64.sh

conda命令及pip命令

conda管理数据科学环境,conda和pip类似均为安装、卸载或管理Python第三方包。

conda install  包名    pip install 包名

conda uninstall 包名   pip uninstall 包名

conda install -U 包名   pip install -U 包名

Anaconda设置为国内下载镜像

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/

conda config --set show_channel_urls yes

conda创建虚拟环境

conda env list

conda create py_env python=3.8.8 #创建python3.8.8环境

activate py_env   #激活环境

deactivate py_env #退出环境

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值