Python学习笔记(未完成)

前言

  1. python版本为3.10.11

  2. 代码块中注释均为中文编码

  3. 代码块中 #-- 为控制台输出内容

环境

Python下载

官网地址:Welcome to Python.org

Pycharm下载

官网地址:JetBrains: Essential tools for software developers and teams

一.字面量

1.1 常用的六种字面量

  1. 数字(Number)

    1. 整数(int)

    2. 浮点数(float)

    3. 复数(complex)

  2. 字符串(String)

  3. 列表(List)

  4. 元组(Tuple)

  5. 集合(Set)

  6. 字典(Dictionary)

  7. 布尔(Bool)

1.2 数据类型

常用的三个:

  1. 字符串(string)

  2. 整型(int)

  3. 浮点型(float)

查看数据类型:type()

print(type(666))
print(type("666"))
print(type(666.0))
​
#-- <class 'int'>
#-- <class 'str'>
#-- <class 'float'>
​
​
int_type = type("789")
print(int_type)
​
#-- <class 'str'>
​
name = "123"
name_type = type(name)
print(name_type)
​
#-- <class 'str'>

1.3 类型转换

  1. int(x)

  2. float(x)

  3. str(x)

# 整型转字符串
num_str = type(str(666))
print(num_str)
​
#-- <class 'str'>
​
# 整型转浮点数
num_float = type(float(666))
print(num_float)
​
#-- <class 'float'>
​
# 字符串转整型
str_int = type(int("666"))
print(str_int)
​
#-- <class 'int'>
​
# 字符串转浮点数
str_float = type(float("666.5"))
print(str_float)
​
#-- <class 'float'>
​
# 浮点数转整型
float_int = type(int(666.55))
print(float_int)
​
#-- <class 'int'>
​
# 浮点数转字符串
float_str = type(str(666.55))
print(float_str)
​
#-- <class 'str'>

1.4 字符串扩展

  1. 单引号 name = 'zzb'

  2. 双引号 name = "zzb"

  3. 三引号 三引号支持换行

  4. 字符串拼接 :

    1. print("zzb" + "大帅锅")
    2. %s(%表示我要占位 s表示将变量转成字符串放入占位的地方)

      1. %s 转成字符串放入占位位置

      2. %d 转成整数放入占位位置

      3. %f 转成浮点数放入占位位置

name = """1q23123
12321321321321321"""
print(name)
​
#-- 1q23123
#-- 12321321321321321
​
name = "'黑马'"
print(name)
​
#-- '黑马'
​
name = "\"123\""
print(name)
​
#-- "123"
​
# 字符串拼接
print("zzb" + "大帅锅")
​
#-- zzb大帅锅
​
name = "zzb"
status = "%s学习" % name
print(status)
​
#-- zzb学习
​
phone = "1388888"
print("%s的电话是%s" % (name, phone))
​
#-- zzb的电话是1388888

1.5 格式化字符串的精度控制

m.n:

m:控制宽度,要求是数字(宽度小于数字自身时宽度不生效)

n:控制精度,要求是数字,会进行小数的四射五入

示例:

%5d 表示将整数的宽度控制在5位

%5.2f 表示将宽度控制在5位,精度设置为2

%.2f 表示不限制宽度,只限制精度为2

price = 19.9
print("今天的价格是:%f" % price)
​
#-- 今天的价格是:19.900000
​
num = 5
print("限制宽度:%5d" % num)  # 限制宽度导致5前面有4个空格
​
#-- 限制宽度:    5
​
print("限制宽度为5,精度为3:%7.3f" % price)  # 限制宽度为7 所以19.900 前有一个空格(.占据一个宽度) 限制精度为3 所以.后有三位
​
#-- 限制宽度为5,精度为3: 19.900
​
print("只限制精度为2:%.2f" % price)  # 限制精度为2 所以.后有两位
​
#-- 只限制精度为2:19.90

字符串格式化快速写法:

f"{变量} {变量}"

name = "123"
​
year = 2000
​
price = 19.9
​
print(f"{name},生产于{year},价格是{price}")
​
#-- 123,生产于2000,价格是19.9

二.变量

格式: 变量名 = 变量值

注:变量没有类型

money = 50
print("钱包还剩:", money)
​
#-- 钱包还剩: 50
​
​
money = money - 10
print("钱包还剩:", money)
​
#-- 钱包还剩: 40

内置函数id()可以获取变量的内存地址

允许多个变量指向同一个值

no1 = 2048
print(id(no1))
​
no2 = 2048
print(id(no2))
​
#-- 1685782066160
#-- 1685782066160

三.标识符与关键字

1.标识符:

只允许出现:英文、中文(不推荐使用)、数字、下划线(_),数字不可以开头,区分大小写,不可使用关键字

2.关键字:

区分大小写

3.1 关键字表(不需要记)

andasassertbreakclasscontinue
defdelelifelseexceptfinally
forfromFalseglobalifimport
inislambdanonlocalnotNone
orpassraisereturntryTrue
whilewithyield

可以输入查看关键字

import keyword
​
print(keyword.kwlist)

四.运算符

4.1 运算符

  1. 加 +

  2. 减 -

  3. 乘 *

  4. 除 /

  5. 取整除 //

  6. 取余 %

  7. 指数 **

4.2 赋值运算符

=

4.3 复合赋值运算符

  1. 加法赋值运算符 +=

  2. 减法赋值运算符 -=

  3. 乘法赋值运算符 *=

  4. 除法赋值运算符 /=

  5. 取模赋值运算符 %=

  6. 幂赋值运算符 **=

  7. 取整除赋值运算符 //=

4.4 比较运算符

1. ==
​
2. !=
​
3. >
​
4. <
​
5. >=
​
6. <=
result = 10 > 5
print(result, type(result))
​
#-- True <class 'bool'>
​
result = "zzb" == "zzb2"  # 比较两个字符串是否相等
print(result)
​
#-- False
​
num = 1
str = "1"
print(num == str)
​
#-- False

当需要判断一个变量是否介于两个值之间时,可以采用“值1<变量<值2”的形式。

4.5 逻辑运算符

运算符含义用法
and逻辑与op1 and op2
or逻辑或op1 or op2
not逻辑非not op

4.6 位运算符

不常用

五.数据输入输出

注意:默认接收的都是字符串

print("请输入姓名:")
name = input()
print("您的姓名是:" + name)
​
​
name = input("请输入姓名:")
print("您的姓名是:" + name)

5.1 教你一招

默认情况下print()输出后会自动换行,可以使用逗号“,”进行分隔达到不换行输出。

使用chr()即可通过ASCII码显示字符。

print(a,b,"要么出众,要么出局")
​
print(chr(65))

六.判断语句

6.1 if语句的基本格式

  1. if 要判断的条件: 条件成立时,要做的事情

  2. if else

  3. if elif else

  4. 判断语句的嵌套

num = 1
str = "1"
​
if num != str:
    print(num == int(str))
print(num != str)
# 如果num不等于str则比较num与转换类之后的str,最终输出num不等于str的值
​
#-- True
#-- True
​
# if else
age = input("请输入年龄:")
if int(age) >= 18:
    print("你是成年人")
else:
    print("你是未成年人")
​
# if elif else
height = int(input("请输入身高:"))
if height <= 120:
    print("免费")
elif height >= 150:
    print("需要买票,15元")
else:
    print("需要买票,10元")
​
# 判断语句的嵌套
height = int(input("请输入身高:"))
if height >= 120:
    if height <= 150:
        print("需要买票,10元")
    else:
        print("需要买票,15元")
else:
    print("免费")

七.循环

7.1 while循环

while 条件: 执行语句

import random
​
# 计算1-100的和
i = 1
sum = 0
while i <= 100:
    sum += i
    i += 1
print(sum)
​
#-- 5050

7.1.1 猜数字

# 猜数字
number = random.randint(1, 100)
total = 1
flag = True
while flag:
    guessNumber = int(input("请输入猜的数字:"))
    if guessNumber == number:
        print("恭喜你猜对了,共猜了:%s" % total)
        flag = False
    else:
        if guessNumber > number:
            print("猜大了")
        else:
            print("猜小了")
        total += 1
7.1.2 九九乘法表
# 九九乘法表
row = 1
while row <= 9:
    col = 1
    while col <= row:
        print(f"{col} * {row} = {row * col} \t", end='')
        col += 1
    row += 1
    print()

7.2 for循环

for循环(遍历循环) for 临时变量 in 待处理数据集 循环满足条件时执行的代码

1.待处理数据集 称之为 序列 2.序列类型有:字符串 列表 元组

name = "zzb"
for word in name:
    print(word)
#-- z
#-- z
#-- b
    
#计算有多少个 a
name = "itheima is a brand of itcast"
sum = 0
for letter in name:
    if letter == "a":
        sum += 1
print(sum)
​
#-- 4
​
for num in range(5, 11, 2):  # 生成一个从5开始到11(不包括 11)结束的数字序列,步长为2
    print(num)
    
#-- 5
#-- 7  
#-- 9
​
for num in range(1, 101):
    print("第%d天" % num)
    for flower in range(1, 11):
        print("第%d只花" % flower)
​
#-- 一天送一只花连续送100天
        
​
for i in range(1, 10):
    print(i)
    break

7.2.1 九九乘法表

#九九乘法表
for row in range(1, 10):
    for col in range(1, row + 1):
        print(f"{col} * {row} = {row * col}\t", end='')
    print()

7.2.2 随机数

  1. range(num) 从0开始获取一个num的序列 不包括num本身 range(3) : [0,1,2]

  2. range(num1,num2) 从num1开始获取一个num的序列 不包括num2本身 range(4,6) : [4,5,]

  3. range(num1,num2,num3) 从num1开始获取一个间隔num3的num序列 不包括num2本身 range(4,9,2) : [4,6,8]

import random
​
money = 10000
for user in range(1, 21):
    if money > 0:
        score = int(random.randint(1, 10))
        if score <= 5:
            print(f"第{user}位,绩效{score}不发放工资!")
            continue
        else:
            money -= 1000
            print(f"第{user}位,绩效{score}开始发放工资!账户余额{money}")
    else:
        print("工资发放完毕")
        break

八.函数

定义格式:

def 函数名(传入参数):
    """
        注释
    """
    函数体
    return 返回值
def add(x, y):
    """
    求和
    :param x: 入参1
    :param y: 入参2
    :return: 结果
    """
    result = x + y
    print(f"{x} + {y} = {result}")
​
​
add(1, 6)
add("1", "2")  # 进行字符串的拼接
add(1.5, 2.6)
​
#-- 1 + 6 = 7
#-- 1 + 2 = 12
#-- 1.5 + 2.6 = 4.1

函数多返回值:

def test_return_values():
    return 10, "你好", True, ["1", "2"]
​
​
data1, data2, data3, data4 = test_return_values()
print(f"第一个返回值是:{data1}")
print(f"第二个返回值是:{data2}")
print(f"第三个返回值是:{data3}")
print(f"第四个返回值是:{data4}")
​
#-- 第一个返回值是:10
#-- 第二个返回值是:你好
#-- 第三个返回值是:True
#-- 第四个返回值是:['1', '2']

函数多种传参方式:

  1. 关键字传参

  2. 缺省参数

  3. 不定长参数

  4. 关键字传递

  5. 匿名函数

# 关键字传参
def user_info(name, age, sex):
    print(f"姓名:{name},年龄:{age},性别:{sex}")
​
​
user_info("张三", 12, "男")
user_info(name="李四", age=15, sex="女")
user_info(age=15, name="王五", sex="女")
user_info("张三", age=12, sex="男")  # 位置参数必须在前
​
# 缺省参数
def default_user_info(name, age, sex="男"):
    print(f"姓名:{name},年龄:{age},性别:{sex}")
​
​
default_user_info("zzb", "45")
​
# 不定长参数
def length_user_info(*args):  # args 元组类型
    print(args)
​
​
length_user_info("zzb1", "zzb2")
​
# 关键字传递
def key_user_info(**kwargs):
    print(kwargs)
​
​
key_user_info(name="张三", age=12)
​
# 匿名函数
# 函数作为参数传递
def test_func(compute):
    result = compute(1, 2)
    print(result)
​
​
def compute(x, y):
    return x + y
​
​
test_func(compute)  # 只是计算逻辑的传递,不是值的传递
# lambda匿名函数——只可使用一次
test_func(lambda x, y: x + y)

8.1 数学运算类内置函数

函数介绍
abs(x)求绝对值 参数可以是整数,也可以是复数 若参数是复数,则返回复数的模
oct(x)将一个数字转换为八进制字符串
hex(x)将整数x转换为十六进制字符串
chr(x)返回整数x对应的ASCII字符
ord(x)返回x对应的ASCII码值

复数:形如$(a + bi) (a, b \in \mathbb{R})$的数叫复数

复数的模:指复数在复平面上到原点的距离。$\sqrt{a^2 + b^2}$

九.数据容器

  1. 列表(list)

  2. 元组(tuple)

  3. 字符串(string)

  4. 集合(set)

  5. 字典(dict)

9.1 列表

字面量:[元素1,元素2,·······]

定义变量:变量名称 = [元素1,元素2,·······]

定义空列表: 变量名称 = [] 变量名称 = list()

name_list = ['张三', '李四', 1, 1.2, [1, 2, 3]]  # 列表可以嵌套列表
print(type(name_list))
​
#-- <class 'list'>
​
for name in name_list:
    print(name, type(name))
    
#-- 张三 <class 'str'>
#-- 李四 <class 'str'>
#-- 1 <class 'int'>
#-- 1.2 <class 'float'>
#-- [1, 2, 3] <class 'list'>    
​
# 下标索引
print(name_list[0])
​
#-- 张三
​
# 获取元素的下标
print(name_list.index(1))  # 获取元素1的下标  从0开始
​
#-- 2
​
# 反向索引
print(name_list[-1])  # 从-1开始 及最后一个元素
​
#-- [1, 2, 3]
​
# 修改索引位置的元素值
name_list[0] = "王五"
print(name_list)
​
#-- ['王五', '李四', 1, 1.2, [1, 2, 3]]
​
# 在指定索引位置插入元素
name_list.insert(0, "best")  # 索引后的元素索引值加1
print(name_list)
​
#-- ['best', '张三', '李四', 1, 1.2, [1, 2, 3]]
​
# 追加元素 追加到尾部
name_list.append("Japan.txt")
print(name_list)
​
#-- ['张三', '李四', 1, 1.2, [1, 2, 3], 'Japan.txt']
​
# 把其他容器的内容追加到列表尾部
insert_list = ["qwe", "asd"]
name_list.extend(insert_list)
print(name_list)
​
#-- ['张三', '李四', 1, 1.2, [1, 2, 3], 'qwe', 'asd']
​
# 删除元素 (1) 直接删除指定索引的元素
del name_list[0]
print(name_list)
​
#-- ['李四', 1, 1.2, [1, 2, 3]]
​
# 删除元素 (2)删除指定索引的元素,返回被删除的元素
name_list.pop(0)
print(name_list)
​
#-- 张三
#-- ['李四', 1, 1.2, [1, 2, 3]]
​
# 删除元素在列表中的第一个匹配项
name_list.remove("李四")
print(name_list)
​
#-- ['张三', 1, 1.2, [1, 2, 3]]
​
# 清空列表
name_list.clear()
print(name_list)
​
#-- []
​
# 遍历列表
index = 0
while index < len(name_list):
    print(name_list[index])
    index += 1
​
for element in name_list:
    print(element)    

9.2 元组

元组(一旦定义完成,不允许修改) 字面量:(元素1,元素2,·······) 定义变量:变量名称 = (元素1,元素2,·······) 定义空列表: 变量名称 = () 变量名称 = tuple() 注意: 单个元组必须以逗号(,)结尾,否则会认定为字符串

t1 = ('nihao', 'python', 'nihao')
print(t1, type(t1))

#-- ('nihao', 'python', 'nihao') <class 'tuple'>

t2 = ('你好',)  # 注意这里必须加, 如果不加会默认为字符串
print(t2, type(t2))

#-- ('你好') <class 'tuple'>

# 嵌套元组 与取出内容
t3 = ((1, 2, 3), (4, 5, 6))
num = t3[1][2]
print(num)

#-- 6

# 查找元组中的某个元组坐标
print(t1.index('python'))

#-- 1

# 统计元组中某个元素出现的次数
print(t1.count('nihao'))

#-- 2

# 统计元组中元素的数量
print(len(t1))

#-- 3

9.3 字符串

# 字符串
str1 = "nihao"

# 下标索引取值
print(str1[0])

#-- n

# 查找特定字符串的下标索引值
print(str1.index("hao"))
#-- 2


# 字符串的替换 不是原来的字符串 是一个新的字符串
print(str1.replace("hao", "ni123"))

#-- nini123

# 字符串的分割
str1 = "hello world"
print(str1.split(" "))

#-- ['hello', 'world']

# 字符串的规整操作
# 去除前后空格
str2 = " hello world "
print(str2)
#--  hello world 

print(str2.strip())
#-- hello world



# 去除前后指定字符串
str3 = "123 nihao 312"
print(str3.strip("12"))  # 其实是去除 单个 1,2

#-- 3 nihao 3

# 统计字符串中 某字符串出现的次数
print(str3.count("3"))

#-- 2

# 统计字符串长度
print(len(str3))

#-- 13

9.4 集合

集合 不支持重复元素 不支持下标索引 支持修改 字面量:{元素1,元素2,·······} 定义变量:变量名称 = {元素1,元素2,·······} 定义空列表: 变量名称 = set()

# 集合添加元素
my_set = {"Hello", "World"}
my_set.add("123")
print(my_set)

#-- {'World', '123', 'Hello'}

# 移除集合中元素
my_set.remove("World")
print(my_set)

#-- {'123', 'Hello'}

# 从集合中随机取出元素,集合本身被修改,元素被移除
print(my_set.pop())
print(my_set)

#-- World
#-- {'Hello', '123'}

# 清空集合,集合本身被清除
my_set.clear()
print(my_set)

#-- set()

# 取出两个集合的差集
my_set1 = {"1", "2", "3"}
my_set2 = {"3", "4", "5"}
print(my_set1.difference(my_set2))  # 取出集合1和集合2的差集(集合1有而集合2没有)原来集合的元素不变

#-- {'2', '1'}

# 清除两个集合的差集
my_set1.difference_update(my_set2)  # 对比集合1集合2,在集合1内删除集合2相同的元素 集合1被修改 集合2 不变
print(my_set1)
print(my_set2)

#-- {'1', '2'}
#-- {'4', '3', '5'}

# 两个集合合并成一个
print(my_set1.union(my_set2))  # 得到新的集合,集合1集合2不变

#-- {'2', '4', '3', '1', '5'}

# 统计集合元素数量
print(len(my_set1))

#-- 3

# 集合的遍历
for data in my_set1:
    print(data)
    
#-- 1
#-- 2
#-- 3    

十.序列与切片

序列: 内容连续、有序,可使用下标索引的一类数据容器 列表、元组、字符串,均可以视为序列 切片: 从一个序列中,取出一个子序列 语法: 序列[起始下标:结束下标:步长] 起始下标可以为空:视为从头开始 结束下标(不含)可以为空:视为到头结束 步长表示依次取元素的间隔:

  • 步长1表示,一个个取元素

  • 步长2表示,每次跳过1个元素取

  • 步长N表示,每次跳过N-1个元素取

  • 步长为负数表示,反向取(注意,起始下标和结束下标也要反向标记)

my_list = [0, 1, 2, 3, 4, 5, 6]
print(my_list[1:4:1])  # 不含索引为4的元素

#-- [1, 2, 3]

print(my_list[:])  # 从头开始 到头结束 步长为1(省略)

#-- [0, 1, 2, 3, 4, 5, 6]

print(my_list[3:1:-1])

#-- [3, 2]

print(my_list[::2])  # 包含

#-- [0, 2, 4, 6]

print(my_list[::1])  # 包含

#-- [0, 1, 2, 3, 4, 5, 6]

10.1 sort排序

my_list = [["a", 22], ["b", 60], ["c", 45], ["d", 2], ["e", 42]]


def sort(element):
    return element[1]


my_list.sort(key=sort, reverse=True)
print(my_list)

# lambda

my_list.sort(key=lambda element: element[1], reverse=False)
print(my_list)

十一.字典

字典 使用{} 存储的元素是键值对 {key:value,key:value,············} my_dict = {key:value,key:value,······} my_dict = {} my_dict = dict()

my_dict = {"张三": 88, "李四": 85}

# 嵌套字典
stu_dict = {
    "张三": {
        "语文": 80,
        "英语": 90
    },
    "李四": {
        "语文": 85,
        "英语": 80
    }
}

# 查询张三的语文成绩
print(stu_dict["张三"]["语文"])

#-- 80

# 新增元素
my_dict["王五"] = 90
print(my_dict)

#-- {'张三': 88, '李四': 85, '王五': 90}

# 更新元素
my_dict["张三"] = 80
print(my_dict)

#-- {'张三': 80, '李四': 85, '王五': 90}

# 删除元素
score = my_dict.pop("张三")
print(score)
print(my_dict)

#-- 80
#-- {'李四': 85, '王五': 90}

# 清空元素
my_dict.clear()
print(my_dict)

#-- {}

# 获取全部的key
my_dict = {"张三": 88, "李四": 85, "王五": 60}
keys = my_dict.keys()
print(keys)

#-- dict_keys(['张三', '李四', '王五'])

# 遍历字典 1
for key in keys:
    print(f"{key}: {my_dict[key]}")
    
#-- 张三: 88
#-- 李四: 85
#-- 王五: 60

# 遍历字典 2
for key in my_dict:
    print(f"{key}: {my_dict[key]}")

# 统计字典内元素数量
num = len(my_dict)
print(num)

#-- 3

十二.文件

12.1 文件的读取(r)

语法:

open(name,mode,encoding)

  • name: 打开的文件名(可以包含文件名的具体路径)

  • mode: 设置打开文件的模式(访问模式):只读、读写、追加等

  • encoding: 编码格式 encoding 的顺序不是第三位,所以不能用位置参数,用关键字参数直接指定

f = open("D:\\study\\python\\pythonProject\\file\\test.txt", "r", encoding="UTF-8")

# read 方法
# 文件对象.read(num) num:从文件中读取的数据长度(单位为字节),如果没有num表示读取全部数据
content1 = f.read(5)
print(content1)
content2 = f.read()  # 第二次读会延续上次的位置
print(content2)

f.close()


# readlines 方法
# 按照行的方式读取全部文件内容,返回一个列表,每一行数据为一个元素
f = open("D:\\study\\python\\pythonProject\\file\\test.txt", "r", encoding="UTF-8")
context = f.readlines()
print(f"读取的内容是:{context}")
f.close()


# readline 方法
# 读取一行内容
# for循环读取文件
f = open("D:\\study\\python\\pythonProject\\file\\test.txt", "r", encoding="UTF-8")
for line in f:
    print(f"内容是:{line}")

f.close()  # 文件关闭

# with open 在操作完成后自动关闭文件
with open("D:\\study\\python\\pythonProject\\file\\test.txt", "r", encoding="UTF-8") as newFile:
    for line in newFile:
        print(line)

12.2 文件的写入(w)

f = open("D:\\study\\python\\pythonProject\\file\\write.txt", "w", encoding="UTF-8") # w模式

# 如果文件不存在 新建文件
# 如果文件内容不为空 会覆盖原有内容

f.write("zzb")  # 并未真正写入文件 积攒在内容中(缓冲区)

# 内容刷新
f.flush()  # 真正写入文件

f.close()

12.3 文件的追加(a)

f = open("D:\\study\\python\\pythonProject\\file\\write.txt", "a", encoding="UTF-8")  # a模式

# 如果文件不存在 新建文件
# 追加至文件内容后

f.write("zzb")  # 并未真正写入文件 积攒在内容中(缓冲区)

# 内容刷新
f.flush()  # 真正写入文件

f.close()

十三.异常

try: 可能发生异常的代码 except: 如果出现异常执行的代码

try:
    f = open("D:\\study\\python\\pythonProject\\file\\1.txt", "r", encoding="UTF-8")
except FileNotFoundError as e:
    print("报错啦")

try:
    print(name)
except NameError as e:
    print("未定义的变量")

try:
    print(name)
    0 / 1
except (NameError, ZeroDivisionError) as e:
    print("捕获了异常")

try:
    print(1)
except NameError as e:
    print("出现了异常")
else:
    print("没有异常")

try:
    f = open("D:\\study\\python\\pythonProject\\file\\write.txt", "r", encoding="UTF-8")
except FileNotFoundError as e:
    print("报错啦!文件不存在")
else:
    print("文件正常打开!")
finally:
    f.close()

13.1 异常的传递

当函数1发生异常,并且没有捕获到异常,异常会传递到下一个函数,直到main函数也没有捕获到异常,程序就会报错

def func1():
    print("函数1开始执行")
    1 / 0
    print("函数1结束执行")

def func2():
    print("函数2开始执行")
    func1()
    print("函数2结束执行")

def func3():
    print("函数3开始执行")
    func2()
    print("函数3结束执行")


func3()

十四.Python模块

模块是一个python文件,能定义函数、类和变量,也可以包含可执行代码 模块导入方式: [from 模块名] import [模块 | 类 | 变量 | 函数 | *] [as 别名]

常用组合形式: import 模块名 from 模块名 import 类、变量、方法等 from 模块名 import * import 模块名 as 别名 from 模块名 import 功能名 as 别名

import time

time.sleep(2)

新增模块 my_module1

def my_function(a, b, c):
    print("I am a function")
    result = (a + b) * c
    print(result)

    return result


print(__name__)

"""
使用main运行时 __name__ 为 __main__
使用import 导入模块时 __name__ 为 模块名
"""
if __name__ == '__main__':
    my_function(1, 2, 3)
__all__ = ['test1']  # 当使用 from my_model2 import * 时 只会引入test1方法


def test1(a, b):
    return a + b


def test2(a, b):
    return a * b
import my_module1
from my_module2 import *

my_module1.my_function(1, 6, 5)
test1(1, 6)

14.1 样式模块包

  • import 导入

  • from 导入

import my_package.my_module1
import my_package.my_module2

my_package.my_module1.info_print1()
my_package.my_module2.info_input2()
from my_package import my_module1

my_module1.info_print1()

from my_package.my_module2 import info_input2

info_input2()
# 在__init__ 中使用 __all__ = ["my_module1"] 限制 * 形式的模块导入

from my_package import *
my_module1.info_print1()

# my_module2.info_print2()

十五.第三方包的引入

# 安装命令
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名

十六.对象

class Student:
    name = None
    sex = None
    age = None

    def say_hello(self):
        print(f'你好我是{self.name}')

    def say_goodbye(self, message):
        print(f"再见,{message}")


student_1 = Student()

student_1.name = "张三"
student_1.sex = "男"
student_1.age = 18
student_1.say_hello()
student_1.say_goodbye("zzb")


class User:
    name = None
    age = None
    sex = None

    def __init__(self, name, age, sex):  # 构造方法
        self.name = name
        self.age = age
        self.sex = sex

    def __str__(self):  # toString
        return f"user类对象,name = {self.name},age = {self.age},sex = {self.sex}"

    def __lt__(self, other):  # 比较大小 小于 大于(<,>)
        return self.age < other.age

    def __le__(self, other):  # 比较大小 小于等于 大于等于 (<=,>=)
        return self.age <= other.age

    def __eq__(self, other):  # 比较大小 等于(=)
        return self.age == other.age

user_1 = User("张三", 12, "男")
user_2 = User("李四", 14, "男")
print(str(user_1))
print(user_1 < user_2)

16.1 私有成员变量、私有成员方法

class Phone:
    IMEI = None  # 序列号
    producer = None  # 厂商

    # 私有成员变量
    __current_voltage = 0.5  # 当前电压

    def call_by_5g(self):
        print("5G")

    # 私有成员方法
    def __keep_single_core(self):
        print("单核模式运行")

    def call_by_5g(self):
        if self.__current_voltage >= 1:
            print("开启通话")
        else:
            print("调度开始")
            self.__keep_single_core()



phone = Phone()
phone.call_by_5g()

十七.继承

class Phone:
    __is_5g_enable = False

    def __check_5g(self):
        if self.__is_5g_enable:
            print("开启5G")
        else:
            print("5G关闭、使用4G网络")

    def call_by_5g(self):
        self.__check_5g()
        print("正在通话中")


# 继承Phone
class Phone2024(Phone):
    face_id = "100001"

    def new(self):
        print("2024年新功能")


phone = Phone2024()
phone.call_by_5g()
phone.new()


class NFCReader():
    nfc_type = "第五代"

    def read_nfc_type(self):
        print(f"{self.nfc_type}")


class RemoteControl():
    rc_type = "红外遥控"

    def read_rc_type(self):
        print(f"{self.rc_type}")


class MyPhone(NFCReader, RemoteControl):

    def print_hello(self):
        print(f"你好")


my_phone = MyPhone()

十八.复写

class Phone:
    IMEI = None
    producer = "ITCAST"

    def call_by_5G(self):
        print("父类的5G通话")


class MyPhone(Phone):
    producer = "ZZB"

    def call_by_5G(self):
        # 调用父类成员
        # 方式一:
        Phone.call_by_5G(self)
        # 方式二:
        print(super().producer)

        print("子类的5G通话")


phone = MyPhone()
phone.call_by_5G()

十九.类型注解

var_1: int = 10
var_2: float = 20.22
var_3: str = "3.14"
var_4: bool = True

# my_list: list = [1, 2, 3, 4, 5]
# my_tuple: tuple = (1, 2, 3, 4, 5)
# my_set: set = {1, 2, 3, 4, 5, 6}
# my_dict: dict = {"1": 6}
# my_str: str = "zzb"

# 容器详细注解
my_list: list[int] = [1, 2, 3, 4, 5]
my_tuple: tuple[str, int, bool] = ("zzb", 66, False)
my_set: set[int] = {1, 2, 3, 4, 5, 6}
my_dict: dict[str, int] = {"1": 6}


class Student:
    def test(self):
        print(f"你好")


stu: Student = Student()

"""
形参注解
"""


def func(x: int, y: int):
    print("123")


func(1, 2)


# 对返回值进行注解
def func(x: int, y: int) -> float:
    return x * y


result = func(1, 2)
print(result, type(result))

# union 类型联合注解

from typing import Union

my_list_union: list[Union[int, str]] = [1, 2, 3, 4, 5, "123"]

my_dict_union: dict[str, Union[int, str]] = {"age": 6, "sex": "男"}


def func(data: Union[int, str]) -> Union[int, str]:
    print(data)
    return data


func(789)
func("456")

二十.多态

class Animal:
    def speak(self):  # 抽象方法
        pass  # 空实现 由子类决定


class Dog(Animal):
    def speak(self):
        print("汪汪汪")


class Cat(Animal):
    def speak(self):
        print("喵喵喵")


def make_noise(animal: Animal):
    animal.speak()


dog = Dog()
cat = Cat()

make_noise(dog)
make_noise(cat)

二十一.Spark

spark 大规模数据处理分析引擎 用于计算大量数据

pip install -i Simple Index pyspark

from pyspark import SparkConf, SparkContext

# 创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")

# 基于SparkConf类对象创建SparkContext类对象
sc = SparkContext(conf=conf)

print(sc.version)

sc.stop()

21.1 RDD(弹性分布式数据集)对象

from pyspark import SparkConf, SparkContext

# 创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")

# 基于SparkConf类对象创建SparkContext类对象
sc = SparkContext(conf=conf)

rdd1 = sc.parallelize([1, 2, 3, 4, 5, 6])
rdd2 = sc.parallelize((1, 2, 3, 4, 5, 6, 7))
rdd3 = sc.parallelize("abc")
rdd4 = sc.parallelize({1, 2, 3, 6, 5, 4, 8, 9})
rdd5 = sc.parallelize({"name": "张三", "age": 23})

# 查看RDD 需要用collect()方法
print(rdd1.collect())
print(rdd2.collect())
print(rdd3.collect())
print(rdd4.collect())
print(rdd5.collect())

sc.stop()

21.2 PySpark RDD成员方法

21.2.1 map算子

from pyspark import SparkConf, SparkContext
import os

# 设置环境变量
os.environ['PYSPARK_PYTHON'] = 'D:\\soft\\python-3.10.11\\python.exe'

# 创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")

# 基于SparkConf类对象创建SparkContext类对象
sc = SparkContext(conf=conf)

rdd = sc.parallelize([1, 2, 3, 4, 5])


def func(data):
    return data * 10


# 通过map方法将全部数据乘10
# rdd2 = rdd.map(func)
rdd2 = rdd.map(lambda x: x * 10)
# (T) -> U  (T):传入参数  U:返回值

print(rdd2.collect())

sc.stop()

21.2.2 flatMap算子

对RDD执行map操作,然后禁用接触嵌套操作

from pyspark import SparkConf, SparkContext
import os

# 设置环境变量
os.environ['PYSPARK_PYTHON'] = 'D:\\soft\\python-3.10.11\\python.exe'

conf = SparkConf().setMaster("local[*]").setAppName("test_flatMap")
sc = SparkContext(conf=conf)

rdd = sc.parallelize(["zzb 666", "python"])

rdd1 = rdd.flatMap(lambda x: x.split(" "))
print(rdd1.collect())

21.2.3 reduceByKey

对KV型RDD,自动按照key分组,然后根据聚合逻辑,完成组内数据(value)的聚合操作

from pyspark import SparkConf, SparkContext
import os

# 设置环境变量
os.environ['PYSPARK_PYTHON'] = 'D:\\soft\\python-3.10.11\\python.exe'

conf = SparkConf().setMaster("local[*]").setAppName("test_reduceByKey")
sc = SparkContext(conf=conf)

rdd = sc.parallelize([('a', 2), ('a', 3), ('b', 2), ('b', 5)])

rdd1 = rdd.reduceByKey(lambda x, y: x + y)
print(rdd1.collect())

21.2.4 filter

过滤想要的数据进行保留

from pyspark import SparkConf, SparkContext
import os

# 设置环境变量
os.environ['PYSPARK_PYTHON'] = 'D:\\soft\\python-3.10.11\\python.exe'

conf = SparkConf().setMaster("local[*]").setAppName("test_reduceByKey")
sc = SparkContext(conf=conf)

rdd = sc.parallelize([1, 2, 3, 4, 5, 6, 7, 8, 9, 1])

rdd1 = rdd.filter(lambda x: x % 2 == 0)
print(rdd1.collect())

21.2.5 distinct(去重)

from pyspark import SparkConf, SparkContext
import os

# 设置环境变量
os.environ['PYSPARK_PYTHON'] = 'D:\\soft\\python-3.10.11\\python.exe'

conf = SparkConf().setMaster("local[*]").setAppName("test_reduceByKey")
sc = SparkContext(conf=conf)

rdd = sc.parallelize([1, 2, 3, 4, 5, 6, 7, 8, 9, 1])

rdd2 = rdd.distinct()
print(rdd2.collect())

21.2.6 sortBy(排序)

ascending : True(升序) False(降序) numPartitions : 用多少分区排序

from pyspark import SparkConf, SparkContext
import os

# 设置环境变量
os.environ['PYSPARK_PYTHON'] = 'D:\\soft\\python-3.10.11\\python.exe'

conf = SparkConf().setMaster("local[*]").setAppName("test_reduceByKey")
sc = SparkContext(conf=conf)

rdd = sc.parallelize([1, 2, 3, 4, 5, 6, 7, 8, 9, 1])

rdd3 = rdd.sortBy(lambda x: x, True, 1)
print(rdd3.collect())

21.2.7 collect

将RDD内容转换为list

from pyspark import SparkConf, SparkContext
import os

# 设置环境变量
os.environ['PYSPARK_PYTHON'] = 'D:\\soft\\python-3.10.11\\python.exe'

conf = SparkConf().setMaster("local[*]").setAppName("test_reduce")
sc = SparkContext(conf=conf)

rdd = sc.parallelize([1, 2, 3, 4, 5, 6, 7])

rdd1 = rdd.collect()
print(rdd1)

21.2.8 reduce

对RDD内容进行自定义聚合

from pyspark import SparkConf, SparkContext
import os

# 设置环境变量
os.environ['PYSPARK_PYTHON'] = 'D:\\soft\\python-3.10.11\\python.exe'

conf = SparkConf().setMaster("local[*]").setAppName("test_reduce")
sc = SparkContext(conf=conf)

rdd = sc.parallelize([1, 2, 3, 4, 5, 6, 7])

rdd1 = rdd.reduce(lambda x, y: x + y)
print(rdd1)

21.2.9 take

取出前N个元素 组成list

from pyspark import SparkConf, SparkContext
import os

# 设置环境变量
os.environ['PYSPARK_PYTHON'] = 'D:\\soft\\python-3.10.11\\python.exe'

conf = SparkConf().setMaster("local[*]").setAppName("test_reduce")
sc = SparkContext(conf=conf)

rdd = sc.parallelize([1, 2, 3, 4, 5, 6, 7])

rdd2 = rdd.take(3)
print(rdd2)

21.2.10 count

计算有多少个元素

from pyspark import SparkConf, SparkContext
import os

# 设置环境变量
os.environ['PYSPARK_PYTHON'] = 'D:\\soft\\python-3.10.11\\python.exe'

conf = SparkConf().setMaster("local[*]").setAppName("test_reduce")
sc = SparkContext(conf=conf)

rdd = sc.parallelize([1, 2, 3, 4, 5, 6, 7])

rdd3 = rdd.count()
print(rdd3)

21.2.11 saveAsTextFile

需要配置Hadoop依赖

from pyspark import SparkConf, SparkContext
import os

# 设置环境变量
os.environ['PYSPARK_PYTHON'] = 'D:\\soft\\python-3.10.11\\python.exe'
os.environ['HADOOP_HOME'] = 'D:\\soft\\hadoop\\hadoop-3.0.0'

conf = SparkConf().setMaster("local[*]").setAppName("test_reduce")
conf.set("spark.default.parallelism", "1")  # 设置并行度 方式一
sc = SparkContext(conf=conf)

rdd = sc.parallelize([1, 2, 3, 4, 5, 6, 7])

# 方式二
# 创建rdd时设置
# rdd1 = sc.parallelize([1, 2, 3, 4, 5, 6, 7], numSlices=1)
# rdd2 = sc.parallelize([1, 2, 3, 4, 5, 6, 7], 1)

rdd.saveAsTextFile("D:\\output")

二十二.闭包

# 全局变量account_amount有被修改的风险

account_amount = 0


def atm(num, deposit=True):
    global account_amount
    if deposit:
        account_amount += num
        print(f"存款金额:", account_amount)
    else:
        account_amount -= num
        print(f"取款金额:", account_amount)


atm(300)
atm(300)
atm(100, False)
def outer(logo):
    def inner(msg):
        print(f"<{logo}>{msg}")

    return inner


fn1 = outer("zzb1")
fn1("hello")

fn2 = outer("zzb2")
fn2("hello world")


# 修改atm的实现

def account_amount(money=0):
    def atm(num, deposit=True):
        nonlocal money  # 内部函数可以修改外部函数的变量
        if deposit:
            money += num
            print(f"存款金额:", money)
        else:
            money -= num
            print(f"取款金额:", money)

    return atm


atm = account_amount()
atm(300)

"""
装饰器
"""


# def outer(func):
#     def inner():
#         print("我要睡觉了...")
#         func()
#         print("睡醒了...")
#
#     return inner


# def sleep():
#     import random
#     import time
#     print("睡觉中...")
#     time.sleep(random.randint(1, 3))


# fn = outer(sleep)
# fn()


# 装饰器的语法糖写法
def outer(func):
    def inner():
        print("我要睡觉了...")
        func()
        print("睡醒了...")

    return inner

@outer
def sleep():
    import random
    import time
    print("睡觉中...")
    time.sleep(random.randint(1, 3))

sleep()

二十三.设计模式

  • 单例模式

  • 工厂模式

class StrTools:
    pass

str_tool = StrTools()
class Person:
    pass


class Worker(Person):
    pass


class Student(Person):
    pass


class Teacher(Person):
    pass


class Factory:
    def get_person(self, type):
        if type == 'worker':
            return Worker()
        elif type == 'student':
            return Student()
        elif type == 'teacher':
            return Teacher()
        else:
            return None


factory = Factory()
worker = factory.get_person('worker')
print(worker)
from demo44_1 import str_tool

# 单例模式

s1 = str_tool
s2 = str_tool

print(id(s1))
print(id(s2))


# class str_tool2:
#     pass
#
#
# s3 = str_tool2
# s4 = str_tool2
#
# print(id(s3))
# print(id(s4))

二十三.多线程

threading.Thread() 参数: group:暂时无用,预留参数 target:执行的目标任务名 args:以元组的方式给执行任务传参 kwargs:以字典方式给执行任务传参 name:线程名,一般不设置

import threading
import time

def sing(msg):
    while True:
        print(msg)
        time.sleep(1)


def dance(msg):
    while True:
        print(msg)
        time.sleep(2)


if __name__ == '__main__':
    dance_thread = threading.Thread(target=dance, args=('我要跳舞',))
    sing_thread = threading.Thread(target=sing, kwargs={"msg": "我在唱歌"})

    dance_thread.start()
    sing_thread.start()

二十四.网络变成

24.1 socket 服务端

import socket

# 创建 socket对象
socket_server = socket.socket()

# 绑定端口
socket_server.bind(('127.0.0.1', 8888))

# 监听
socket_server.listen(1)  # 允许链接的数量

# 等待客户端链接
# 返回二元元组
result: tuple = socket_server.accept()

# conn = result[0]  # 客户端和服务端的链接对象
# address = result[1]  # 客户端的地址信息
conn, address = result
# accept() 是阻塞的方法 等待连接,如果没有连接 卡在这一行不执行

print(f"接收到连接,信息为:{address}")

while True:
    # 接收客户端发送的信息
    # 使用conn 对象接收信息
    data = conn.recv(1024).decode("UTF-8")
    # recv 缓冲区大小 , 返回字节数组 通过decode 转换为字符串
    if data == "exit":
        break
    print(f"接收到客户端发送的信息为:{data}")
    # 发送信息给客户端
    reply = input("请输入要发送的信息:").encode("UTF-8")
    conn.send(reply)

# 关闭链接
conn.close()

24.2 socket 客户端

import socket

# 创建 socket对象
socket_client = socket.socket()

socket_client.connect(('127.0.0.1', 8888))

while True:
    msg = input("请输入要发送的数据:")
    if msg == "exit":
        break
    socket_client.send(msg.encode("utf-8"))
    data = socket_client.recv(1024)
    print("服务端回复:", data.decode("utf-8"))

socket_client.close()

二十五.正则表达式

  • match 从头开匹配

  • search 搜索整个字符串 从头开始 找到第一个结束

  • findall 查询全部

import re

s = "hello world"

result = re.match('hello', s)

print(result)
print(result.span())
print(result.group())

s1 = "hello world hello"

result2 = re.search('world', s1)

print(result2)

s3 = "hello world hello"

result3 = re.findall('hello', s3)
print(result3)

# 元字符匹配

s = "zzb dsg1"

result4 = re.findall(r'\d', s)  # 字符串带 r 表示转义字符无效
print(result4)

二十六.操作MySQL数据库

from dbutils.pooled_db import PooledDB
import pymysql

# 创建连接池
pool = PooledDB(
    creator=pymysql,  # 使用pymysql作为数据库驱动
    maxconnections=100,  # 连接池允许的最大连接数
    mincached=10,  # 初始化时,连接池中至少创建的空闲的连接
    maxcached=10,  # 连接池中最多闲置的连接
    maxshared=30,  # 连接池中最多共享的连接数量
    blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待
    setsession=[],  # 开始会话前执行的命令列表
    ping=0,  # ping MySQL服务端,检查是否服务可用
    host='192.168.1.61',  # 本地
    port=3306,
    user='root',
    password='123456',
    database='web',
    charset='utf8',
    cursorclass=pymysql.cursors.DictCursor
)


class load_mysql:

    def __init__(self):
        return

    # 使用连接池
    def query_db(sql, params=None):
        # 从连接池中获取连接
        conn = pool.connection()
        # 获取游标对象
        cursor = conn.cursor()
        try:
            if params:
                # 执行sql
                cursor.execute(sql, params)
            else:
                cursor.execute(sql)
            # 从结果集中获取所有(剩余的)行,返回一个列表。每一行是一个元组,包含了查询结果中的字段值。如果结果集为空,将返回一个空列表。
            result = cursor.fetchall()
            conn.commit()  # 提交
            return result
        except Exception as e:
            conn.rollback()  # 回滚
            print(f"An error occurred: {e}")
            return None
        finally:
            # 关闭游标和连接
            cursor.close()
            conn.close()

    # 使用连接池执行插入操作
    def insert_db_return_number(sql, params=None):
        # 从连接池中获取连接
        conn = pool.connection()
        cursor = conn.cursor()
        try:
            if params:
                cursor.execute(sql, params)
            else:
                cursor.execute(sql)
            conn.commit()  # 提交事务
            return cursor.rowcount  # 返回最后修改的行数
        except Exception as e:
            conn.rollback()  # 发生错误时回滚事务
            print(f"An error occurred: {e}")
            return None
        finally:
            # 关闭游标和连接
            cursor.close()
            conn.close()

    def insert_db_return_numbers(sql, params=None):
        conn = pool.connection()
        cursor = conn.cursor()
        try:
            if params:
                cursor.execute(sql, params)
            else:
                cursor.execute(sql)
            conn.commit()
            return cursor.rowcount
        except Exception as e:
            if "Duplicate entry" in str(e):
                print("Insertion failed: Duplicate entry")
            else:
                print(f"An error occurred: {e}")

            conn.rollback()
            return None
        finally:
            cursor.close()
            conn.close()

        # 使用连接池执行插入操作

    def insert_db_return_id(sql, params=None):
        # 从连接池中获取连接
        conn = pool.connection()
        cursor = conn.cursor()
        try:
            if params:
                cursor.execute(sql, params)
            else:
                cursor.execute(sql)
            conn.commit()  # 提交事务
            return cursor.lastrowid  # 返回最后插入的id
        except Exception as e:
            conn.rollback()  # 发生错误时回滚事务
            print(f"An error occurred: {e}")
            return None
        finally:
            # 关闭游标和连接
            cursor.close()
            conn.close()

    # 修改返回id
    def update_db_return_id(sql, params=None):
        # 从连接池中获取连接
        conn = pool.connection()
        cursor = conn.cursor()
        try:
            if params:
                cursor.execute(sql, params)
            else:
                cursor.execute(sql)
            conn.commit()  # 提交事务
            return cursor.lastrowid  # 返回最后插入行的主键ID
        except Exception as e:
            conn.rollback()  # 发生错误时回滚事务
            print(f"An error occurred: {e}")
            return None
        finally:
            # 关闭游标和连接
            cursor.close()
            conn.close()

    def update_db_return_number(sql, params=None):
        # 从连接池中获取连接
        conn = pool.connection()
        cursor = conn.cursor()
        try:
            if params:
                cursor.execute(sql, params)
            else:
                cursor.execute(sql)
            conn.commit()  # 提交事务
            return cursor.rowcount  # 返回最后修改的行数
        except Exception as e:
            conn.rollback()  # 发生错误时回滚事务
            print(f"An error occurred: {e}")
            return None
        finally:
            # 关闭游标和连接
            cursor.close()
            conn.close()

    # 使用连接池执行删除操作
    def delete_db(sql, params=None):
        # 从连接池中获取连接
        conn = pool.connection()
        cursor = conn.cursor()
        try:
            if params:
                cursor.execute(sql, params)
            else:
                cursor.execute(sql)
            conn.commit()  # 提交事务
            return cursor.rowcount  # 返回被删除的行数
        except Exception as e:
            conn.rollback()  # 发生错误时回滚事务
            print(f"An error occurred: {e}")
            return None
        finally:
            # 关闭游标和连接
            cursor.close()
            conn.close()
import connectMySQL

goods_id = 1
user_id = 1
sql = "select * from ygh_order where goods_id=%s and user_id=%s"
param = (goods_id, user_id)
result = connectMySQL.load_mysql.query_db(sql, param)

for row in result:
    print(row)

二十七.常用的GUI框架

27.1 什么是GUI

GUI全称为Graphical User Interface,即图形用户界面,是一种采用图形方式显示的计算机操作用户界面。

27.1.1 常用的GUI框架

  • wxPython

  • Kivy

  • Flexx

  • PyQt

  • Tkinter

  • Pywin32

  • PyGTK

  • pyui4win

27.2 wxPython的使用

27.2.1 安装wxPython

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple wxPython

27.2.2 创建一个wx.App的子类

import wx


class App(wx.App):
    # 初始化
    def OnInit(self):
        frame = wx.Frame(None, title='Hello World')  # 创建一个窗口
        frame.Show()  # 显示窗口
        return True


if __name__ == '__main__':
    app = App()  # 创建App类的实例
    app.MainLoop()  # 调用App类的MainLoop()主循环方法

27.2.3 直接使用wx.App

import wx

app = wx.App()  # 初始化wx.APP类
frame = wx.Frame(None, title='Hello World')  # 创建一个窗口
frame.Show()  # 显示窗口
app.MainLoop()  # 调用App类的MainLoop()主循环方法

上述代码中,wx.App()初始化wx.App类,包含了OnInit()方法。

27.2.4 使用wx.Frame框架

框架是一个容器,用户可以将它在屏幕上任意移动,并可对他进行缩放,它通常包含标题栏、菜单等。wx.Frame是所有框架的父类。当创建wx.Frame的子类时,子类应调用其父类的构造器。wx.Frame构造器语法格式如下:

wx.Frame.__init__(parent, id=-1, title="", pos=wx.DefaultPosition, size=DefaultSize,style=wx.DEFAULT_FRAM_STYLE,name="frame")

参数说明:

paremt:框架的父窗口。如果是顶级窗口,这个值是None。

id:关于新窗口的id号。通常设为-1,让wx.Frame自动生成一个新的id。

title:窗口的标题。

pos:指定这个新窗口的左上角在屏幕中的位置。通常(0,0)是显示器的左上角。(-1,-1)将让系统决定窗口的位置。

size:指定这个窗口的初始尺寸。(-1,-1)将让系统决定窗口的初始尺寸。

style:指定窗口的类型常量。

name:框架内在的名字。可以通过它来寻找这个窗口。

import wx


class MyFrame(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, title="创建 Frame", pos=(100, 100), size=(300, 300))


if __name__ == '__main__':
    app = wx.App()  # 初始化应用
    frame = MyFrame(None, -1)  # 实例化MyFrame类,并传递参数
    frame.Show()  # 显示窗口
    app.MainLoop()

27.2.5 常用控件

27.2.5.1 StaticText文本类

在屏幕上绘制纯文本

wx.StaticText(parent, id, label, pos=wx.DefaultPosition, size=DefaultSize, style=0, name="staticText")

wx.StaticText构造函数的参数如下:

  • parent:父窗口部件

  • id:标识符。使用-1可以自动创建一个唯一的标识

  • label:显示在静态控件中的文本内容

  • pos:窗口部件的位置

  • size:窗口部件的尺寸

  • style:样式标记

  • name:对象的名字

import wx


class MyFrame(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, title="创建 StaticText", pos=(100, 100), size=(600, 400))

        panel = wx.Panel(self)  # 创建画板
        title = wx.StaticText(panel, label="Python 之禅——Tim Peters", pos=(100, 20))
        # 创建标题并设置字体 
        font = wx.Font(16, wx.DEFAULT, wx.FONTSTYLE_NORMAL, wx.NORMAL)
        title.SetFont(font)
        # 创建文本
        wx.StaticText(panel, label="优美胜于丑陋", pos=(50, 50))
        wx.StaticText(panel, label="明了胜于晦涩", pos=(50, 70))
        wx.StaticText(panel, label="简洁胜于复杂", pos=(50, 90))
        wx.StaticText(panel, label="复杂胜于凌乱", pos=(50, 110))
        wx.StaticText(panel, label="扁平胜于嵌套", pos=(50, 130))
        wx.StaticText(panel, label="间隔胜于紧凑", pos=(50, 150))
        wx.StaticText(panel, label="可读性胜于效率", pos=(50, 170))


if __name__ == '__main__':
    app = wx.App()  # 初始化应用
    frame = MyFrame(None, id=-1)  # 实例化MyFrame类,并传递参数
    frame.Show()  # 显示窗口
    app.MainLoop()

字体参数说明:

  • pointSize:字体的整体尺寸,单位为磅

  • family:字体

  • style:字体是否倾斜

  • weight:字体的醒目程度

  • underline:仅在Windows下有效,True则加下划线,False无下划线

  • faceName:字体的名称

  • encoding:编码

wx.Font(pointSize, family, style, weight, underline=False, faceName="", encoding=wx.FONTENCODING_DEFAULT)
27.2.5.2 TextCtrl 输入文本类

允许输入单行或多行文本。也可以作为密码输入控件,掩饰所按下的按键。

wx.TextCtrl(parent, id, value="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, validator=wx.DefaultValidator, name=wx.TextCtrlNameStr)

参数说明:

  • parent:父窗口部件

  • id:标识符。使用-1可以自动创建一个唯一的标识

  • pos:部件的位置

  • size:部件的尺寸

  • name:对象的名字

  • style:

    • TE_CENTER 控件中的文本居中

    • TE_LEFT 控件中的文本左对齐

    • TE_NOHIDESEL 始终高亮显示

    • TE_PASSWORD 不显示说键入的文本。以*代替

    • TE_PROCESS_ENTER 如果使用了这个样式,那么当用户在控件内按下回车 键时,一个文本输入事件被触发。否则,按键事件内在的由该文本控件或该对话框管理。

    • TE_PROCESS_TAB 如果指定了这个样式,那么通常的字符事件在Tab键按下 时创建(一般意味一个制表符将被插入文本)。否则,tab由对话框来管理,通常是 控件间的切换。

    • TE_READONLY:文本控件为只读,用户不能修改其中的文本。

    • TE_RIGHT:控件中的文本右对齐。

  • value:显示在空间中的初始文本

  • validator:过滤数据

import wx


class MyFrame(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, title="创建 TextCtrl", pos=(100, 100), size=(400, 300))

        panel = wx.Panel(self)  # 创建画板
        # 创建文本和输入框
        self.title = wx.StaticText(panel, label="请输入用户名和密码:", pos=(140, 20))
        self.label_user = wx.StaticText(panel, label="用户名:", pos=(50, 50))
        self.text_user = wx.TextCtrl(panel, pos=(100, 50), size=(235, 25), style=wx.TE_LEFT)
        self.label_pwd = wx.StaticText(panel, label="密  码:", pos=(50, 90))
        self.text_pwd = wx.TextCtrl(panel, pos=(100, 90), size=(235, 25), style=wx.TE_PASSWORD)

if __name__ == '__main__':
    app = wx.App()  # 初始化应用
    frame = MyFrame(None, id=-1)  # 实例化MyFrame类,并传递参数
    frame.Show()  # 显示窗口
    app.MainLoop()
27.2.5.3 Button按钮类
wx.TextCtrl(parent, id, label, pos, size=wx.DefaultSize, style=0, validator, name="button")

参数与TextCtrl 基本相同,其中label 为显示在按钮上的文本。

import wx


class MyFrame(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, title="创建 TextCtrl", pos=(100, 100), size=(400, 300))

        panel = wx.Panel(self)  # 创建画板
        # 创建文本和输入框
        self.title = wx.StaticText(panel, label="请输入用户名和密码:", pos=(140, 20))
        self.label_user = wx.StaticText(panel, label="用户名:", pos=(50, 50))
        self.text_user = wx.TextCtrl(panel, pos=(100, 50), size=(235, 25), style=wx.TE_LEFT)
        self.label_pwd = wx.StaticText(panel, label="密  码:", pos=(50, 90))
        self.text_pwd = wx.TextCtrl(panel, pos=(100, 90), size=(235, 25), style=wx.TE_PASSWORD)

        self.button = wx.Button(panel, label="登录", pos=(105, 130))


if __name__ == '__main__':
    app = wx.App()  # 初始化应用
    frame = MyFrame(None, id=-1)  # 实例化MyFrame类,并传递参数
    frame.Show()  # 显示窗口
    app.MainLoop()

27.2.6 BoxSizer 布局

上述参数都是通过pos参数布置在画板上,有一种更智能的布局方式—sizer(尺寸器)。wxPython提供了5个sizer

sizer名称描述
BoxSizer在一条水平或垂直线上的窗口部件的布局。当尺寸改变时,控制窗口部件改动
GridSizer一个基础的网格布局
FlexGridSizer对GridSizer的升级
GridBagSizer最灵活的成员。使网格中的窗口部件可以水印放置
StaticBoxSizer标准的BoxSizer带有标题和环线
import wx


class MyFrame(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, title="用户登录", size=(400, 300))

        panel = wx.Panel(self)  # 创建画板
        # 创建文本和输入框
        self.title = wx.StaticText(panel, label="请输入用户名和密码:")
        # 添加容器,容器中空间按纵向排列
        vsizer = wx.BoxSizer(wx.VERTICAL)
        vsizer.Add(self.title, proportion=0, flag=wx.BOTTOM|wx.Top|wx.ALIGN_CENTRE, border=15)
        panel.SetSizer(vsizer)


if __name__ == '__main__':
    app = wx.App()  # 初始化应用
    frame = MyFrame(None, id=-1)  # 实例化MyFrame类,并传递参数
    frame.Show()  # 显示窗口
    app.MainLoop()

在上述代码中,设置了增加背景控件(wx.Panel),并创建了一个wx.BoxSizer,它带有一个决定它是水平还是垂直的参数(wx.HORIZONTAL或者wx.VERTICAL),默认为水平。然后使用Add()方法将控件加入sizer,最后使用面板的SetSizer()方法设定它的尺寸器。

Add()语法格式如下:

Box.Add(control,proportion,flag,border)

参数说明:

  • control:要添加的控件

  • proportion:所添加控件在定义的定位方式所代表方向上,占据的空间比例。如果有3个按钮,它们的比例值分别为0、1和2,它们都已添加到一个宽度为30的水平排列的wx.BoxSizer中,起始宽度都是10。当sizer的宽度从30变成60时,按钮1的宽度保持不变,仍然是10,按钮2的宽度约为20[10+(60-30)×1/(1+2)],按钮3的宽度约为30。

  • flag:与border结合可以指定边距宽度(可以通过|联合使用)

    • wx.LEFT:左边距。

    • wx.RIGHT:右边距。

    • wx.BOTTOM:底边距。

    • wx.TOP:上边距。

    • wx.ALL:上下左右4个边距。

    • 此外,flag参数还可以与proportion参数结合,指定控件本身的对齐(排列)方式,包括以下选项。

    • wx.ALIGN_LEFT:左边对齐。

    • wx.ALIGN_RIGHT:右边对齐。

    • wx.ALIGN_TOP:顶部对齐。

    • wx.ALIGN_BOTTOM: 底边对齐。

    • wx.ALIGN_CENTER_VERTICAL: 垂直对齐。

    • wx.ALIGN_CENTER_HORIZONTAL: 水平对齐。

    • wx.ALIGN_CENTER:居中对齐。

    • wx.EXPAND:占据sizer定位方向上所有可用空间。

  • border:控制所添加控件的边距。

27.2.7 事件处理

27.2.7.1 绑定事件
bt_confirm.Bind(wx.EVT_BUTTON,OnclickSubmit)

参数说明:

  • wx.EVT_BUTTON:时间类型为按钮类型(wx.EVT_MOTION:移动鼠标,wx.ENTER_WINDOWS、wx.LEAVE_WINDOWS:鼠标进入或离开一个窗口,wx_EVT_MOUSEWHEEL:鼠标滚轮)

  • OnclickSubmit:方法名。事件发生时执行该方法。

二十八.PyQt框架的使用

28.1 安装PyQt

地址:

https://www.qt.io/download-qt-installer-oss

阿里云盘

下载完成后,进入在线下载器的目录,打开终端执行命令:

.\qt-online-installer-windows-x64-4.8.0.exe --mirror https://mirrors.aliyun.com/qt/  

注意版本,下面是两个镜像网站可以替换

清华大学:https://mirrors.tuna.tsinghua.edu.cn/qt/
中国科学技术大学:https://mirrors.ustc.edu.cn/qtproject/

https://blog.csdn.net/qq_62888264/article/details/132645054?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522172430472116800185863745%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=172430472116800185863745&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-132645054-null-null.142^v100^pc_search_result_base5&utm_term=qt%E5%AE%89%E8%A3%85&spm=1018.2226.3001.4187

二十九.Django Web框架的使用

29.1 Django Web框架的使用

29.1.1 安装Django Web框架

1.使用pip安装

pip install https://pypi.tuna.tsinghua.edu.cn/simple django==2.0
pip install https://mirrors.aliyun.com/pypi/simple/ django==2.0

2.使用vitrualenv

3.使用Anaconda

29.1.2 创建一个Django项目

  1. 首先创建一个文件夹

  2. 在该文件夹中创建environments目录用于放置虚拟环境,然后在命令行中执行

    virtualenv D:\study\python\webprojects\environments\django2.0
  3. 激活环境

    D:\study\python\webprojects\environments\django2.0\Scripts\activate
  4. 使用“django-admin”命令创建一个项目(在需要创建项目的位置运行)

    django-admin startproject demo
  5. 使用Pycharm打开demo项目

目录结构说明

文件说明
manage.py程序执行的入口
settings.py总配置文件、可以配置App、数据库、中间件、模板等选项
urls.py默认路由配置文件
wsgi.py实现WSGI接口的文件,用于处理Web请求
db.sqlite3数据库文件,默认使用这种小型数据库
  1. 运行项目

python manage.py runserver

浏览器中输入 http://127.0.0.1:8000/ 来访问

  1. 在Pycharm命令行中执行

python manage.py migrate
python manage.py createsuperuser

用户名:admin 密码:123456

重启服务,在浏览器访问http://127.0.0.1:8000/admin

29.2 创建App

推荐使用App来完成不同模块的任务,通过执行下面的命令启用一个应用程序:

python manage.py startapp app1

目录及文件说明

文件说明
migrations执行数据库迁移生成的脚本
admin.py配置管理后台的文件
apps.py单独配置添加的每个App的文件
models.py创建数据库数据模型对象的文件
tests.py编写测试脚本的文件
views.py编写视图控制器的文件

将已经创建的App添加到settings.py中,然后将其激活,否则目录中App内文件不会生效。

29.3 数据模型(models)

29.3.1 在App中添加数据模型

在app1的models.py中添加如下代码:

from django.db import models  # 引入

class Person(models.Model):
    """
    编写Person模型类,数据模型应该继承与models.Model或其子类
    """
    # 第一个字段使用models.CharField类型,长度为30
    first_name = models.CharField(max_length=30)
    # 第二个字段使用models.CharField类型,长度为30
    last_name = models.CharField(max_length=30)

上面的类在数据库中会创建如下的表:

create table myapp_person(
	"id" serial not null primary key,
    "first_name" varchar(30) not null,
    "last_name" varchar(30) not null
);

对于一些公有的字段,可以使用如下的实现方式:

fromdjango.db import models  #引入django.db.models模块


class CreateUpdate(models.Model):  # 创建抽象数据模型, 同样要继承于models.Model
    # 创建时间, 使用models.DateTimeField
    created_at = models.DateTimeField(auto_now_add=True)
    # 修改时间, 使用models.DateTimeField
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:  # 元数据,除了字段以外的所有属性
        # 设置model为抽象类。指定该表不应该在数据库中创建
        abstract = True


class Person(CreateUpdate):  # 继承CreateUpdate基类
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)


class Order(
    CreateUpdate):  # 继承CreateUpdate基类 
    order_id = models.CharField(max_length=30, db_index=True)
    order_desc = models.CharField(max_length=120)

django.db.models提供的常见字段类型:

字段类型说明
AutoField一个id自增的字段,但创建表过程Django会自动添加一个自增的主键
BinaryField一个保存二进制源数据的字段
BooleanField一个布尔值字段,应该指明默认值,管理后台默认呈现为CheckBox形式
NullBooleanField可以为None值的布尔值字段
CharField字符串字段,必须指明max_length值
TextField文本域字段
DateField日期字段
DateTimeField时间字段
EmailField邮件字段
FileField上传文件字段
ImageField图片上传字段
IntegerField整数值字段
FloatField浮点数值字段
SlugField只保存字母、数字、下划线和连接符,用于生成URL的短标签
UUIDFielduuid
ForeignKey外检关系字段
ManyTOManyField多对多关系字段
OneToOneField一对一关系字段

29.3.2 执行数据库迁移

不使用Django默认的SQLite,切换成MySQL。在项目的settings.py中找到如下配置:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

替换为:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'demo',
        'USER':'root',
        'PASSWORD':'123456'
    }
}

创建数据库demo

安装数据库驱动:

pip install https://pypi.tuna.tsinghua.edu.cn/simple pymysql

找到D:\study\python\webprojects\environments\demo\demo__init__.py文件,在首行添加如下代码:

import pymysql

pymysql.install_as_MySQLdb()

执行以下命令,创建数据表:

python manage.py makemigrations
python manage.py migrate

Django会默认按照“APP名称+下划线+模型类名称”的形式创建数据表

注意:

如果出现RuntimeError: 'cryptography' package is required for sha256_password or caching_sha2_password auth methods

需要安装

pip install cryptography

29.3.3 Django数据API

这里所有命令将在Django的交付命令行中执行,在项目根目录下启用交互命令行,执行以下命令:

python manage.py shell

导入数据模型命令:

from app1.models import Person, Order

创建数据:

方法一:

p = Person.objects.create(first_name="huguo",last_name="zhang")

方法二:

p = Person(first_name="huguo",last_name="zhang")
p.save()

查询数据:

Person.objects.all()

查询单个数据:

Person.objects.get(first_name="huguo")

查询指定条件数据:

Person.objects.filter(first_name__exact="huguo")  # 指定first_name字段值必须为huguo
Person.objects.filter(first_name__iexact="hUguo")  # 不区分大小写查找值必须为hugo的
Person.objects.filter(id__gt=1)  # 查询所有id大于1的
Person.objects.filter(id__lt=100)  # 查询所有id小于100的

Person.objects.exclude(created_at__gt=datetime.datetime.now(tz=datetime.timezone.utc))  # 排除所有创建时间大于现在时间的
Person.objects.exclude(first_name__contains="h").order_by('id')  # 过滤出所有first_name包含h的,然后按照id排序
Person.objects.exclude(first_name__icontains="h")  # 查询所有first_name不含h的

修改查询到的数据,修改之前需要查询对应的数据

p = Person.objects.get(first_name__exact="huguo")

p.first_name="john"
p.save()

或者使用get_or_create,如果数据存在就修改,不存在就创建

返回一个元组、一个数据对象和一个布尔值,defaults参数是一个字典。当获取数据的时候,default参数里面的值不会被传入,也就是说获取的对象只存在default之外的关键字参数的值

p.is_created = Person.objects.get_or_create(
	first_name="hugo",
	defaults={"last_name":"wang"}
)

删除数据同样需要先查找到对应的数据,然后进行删除

Person.objects.get(id=1).delete()

29.3.4 管理后台

编辑app1下面的admin.py文件:

from django.contrib import admin
from app1.models import Person, Order

class PersonAdmin(admin.ModelAdmin):
    """
    创建PersonAdmin类,继承自admin.ModelAdmin
    """
    # 列表页显示的字段
    list_display = ('id', 'first_name', 'last_name', 'created_at', 'updated_at')
    # 列表页过滤器
    list_filter = ('created_at', 'updated_at')
    # 列表页搜索
    search_fields = ('first_name', 'last_name')
    # 配置只读字段,设置后不可编辑
    readonly_fields = ('created_at', 'updated_at')

# 绑定Person模型和PersonAdmin类
admin.site.register(Person, PersonAdmin)

29.3.5 路由(urls)

Django的URL路由流程如下:

  1. Django查找全局urlpatterns变量(urls.py)

  2. 按照先后顺序,对URL逐一匹配urlpatterns每个元素

  3. 找到第一个匹配时停止查找,根据匹配的结果执行对应的处理函数

  4. 如果没有找到或者出现异常,Django会进行错误处理

Django支持三种表达式格式,分别如下:

  1. 精确字符串格式,如”articles/2017/“

    一个精确URL匹配一个操作函数:最简单的形式,适合对静态URL的响应:URL字符串不以“/”揩油,但要以“/”结尾

  2. Django的转换格式:<类型:变量名>,如“articles/<int:year>/”

    Django转换后的格式是一个URL模板,匹配URL同时在其中获得一批变量作为参数,是一种常用形式,目的是通过URL进行参数获取和传递

    格式转换类型说明
    str匹配除分隔符(/)外的非空字符,默认类型<year>等价于str:year
    int匹配0和正整数
    slug匹配字母、数字、横杠、下划线组成的祖父穿,str的子集
    uuid匹配格式化的UUID
    path匹配人格非空字符串,包括路径分隔符,是全集
  3. Django支持的正则表达式格式,如“articles/(?p<year>[0-9]{4})/”

    使用正则表达式的两种形式:

    • 不提取参数:如re_path(articles/([0-9]{4}))/,表示4位数字,每一个数字都是0-9的任意数字

    • 提取参数:命名形式为(?p<name>pattern)

注意:当网站功能较多是,可以在该功能文件夹中创建一个urls.py文件,将该功能模块下的URL全部卸载该文件里,但是要在全局的urls.py中使用include方法实现URL映射分发

编写URL的三种情况如下:

  • 普通URL:re_path('^index/',view.index),re_path('^home/',view.Home.as_view())

  • 顺序传参:re_path(r'detail-(\d+)-(\d+).html/',views.detail)

  • 关键字传参:re_path(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html/',views.detail)

推荐使用关键字传参,找到根目录的配置文件夹demo下面的urls.py:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app1/', include('app1.urls'))
]

在app1下面创建一个urls.py文件,并在其中编写属于这个模块的URL规则:

from app1 import views as app1_views
from django.urls import path, include

urlpatterns = [
    path('articles/2003/', app1_views.special_case_2003),
    path('articles/<int:year>/', app1_views.year_archive),
    path('articles/<int:year>/<int:month>/', app1_views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', app1_views.article_detail),
]

如果使用正则:

from app1 import views as views
from django.urls import re_path, path

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
]

在app1中的views.py中编写:

from django.shortcuts import render

# Create your views here.
from django.http import HttpResponse


def special_case_2003(request):
    return HttpResponse("This is the special case for 2003.")

def year_archive(request, year):
    return HttpResponse("This is the year archive for %s." % year)

def month_archive(request, year, month):
    return HttpResponse("This is the month archive for %s, %s." % (year, month))
def article_detail(request, year, month, slug):
    return HttpResponse("This is the article detail for %s, %s, %s." % (year, month, slug))

启动,访问

127.0.0.1:8000/app1/articles/2003/

127.0.0.1:8000/app1/articles/2003/12/

127.0.0.1:8000/app1/articles/2003/12/my-day/

29.3.6 表单(forms)

在app1文件夹下新建一个forms.py文件,添加如下代码:

from django import forms


class PersonForm(forms.Form):
    first_name = forms.CharField(max_length=30, label='First Name')
    last_name = forms.CharField(max_length=30, label='Last Name')

表单类forms.Form有一个is_valid()方法,可以在views.py中验证提交的表单是否符合规则。

from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from app1.forms import PersonForm

def get_name(request):
    if request.method == 'POST':
        form = PersonForm(request.POST)
        if form.is_valid():
            first_name = form.cleaned_data['first_name']
            last_name = form.cleaned_data['last_name']

            return HttpResponse('Hello %s %s' % (first_name, last_name))
        else:
            return HttpResponseRedirect('/error/')
    else:
        return render(request, 'name.html', {'form': PersonForm()})

在app1下新建templates文件夹,在该文件夹下新建name.html文件

<form action="/app1/get_name/" method="post"> {% csrf_token %}
    {{ form }}
    <button type="submit">Submit</button>
</form>

{{ form }}是Django模版语法,用来获取页面返回的数据,这个数据是一个PersonForm实例,所以Django就按照规则渲染表单

添加url到app1/urls.py中

    path('get_name/', app1_views.get_name),

访问127.0.0.1:8000/app1/get_name/

29.3.7 视图(views)

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)
def person_detail(request, pk):
    try:
        p = Person.objects.get(pk=pk)
    except Person.DoesNotExist:
        raise Http404('Person Does Not Exist')
    return render(request, 'person_detail.html', {'person': p})
class PersonFormView(View):
    form_class = PersonForm
    initial = {'key': 'value'}
    template_name = "name1.html"

    def get(self, request, *args, **kwargs):
        return render(request, self.template_name, {"form": self.form_class(initial=self.initial)})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            return HttpResponse('Hello1 %s %s' % (form.cleaned_data['first_name'], form.cleaned_data['last_name']))
        return render(request, self.template_name, {"form": form})
    path('get_name1/', app1_views.PersonFormView.as_view()),

29.3.8 Django模版

在settings.py中配置

TEMPLATES = [
    {
        # 默认模板引擎
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],  # 模板文件目录
        'APP_DIRS': True,  # 默认加载模板目录下的所有模板文件
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

介绍如何使用模板

{% extends "base_generic.html" %}
{% block title %}{{ section.title }}{% endblock %}
{% block content %}
    <h1>{{ section.title }}</h1>
    {% for story in story_list %}
        <h2>
            <a href="{{ story.get_absolute_url }}">
                {{ story.headline|upper }}
            </a>
        </h2>
        <p>{{ story.tease|truncatewords:"100" }}</p>
    {% endfor %}
{% endblock %}
标签说明
{% extends "base_generic.html" %}扩展一个母模板
{% block title %}指定母模板中的一段代码块,此处为title,在母模板中定义title代码块,可以在字模版中重写该代码块,block标签必须是封闭的,要由{% endblock %}结尾
{{ section.title }}获取变量的值
{% for story in story_list %}、{% endfor %}和for循环相似,必须是封闭的

过滤器:

{{value|default:"nothing"}}:用于指定默认值

{{value|length}}:计算返回的列表或字符串长度

{{value|fiesizeformat}}:将数字转为文件大小,如13KB

{{value|truncatewords:30}}:将返回的字符串取固定长度

{{value|lower}}:将返回数据变为小写字母

三十.游戏框架

30.1 初识

30.1.1 安装

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pygame

30.1.2 Pygame常用模块

模块名功能
pygame.cdrom访问光驱
pygame.cursors加载光标
pygame.display访问显示设备
pygame.draw绘制形状、点和线
pygame.event管理事件
pygame.font使用字体
pygame.image加载和存储图片
pygame.joystick使用游戏手柄或类似的东西
pygame.key读取键盘按键
pygame.mixer声音
pygame.mouse鼠标
pygame.movie播放视频
pygame.music播放音频
pygame.overlay访问高级视频叠加
pygame.rect管理矩形区域
pygame.sndarray操作声音数据
pygame.sprite操作移动图像
pygame.surface管理图像和屏幕
pygame.surfarray管理点阵图像数据
pygame.time管理事件和帧信息
pygame.transform缩放和移动图像

使用pygame创建窗口:

# -*- coding: utf-8 -*-
import sys
import pygame

pygame.init()  # 初始化
size = width, height = 800, 600  # 窗口大小
screen = pygame.display.set_mode(size)  # 创建窗口

while True:
    # 检查事件
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
            sys.exit()
pygame.quit()  # 退出

display的常用方法:

方法名功能
pygame.display.init初始化display模块
pygame.display.quit结束display模块
pygame.display.get_init如果display模块已被初始化,则返回true
pygame.display.set_mode初始化一个准备显示的界面
pygame.display.get_surface获取当前的surface对象
pygame.display.flip更新整个待显示的surface对象到屏幕上
pygame.display.update更新部分内容显示到屏幕上。如果没有参数,则与flip方法的功能相同

加载图片,绘制窗口

# -*- coding: utf-8 -*-
import sys
import pygame

pygame.init()  # 初始化
size = width, height = 800, 600  # 窗口大小
screen = pygame.display.set_mode(size)  # 创建窗口
color = (255, 255, 255)

ball = pygame.image.load(r"D:\study\python\pythonBook\GUI\images\askme.png")
ballrect = ball.get_rect()

while True:
    # 检查事件
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
            sys.exit()

    screen.fill(color)
    screen.blit(ball, ballrect)
    pygame.display.flip()

pygame.quit()  # 退出

surface对象常用方法:

方法名功能
pygame.Suface.blit将一幅图像画到另一幅图像上
pygame.Suface.convert转换图像的像素格式
pygame.Suface.convert_alpha转换图像的像素格式,包含Apha通道的转换
pygame.Suface.fill使用颜色填充Suface
pygame.Suface.get_rect获取Suface的矩形区域

跳跃的小球完整代码:

# -*- coding: utf-8 -*-
import sys
import pygame

pygame.init()  # 初始化
size = width, height = 800, 600  # 窗口大小
screen = pygame.display.set_mode(size)  # 创建窗口
color = (255, 255, 255)

ball = pygame.image.load(r"D:\study\python\pythonBook\GUI\images\askme.png")
new_width = ball.get_width() // 3
new_height = ball.get_height() // 3
ball = pygame.transform.scale(ball, (new_width, new_height))
ballrect = ball.get_rect()

speed = [3, 3]  # 速度 x、y轴距离
clock = pygame.time.Clock()  # 创建时钟

while True:
    clock.tick(60)  # 设置每秒执行60次
    # 检查事件
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
            sys.exit()

    ballrect = ballrect.move(speed)

    if ballrect.left < 0 or ballrect.right > width:
        speed[0] = -speed[0]
    if ballrect.top < 0 or ballrect.bottom > height:
        speed[1] = -speed[1]

    screen.fill(color)
    screen.blit(ball, ballrect)
    pygame.display.flip()

pygame.quit()  # 退出

三十一.网络爬虫框架

31.1 网络爬虫的常用技术

31.1.1 Python的网络请求

31.1.1.1 urllib模块

通过urlupload()方法,指定url发送网络请求来获取数据。其子模块描述如表:

模块名称描述
urllib.request该模块定义的打开URL的方法和类,你如,身份验证、重定向、Cookie等
urllib.error主要包含异常类
urllib.parseURL解析、URL引用
urllib.robotparser用于解析robots.txt文件
import urllib.request

response = urllib.request.urlopen('http://www.baidu.com')
html = response.read()
print(html)

使用post请求:

import urllib.request

data = bytes(urllib.parse.urlencode({'word': 'hello'}), encoding='utf-8')
response = urllib.request.urlopen('https://ys.xuying.vip/', data=data)

html = response.read()
print(html)
31.1.1.2 urllib3模块
import urllib3

http = urllib3.PoolManager()

response = http.request('GET', 'https://www.baidu.com')

print(response.data)

post请求:

import urllib3

http = urllib3.PoolManager()

response = http.request('POST', 'https://ys.xuying.vip/', fields={'world': 'hello'})

print(response.data)
31.1.1.3 requests模块
import requests

response = requests.get("https://www.baidu.com")

print(response.status_code)
print(response.url)
print(response.headers)
print(response.cookies)
print(response.text)
print(response.content)

31.1.2 代理服务

import requests

proxy = {
    'http': 'http://127.0.0.1:10809',
    'https': 'https://127.0.0.1:10809'  # 设置代理地址对应的端口号
}

response = requests.get('http://www.mingrisoft.com', proxies=proxy)

print(response.content)

31.1.3 BeautifulSoup

31.1.3.1 安装
pip install bs4
pip install beautifulsoup4

pip install lxml
pip install html5lib
31.1.3.2 使用
import requests
from bs4 import BeautifulSoup

response = requests.get("https://www.baidu.com")

soup = BeautifulSoup(response.content, "lxml")
print(soup)

31.2 网络爬虫开发框架

31.2.1 Scrapy

官网:Scrapy | A Fast and Powerful Scraping and Web Crawling Framework

31.2.1.1 搭建Scrapy框架
pip install Twisted

pip install Scrapy

在命令行窗口输入“scrapy”,如果没有出现异常或报错信息,则表示安装成功:

安装pywin32模块

pip install pywin32
31.2.1.2 创建项目

在保存项目文件夹下打开命令行窗口,输入

scrapy startproject scrapyDemo

items.py:项目中定义item文件

middlewares.py:项目中middlewares文件

pipelines.py:项目中pipelines文件

settings.py:项目配置文件

31.2.1.3 创建爬虫

首先需要创建一个存放爬虫模块的文件,该文件需要放在spiders文件夹下,代码示例:

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "itcast"  # 定义爬虫的名字

    def start_requests(self):
        # 定义爬取的url
        urls = [
            'https://quotes.toscrape.com/page/1'
        ]

        # 获取所有地址
        for url in urls:
            # 发送网络请求
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        # 获取数据
        page = response.url.split("/")[-2]
        # 根据页数创建文件名
        filename = 'quotes-%s.html' % page
        # 以写入模式打开文件,如果文件不存在则创建
        with open(filename, 'wb') as f:
            # 将数据写入文件中
            f.write(response.body)
        # 打印日志
        self.log('Saved file %s' % filename)

然后在命令行输入”scrapy crawl itcast“其中itcast是爬虫名称

或者

import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings


class QuotesSpider(scrapy.Spider):
    name = "itcast"  # 定义爬虫的名字

    def start_requests(self):
        # 定义爬取的url
        urls = [
            'https://quotes.toscrape.com/page/1'
        ]

        # 获取所有地址
        for url in urls:
            # 发送网络请求
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        # 获取数据
        page = response.url.split("/")[-2]
        # 根据页数创建文件名
        filename = 'quotes-%s.html' % page
        # 以写入模式打开文件,如果文件不存在则创建
        with open(filename, 'wb') as f:
            # 将数据写入文件中
            f.write(response.body)
        # 打印日志
        self.log('Saved file %s' % filename)


if __name__ == '__main__':
    # 创建爬虫进程
    process = CrawlerProcess(get_project_settings())
    # 添加爬虫
    process.crawl("itcast")
    # 运行
    process.start()
31.2.1.4 获取数据
import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings


class QuotesSpider(scrapy.Spider):
    name = "itcast"  # 定义爬虫的名字

    def start_requests(self):
        # 定义爬取的url
        urls = [
            'https://quotes.toscrape.com/page/1'
        ]

        # 获取所有地址
        for url in urls:
            # 发送网络请求
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        for quote in response.xpath(".//*[@class='quote']"):
            text = quote.xpath('.//*[@class="text"]/text()').extract_first(),
            author = quote.xpath('.//*[@class="author"]/text()').extract_first(),
            tags = quote.xpath('.//*[@class="tags"]/a/text()').extract()
            print(dict(text=text, author=author, tags=tags))


if __name__ == '__main__':
    # 创建爬虫进程
    process = CrawlerProcess(get_project_settings())
    # 添加爬虫
    process.crawl("itcast")
    # 运行
    process.start()

翻页获取数据

import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings


class QuotesSpider(scrapy.Spider):
    name = "itcast"  # 定义爬虫的名字

    def start_requests(self):
        # 定义爬取的url
        urls = [
            'https://quotes.toscrape.com/page/1'
        ]

        # 获取所有地址
        for url in urls:
            # 发送网络请求
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        for quote in response.xpath(".//*[@class='quote']"):
            text = quote.xpath('.//*[@class="text"]/text()').extract_first(),
            author = quote.xpath('.//*[@class="author"]/text()').extract_first(),
            tags = quote.xpath('.//*[@class="tags"]/a/text()').extract()
            print(dict(text=text, author=author, tags=tags))
        for herf in response.css('li.next a::attr(href)'):
            yield response.follow(herf, callback=self.parse)


if __name__ == '__main__':
    # 创建爬虫进程
    process = CrawlerProcess(get_project_settings())
    # 添加爬虫
    process.crawl("itcast")
    # 运行
    process.start()

创建item

定义item,在items.py中添加:

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class ScrapydemoItem(scrapy.Item):
    text = scrapy.Field()

    author = scrapy.Field()

    tags = scrapy.Field()
    
    pass
import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

from scrapyDemo.items import ScrapydemoItem


class QuotesSpider(scrapy.Spider):
    name = "itcast"  # 定义爬虫的名字

    def start_requests(self):
        # 定义爬取的url
        urls = [
            'https://quotes.toscrape.com/page/1'
        ]

        # 获取所有地址
        for url in urls:
            # 发送网络请求
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        for quote in response.xpath(".//*[@class='quote']"):
            text = quote.xpath('.//*[@class="text"]/text()').extract_first(),
            author = quote.xpath('.//*[@class="author"]/text()').extract_first(),
            tags = quote.xpath('.//*[@class="tags"]/a/text()').extract()

            item = ScrapydemoItem(author=author, tags=tags, text=text)
            yield item

        for herf in response.css('li.next a::attr(href)'):
            yield response.follow(herf, callback=self.parse)


if __name__ == '__main__':
    # 创建爬虫进程
    process = CrawlerProcess(get_project_settings())
    # 添加爬虫
    process.crawl("itcast")
    # 运行
    process.start()

其他内容参考官网:https://docs.scrapy.org/en/latest

pyecharts

from file_define import FileReader, JsonFileReader, TextFileReader
from data_define import Record
from bar import SalesBar

text_file_reader = TextFileReader("D:/study/python/pythonProject/practice/basis/sales/2011年1月销售数据.txt")

json_file_reader = JsonFileReader("D:/study/python/pythonProject/practice/basis/sales/2011年2月销售数据JSON.txt")

jan_data = text_file_reader.read_file()

feb_data = text_file_reader.read_file()

# 合并
all_data: list[Record] = jan_data + feb_data

# 数据计算

data_dict = {}
for record in all_data:
    if record.date in data_dict:
        # 当前日期已经有记录
        data_dict[record.date] += record.money
    else:
        # 没有记录
        data_dict[record.date] = record.money

sales_bar = SalesBar(data_dict)
sales_bar.buildBar()
from pyecharts.charts import Bar
from pyecharts.options import *


class SalesBar(Bar):

    def __init__(self, data_dict):
        self.data_dict = data_dict

    def buildBar(self) -> Bar:
        bar = Bar()

        bar.add_xaxis(list(self.data_dict.keys()))
        bar.add_yaxis("销售额", list(self.data_dict.values()), label_opts=LabelOpts(is_show=False))

        bar.set_global_opts(
            title_opts=TitleOpts(title="每日销售额")
        )
        bar.render("每日销售额柱状图.html")
        return bar

练习-疫情统计图

import json
from pyecharts.charts import Line
from pyecharts.options import TitleOpts, LegendOpts, ToolboxOpts, VisualMapOpts, LabelOpts

f_us = open("/practice/pyecharts/epidemic/America.txt", "r", encoding="utf-8")
f_ja = open("/practice/pyecharts/epidemic/Japan.txt", "r", encoding="utf-8")
f_in = open("/practice/pyecharts/epidemic/India.txt", "r", encoding="utf-8")

us_data = f_us.read()  # 美国的全部数据
us_data = us_data.replace("jsonp_1629344292311_69436(", "")
us_data = us_data[:-2]  # 使用切片的方式

ja_data = f_ja.read()
ja_data = ja_data.replace("jsonp_1629350871167_29498(", "")
ja_data = ja_data[:-2]

in_data = f_in.read()
in_data = in_data.replace("jsonp_1629350745930_63180(", "")
in_data = in_data[:-2]

us_dict = json.loads(us_data)
ja_dict = json.loads(ja_data)
in_dict = json.loads(in_data)

us_trend = us_dict['data'][0]['trend']
ja_trend = ja_dict['data'][0]['trend']
in_trend = in_dict['data'][0]['trend']

us_x_data = us_trend['updateDate'][:314]

us_y_data = us_trend['list'][0]['data'][:314]
ja_y_data = ja_trend['list'][0]['data'][:314]
in_y_data = in_trend['list'][0]['data'][:314]

line = Line()
line.add_xaxis(us_x_data)
line.add_yaxis("美国确诊人数", us_y_data, label_opts=LabelOpts(is_show=False))
line.add_yaxis("日本确诊人数", ja_y_data, label_opts=LabelOpts(is_show=False))
line.add_yaxis("印度确诊人数", in_y_data, label_opts=LabelOpts(is_show=False))

line.set_global_opts(
    title_opts=TitleOpts(title="2020年美日印确诊人数对比图", pos_left="center", pos_bottom="1%")
)

line.render()

f_us.close()
f_ja.close()
f_in.close()

网页数据爬取

浏览器插件获取

import requests
from lxml import etree
import chardet
from beyond_time.write_file import write
from beyond_time.processing_content import processing_content

# 谷歌插件 XPath Helper

# url
url = 'https://m.ikbook8.com/book/15335057/17117310.html'
while True:
    next_chapter_link = ''
    # 伪装
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'
    }

    # 发送请求  verify为是否禁用SSL验证
    resp = requests.get(url, headers=headers, verify=True)

    detected_encoding = chardet.detect(resp.content)['encoding']
    # print(f"----------获取到的编码为: {detected_encoding}")

    # 设置编码
    resp.encoding = detected_encoding

    # print(resp.text)  # 以字符串的形式显示

    e = etree.HTML(resp.text)

    content = e.xpath('string(//div[@class="reader-main"]/div[@class="content"][2])')

    title = e.xpath('string(//div[@class="reader-main"]/h1)')

    btn = e.xpath('string(//div[@class="content"][2]/a[@class="btn btn-info"])')

    mark = e.xpath('string(//div[@class="content"][2]/a[@class="btn-addbs"])')

    # 小章节链接
    next_page_link = e.xpath('//div[@class="content"][2]/a[@class="btn btn-info"]/@href')
    # 如果有小章节链接 使用小章节链接,如果没有则使用大章节链接
    if next_page_link:
        next_page_link = next_page_link[0]
        url = next_page_link
        print(next_page_link)
    else:
        # 清空小章节链接
        next_page_link = None
        # 获取大章节链接
        next_chapter_link = e.xpath('//div[@class="section-opt m-bottom-opt"]/a[3]/@href')
        if next_chapter_link:
            next_chapter_link = next_chapter_link[0]
            url = next_chapter_link
    # print(url)

    # 内容处理
    content = processing_content(content, btn, mark)

    print(title)
    print(content)

    # 写入文件
    write(file_name="光阴之外.txt", title=title, content=content)

    # 如果大章节链接为https://m.ikbook8.com/book/15335057.html视为最后一章,结束循环
    if next_chapter_link == 'https://m.ikbook8.com/book/15335057.html':
        break
def processing_content(content, btn, mark):
    """
    内容处理
    :param content: 需要处理的内容
    :param btn: 脚标
    :param mark: 标记
    :return: 处理后的内容
    """
    junk_content = "\/阅|读|模|式|内|容|加|载|不|完|整|,退出可阅读完整内容|点|击|屏|幕|中|间可|退|出|阅-读|模|式|."

    content = content.replace(junk_content, '')

    # 处理空格
    content = content.replace('\xa0', ' ')

    # 处理标点
    if mark != '':
        content = content.replace(mark, '')

    # 如果btn不为空,则把content中与btn相同的内容删除
    if btn != '':
        content = content.replace(btn, '')

    return content
def write(file_name, content, title):
    """
    写入文件 w 覆盖 a 续写
    :param file_name: 文件名 需要加后缀
    :param title:  每章节的标题
    :param content: 内容
    :return: None
    """
    with open(file_name, 'a', encoding='utf-8') as f:
        f.write(title + '\n\n' + content + '\n\n')
        f.flush()  # 真正写入文件

实例

实例01

根据输入的年份(4位数字,如2003)计算目前的年龄。

from datetime import datetime

# 用户输入出生年份
while True:
    try:
        input_year = int(input("请输入您的出生年份(例如:2003): "))
        break
    except ValueError:
        print("输入无效,请输入一个有效的年份!")

# 获取当前年份
now = datetime.now()
year = now.year

# 计算年龄
if input_year > year:
    print("您还未出生")
print(f"您的年龄是 {year - input_year} 岁。")

实例02

使用BoxSizer布局,实现登录界面

# -*- coding:utf-8 -*-
import wx


class MyFrame(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, '用户登录', size=(400, 300))
        # 创建面板
        panel = wx.Panel(self)
        # 创建“确定”和“取消”按钮,并绑定事件
        self.bt_confirm = wx.Button(panel, label='确定')
        self.bt_cancel = wx.Button(panel, label='取消')
        # 创建文本,左对齐
        self.title = wx.StaticText(panel, label="请输入用户名和密码")
        self.label_user = wx.StaticText(panel, label="用户名:")
        self.text_user = wx.TextCtrl(panel, style=wx.TE_LEFT)
        self.label_pwd = wx.StaticText(panel, label="密  码:")
        self.text_password = wx.TextCtrl(panel, style=wx.TE_PASSWORD)
        # 添加容器,容器中控件横向排列
        hsizer_user = wx.BoxSizer(wx.HORIZONTAL)
        hsizer_user.Add(self.label_user, proportion=0, flag=wx.ALL, border=5)
        hsizer_user.Add(self.text_user, proportion=1, flag=wx.ALL, border=5)
        hsizer_pwd = wx.BoxSizer(wx.HORIZONTAL)
        hsizer_pwd.Add(self.label_pwd, proportion=0, flag=wx.ALL, border=5)
        hsizer_pwd.Add(self.text_password, proportion=1, flag=wx.ALL, border=5)
        hsizer_button = wx.BoxSizer(wx.HORIZONTAL)
        hsizer_button.Add(self.bt_confirm, proportion=0, flag=wx.ALIGN_CENTER, border=5)
        hsizer_button.Add(self.bt_cancel, proportion=0, flag=wx.ALIGN_CENTER, border=5)
        # 添加容器,容器中控件纵向排列
        vsizer_all = wx.BoxSizer(wx.VERTICAL)
        vsizer_all.Add(self.title, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=15)
        vsizer_all.Add(hsizer_user, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all.Add(hsizer_pwd, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all.Add(hsizer_button, proportion=0, flag=wx.CENTER | wx.TOP, border=15)
        panel.SetSizer(vsizer_all)

if __name__ == '__main__':
    app = wx.App()
    frame = MyFrame(None, -1)
    frame.Show()
    app.MainLoop()

实例03

根据实例02使用事件判断用户登录

# -*- coding:utf-8 -*-
import wx


class MyFrame(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, '用户登录', size=(400, 300))
        # 创建面板
        panel = wx.Panel(self)
        # 创建“确定”和“取消”按钮,并绑定事件
        self.bt_confirm = wx.Button(panel, label='确定')
        self.bt_confirm.Bind(wx.EVT_BUTTON, self.OnConfirm)
        self.bt_cancel = wx.Button(panel, label='取消')
        self.bt_cancel.Bind(wx.EVT_BUTTON, self.OnCancel)

        # 创建文本,左对齐
        self.title = wx.StaticText(panel, label="请输入用户名和密码")
        self.label_user = wx.StaticText(panel, label="用户名:")
        self.text_user = wx.TextCtrl(panel, style=wx.TE_LEFT)
        self.label_pwd = wx.StaticText(panel, label="密   码:")
        self.text_password = wx.TextCtrl(panel, style=wx.TE_PASSWORD)
        # 添加容器,容器中控件横向排列
        hsizer_user = wx.BoxSizer(wx.HORIZONTAL)
        hsizer_user.Add(self.label_user, proportion=0, flag=wx.ALL, border=5)
        hsizer_user.Add(self.text_user, proportion=1, flag=wx.ALL, border=5)
        hsizer_pwd = wx.BoxSizer(wx.HORIZONTAL)
        hsizer_pwd.Add(self.label_pwd, proportion=0, flag=wx.ALL, border=5)
        hsizer_pwd.Add(self.text_password, proportion=1, flag=wx.ALL, border=5)
        hsizer_button = wx.BoxSizer(wx.HORIZONTAL)
        hsizer_button.Add(self.bt_confirm, proportion=0, flag=wx.ALIGN_CENTER, border=5)
        hsizer_button.Add(self.bt_cancel, proportion=0, flag=wx.ALIGN_CENTER, border=5)
        # 添加容器,容器中控件纵向排列
        vsizer_all = wx.BoxSizer(wx.VERTICAL)
        vsizer_all.Add(self.title, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER, border=15)
        vsizer_all.Add(hsizer_user, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all.Add(hsizer_pwd, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45)
        vsizer_all.Add(hsizer_button, proportion=0, flag=wx.CENTER | wx.TOP, border=15)
        panel.SetSizer(vsizer_all)

    def OnConfirm(self, event):
        """
        确认按钮事件
        :param event:
        :return:
        """
        username = self.text_user.GetValue()
        password = self.text_password.GetValue()
        if username == "" or password == "":
            message = "用户名或密码不能为空"
        elif username == "admin" and password == "123456":
            message = "登录成功"
        else:
            message = "用户名或密码错误"
        wx.MessageBox(message, "提示", wx.OK | wx.ICON_INFORMATION)

    def OnCancel(self, event):
        """
        取消按钮事件
        :param event:
        :return:
        """
        self.text_user.SetValue("")
        self.text_password.SetValue("")


if __name__ == '__main__':
    app = wx.App()
    frame = MyFrame(None, -1)
    frame.Show()
    app.MainLoop()

编码规范

  • 每个import语句只导入一个模块,尽量避免一次导入多个模块。

  • 不要在行尾加";",不要用分号将两条命令放在同一行。

  • 建议每行不超过80个字符,如果超过,建议使用小括号“()”将多行内容隐式连接起来,不推荐使用反斜杠“\”进行连接。

  • 使用必要的空行可以提高代码的可读性。

  • 通常情况下,运算符两侧、函数参数之间、逗号“,”两侧建议使用空格进行分隔。

  • 避免在循环中使用+和+=运算符累加字符串。

  • 适当使用异常处理结构提高程序容错性,但不能过于依赖异常处理结构,适当的显示判断。

  • 模块名尽量短小,并且全部使用小写字母,可以使用下划线分隔。

  • 包名尽量短小,并且全部使用小写字母,不推荐使用下划线。

  • 类名采取驼峰命名规则。

  • 模块内部的类采用下划线“_”+驼峰命名法。

  • 函数、类的属性和方法的命名规则同模块类似,也是全部采用小写字母,多个字母之间用下划线“_”分隔。

  • 常量命名时全部采用大写字母,可以使用下划线。

  • 使用单下划线“_”开头的模块变量或者函数是受保护的,在使用import * from语句从模块中导入时这些变量或者函数不能被导入。

  • 使用双下划线“__”开头的实例变量或者方法时私有的。

附录

1.如果使用Python 2.x 默认使用 ASCII 编码,python文件开头需要加上:

# -*- coding: utf-8 -*-

或者

# conding=utf-8
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值