Python 学习笔记

第二章 编程基础那点事

2.6 模块

在 Python 用 import 或者 from...import 来导入相应的模块。一个模块就是一个文件,模块是保存代码的最小单位,在模块中可以声明变量、函数、属性和类等Python代码元素。

将整个模块导入,格式为: import somemodule 

从某个模块中导入某个函数,格式为: from somemodule import somefunction 

从某个模块中导入多个函数,格式为: from somemodule import firstfunc, secondfunc, thirdfunc 

从某个模块中导入全部函数,格式为: from somemodule import * 

从某个模块中导入函数并起别名,格式为: from somemodule import somefunction as sf 

第四章 运算符

4.1 算术运算符

运算符名称实例描述示例
+a + b求a与b的和3 + 2 = 5
-a - b求a与b的差3 - 2 = 1
*a * b求a与b的积3 * 2 = 6
/a / b求a除以b的商3 / 2 = 1.5
%取余a % b求a除以b的余数3 % 2 = 1
**a ** b求a的b次幂3 ** 2 = 9
//地板除法a // b求小于a与b的商的最大整数3 // 2 = 1

4.2 比较(关系)运算符

运算符名称实例描述
==等于a == ba等于b时返回True,否则返回False
!=不等于a != b与==相反
<小于a < ba小于b时返回True,否则返回False
>大于a > ba大于b时返回True,否则返回False
<=小于等于a <= ba小于等于b时返回True,否则返回False
>=大于等于a >= ba大于等于b时返回True,否则返回False

4.3 逻辑运算符

逻辑运算符

运算符名称实例描述
and逻辑与a and ba、b全为True时,计算结果为True,否则为False
or逻辑或a or ba、b全为False时,计算结果为False,否则为True
not逻辑非not aa为True时,值为False,a为False时,值为True

成员运算符

运算符实例描述
ina in list用于测试是否包含某一个元素
not ina not in list用于测试是否不包含某一个元素

身份运算符

运算符实例描述
isa is b判断两个标识符是不是引用自一个对象
is nota is not b判断两个标识符是不是引用自不同对象

4.4 位运算符

运算符名称实例描述示例
~位反~x将x的值按位取反【公式:~a=(a+1)*-1】~20 = 19
&位与x & y将x与y按位进行位与运算178 & 94 = 18
|位或x | y将x与y按位进行位或运算178 | 94 = 254
^位异或x ^ y将x与y按位进行位异或运算178 ^ 94 = 236
<<左移x << a将x左移a位,低位用0补位178 << 2 = 712
>>右移x >> a将x右移a位,高位采用符号位补位178 >> 2 = 44

4.5 赋值运算符

运算符名称实例描述
+=加赋值a += b等价于a = a + b
-=减赋值a -= b等价于a = a - b
*=乘赋值a *= b等价于a = a * b
/=除赋值a /= b等价于a = a / b
%=取余赋值a %= b等价于a = a % b
**=幂赋值a **= b等价于a = a ** b
//=地板除法赋值a //= b等价于a = a // b
&=位与赋值a &= b等价于a = a & b
|=位或赋值a |= b等价于a = a | b
^=位异或赋值a ^= b等价于a = a ^ b
<<=左移赋值a <<= b等价于a = a << b
>>=右移赋值a >>= b等价于a = a >> b

4.6 运算符的优先级

优先级运算符说明
1()小括号
2**
3位反
4+, -正负号
5*, 1, %, //乘、除、取余、地板除
6+, -加、减
7<<, >>位移
8&位与
9^位异或
10|位或
11<, <=, >, >=, <>, !=, ==比较
12not逻辑非
13and,or逻辑与、逻辑或

第五章 程序流程控制

5.1 if、if-else、if-elif-else

score = int(input("请输入一个0~100的整数:"))
if score >= 90:
    grade = 'A'
elif score >= 80:
    grade = 'B'
elif score >= 70:
    grade = 'C'
elif score >= 60:
    grade = 'D'
else:
    grade = 'F'
print("成绩等级:" + grade)

5.2 while、for

i = 0
while i * i < 10:
    i += 1
    # 添加判断,在i==3时通过break语句终止循环
    if i == 3:
        break
    print(str(i) + ' * ' + str(i) + ' = ',i * i)
# while循环体中断,不会执行else语句
else:
    print('while over!')
for item in range(10):
    if item == 3:
        break
    print(item)
# for循环体中断,不会执行else语句
else:
    print('for over!')

5.3 break、continue、return

第六章 容器类型的数据

# 列表(1ist):是一种可变序列类型,类型可不同,索引访问很方便。
my_list = ['a', 'b', 'c', 1, 2, 3, ]
# 元组(tuple):是一种不可变序列类型,常用来做数据“标签”。
my_tuple = ('a', 'b', 'c', 1, 2, 3)
# 集合(set):是一种可迭代的、无序的、不能包含重复元素的容器类型的数据,集合操作效率高。
my_set = { 'a', 'b', 'c', 1, 2, 3, }
# 字典(dict):是可迭代的、通过键(key)来访问元素的可变的容器类型的数据,键值配对像抽屉,内容检索快又准。
my_dict = { 'a': True, 'b': 'two', 'c': 3 }

6.1 序列

是一种可迭代的、元素有序的容器类型的数据。包括列表(1ist)、字符串(str)、元组(tuple)和字节序列(bytes)等。

6.1.1 序列的索引操作

# 若索引超出范围,则会发生IndexError错误
a = 'Hello'
print(a[0], a[4], a[-1], a[-5])
print(len(a))  # len()函数用于获取序列的长度
print(min(a))  # min()函数用于返回第一个元素
print(max(a))  # max()函数用于返回最后一个元素

6.1.2 加和乘操作

a = 'Hello, '
a *= 2  # *=是乘赋值运算符,相当于a = a * 2
a += 'World'  # +=是加赋值运算符,相当于a = a + 'World'

6.1.3 切片操作

语法:[start:end:step]

解释:start:开始索引,默认值为0

           end:结束索引,默认值为序列的长度(不包含结束索引)

           step:步长,默认值为1,可以为正整数,也可以为负整数

a = 'Hello'
print(a[0:])  # 省略了结束索引,默认结束索引是序列的长度,即5。所以a[0:]与a[0:5]的切片结果是一样的
print(a[0:5])
print(a[:5])  # 省略了开始索引,默认开始索引是0,所以a[:5]与a[0:5]的切片结果是一样的
print(a[:])  # 省略了开始索引和结束索引,a[:]与a[0:5]的结果是一样的
print(a[1:-1])  # 使用了负值索引
print(a[::-1])  # 步长为负值时,从右往左获取元素,所以[::-1]切片的结果是原始序列元素的倒置

6.2 元素的创建、追加、插入、替换、删除

a = [20, 10, 50, 30]
b = [1, 2, 3]
a = []  # 创建空列表
a = ['Hello', 'World', 1, 2, 3]  # 创建一个字符串和整数混合的列表
a = [10]  # 创建只有一个元素的列表
a = [10, ]  # 列表的每一个元素后面都跟着一个逗号,但经常省略这个逗号
a = list('Hello')  # 通过list(iterable)函数创建列表对象,字符串是序列对象,创建的列表对象包含5个字符

a.append(80)  # 在列表后面追加一个元素,不能同时追加多个元素
a += b  # 使用+=运算符追加多个元素
a.extend(b)  # 使用extend()方法追加多个元素
a.insert(2, 80)  # 在索引2的位置插入一个元素,新元素的索引为2
a[1] = 80  # 替换
a.remove(80)  # 找到则删除,若有多个,则只删除第一个匹配的元素

6.3 元组的创建、拆包

a = (21, 32, 43, 45)  # 创建一个有4个元素的元组,用小括号把元素括起来,或省略
a = ('Hello', 'World')  # 创建字符串元组
a = ('Hello', 'World', 1, 2, 3)  # 创建字符串和整数混合的元组
a = tuple('Hello')
a = tuple([21, 32, 43, 45])  # 通过tuple()函数创建元组
a = 1,
a = (1, )  # 创建只有一个元素的元组,元素后面的逗号不能省略
print(type(a))
a = ()  # 通过()可以创建空元组
print(type(a))
s_id, s_name = (102, '张三')  # 将元组(102, '张三')拆包到变量s_id和s_name

6.4 集合的创建、修改

a = set('Hello')
a = {20, 15, 10, 30, 20, 15}
a = {}  # 创建
print(type(a))
a = {'张三', '李四', '王五'}
a.add('董六')  # 添加元素
a.remove('李四')  # 通过remove()方法删除文件元素时,由于要删除的'李四'已经不在集合中,所以会抛出错误
print('李四' in a)  # 在集合中也可以使用成员测试运算符in和not in
a.clear()  # 清空

6.5 字典的创建、修改

a = dict({102: '张三', 105: '李四', 109: '王五', }) # 通过dict()函数创建字典,参数是另外一个字典
a = dict(((102, '张三'), (105, '李四'), (109, '王五'))) # 通过dict()函数创建字典,参数是一个元组,在这个元组中要包含三个只有两个元素的元组
a = dict([(102, '张三'), (105, '李四'), (189, '王五')]) # 通过dict()函数创建字典,参数是一个列表,在这个列表中包含三个只有两个元素的元组
a = dict(zip([102, 105, 109], ['张三', '李四', '王五'])) # 通过zip()函数将两个可迭代对象打包成元组,第1个参数是字典的键,第2个参数是字典值,它们包含的元素个数相同,并且一一对应
a = {}  # 创建空值
a = {102: '张三', 105: '李四', 109: '王五', }
print(a[109])  # 通过字典键返回对应的值
a[110] = '董六'  # 通过110键赋值,如果此时在字典中没有110键,则添加110: '董六'键值对
a[109] = '阮七'  # 将109键对应的值替换为'阮七'
a.pop(105)  # 使用字典的pop(key)方法删除键值对,返回删除的值
print(a.items())  # 返回字典的所有键值对视图dict_items
print(a.keys())  # 返回字典键视图dict_keys
print(a.values())  # 返回字典值视图dict_values
print(list(a.items()))  # dict_items可以使用list()函数返回键值对列表
print(list(a.keys()))  # dict_keys可以使用list()函数返回键列表
print(list(a.values()))  # dict_values可以使用list()函数返回值列表

第七章 字符串

字符表示

Unicode编码

说明

\t

\u0009

水平制表符

\n

\u000a

换行

\r

\u000d

回车

\"

\u0022

双引号

\'

\u0027

单引号

\\

\u005c

反斜线

7.1 普通字符串、原始字符串、长字符串

a = 'Hello'
a = "Hello"  # 普通字符串指用单引号(')或双引号(")括起来的字符串
a = '\u0048\u0065\u006c\u006c\u006f'  # 字符串中的字符采用Unicode编码表示
a = "Hello'World"  # 字符串本身包括单引号,可以使用双引号括起来,不需要转义
a = 'Hello"World'  # 字符串本身包括双引号,可以使用单引号括起来,不需要转义
a = 'Hello\n World'  # 普通字符串中的\n表示换行符
a = 'Hello\u000a World'  # 采用Unicode编码表示转义符
a = 'Hello\t World'
a = 'Hello\' World'  # 替代写法:"Hello' World"
a = 'Hello\" World'  # 替代写法:'Hello" World'
a = 'Hello\\\ World'
a = r'Hello\n World'
a = r"Hello\n World"  # 原始字符串的中\n表示\和n两个字符
# 如果要使用字符串表示一篇文章,其中包含了换行、缩进等排版字符,则可以使用长字符串表示。
# 对于长字符串,要使用三个单引号(''')或三个双引号(""")括起来。
a = '''XXXXXXXXXX'''
a = """XXXXXXXXXX"""

7.2 字符串与数字的相互转换

将字符串转换为数字:将字符串转换为数字,可以使用int()和float()实现,如果成功则返回数字,否则引发异常。

将数字转换为字符串:将数字转换为字符串,可以使用str()函数,str()函数可以将很多类型的数据都转换为字符串。

7.3 格式化字符串

使用字符串的format()方法,它不仅可以实现字符串的拼接,还可以格式化字符串。

7.3.1 使用占位符

要想将表达式的计算结果插入字符串中,则需要用到占位符({})。

s = 'i * i = ' + str(i * i)
s = 'i * i = {}'.format(i * i)  # 默认占位符
s = '{0} * {0} = {1}'.format(i, i * i)  # 参数序号占位符
s = '{p1} * {p1} = {p2}'.format(p1=i, p2 = i * i)  # 参数名占位符

7.3.2 格式化控制符

位于占位符索引或占位符名字的后面,之间用冒号分隔,且不能有空格。

语法:{ 参数序号: 格式控制符 } 或 { 参数名: 格式控制符 }。

格式控制符

说明

s

字符串

d

十进制整数

f、F

十进制浮点数

g、G

十进制整数或浮点数

e、E

科学计算法表示浮点数

o

八进制整数,符号是小英文字母o

x、X

十六进制整数,x是小写表示,X是大写表示

money = 5834.5678
name = 'Tony'
print('{0:s}年龄{1:d},工资是{2:f}元。'.format(name, 20, money))
print('{0}年龄{1},工资是{2:0.2f}元。'.format(name, 20, money))
print("{0}今天收入是{1:g}元。".format(name, money))
print("{0}今天收入是{1:e}元。".format(name, money))
print('十进制数{0:d}的八进制表示为{0:o}'.format(18))
print('十进制数{0:d}的十六进制表示为{0:x}'.format(18))

7.4 操作字符串

7.4.1 字符串查找

str.find(sub[, start[, end]])查找子字符串,在索引start到end之间查找子字符串sub,如果找到,则返回最左端位置的索引;如果没有找到,则返回-1

a = 'Hello World'
print(a.find('e'))
print(a.find('l'))
print(a.find('l', 4))  # 查找l,从第4个字符串开始找起
print(a.find('l', 4, 6))  # 查找l,从第4个开始,到第6个线束(不包含结尾)

7.4.2 字符串替换

str.replace(old, new[, count])字符串替换,用new子字符串替换old子字符串。count参数指定了替换old子字符串的个数,如果count被省略,则替换所有old子字符串。

a = 'AB CD EF GH IJ'
print(a.replace(' ', '|', 2))
print(a.replace(' ', '|'))
print(a.replace(' ', '|', 1))

7.4.3 字符串分割

str.split(sep=None, maxsplit=-1),使用sep子字符串分割字符串str。maxsplit是最大分割次数,如果maxsplit被省略,则表示不限制分割次数。

a = 'AB CD EF GH IJ'
print(a.split(' '))
print(a.split(' ', maxsplit=0))
print(a.split(' ', maxsplit=1))
print(a.split(' ', maxsplit=2))

第八章 函数

def 函数名(形式参数):  # 以英文半角冒号结尾
    函数体  # 缩进(推荐采用4个半角空格)
    return 返回值  # 如果没有数据返回,则可以省略return语句

形参由于定义函数时的参数不是实际数据,会在调用函数时传递给它们实际数据,所以我们称定义函数时的参数为形式参数,简称形参;

实参称调用函数时传递的实际数据为实际参数,简称实参。

你可以将形参理解为在函数中定义的变量。

def rect_area(width, height):  # 形参列表
    area = width * height
    return area

def print_area(width, height):
    area = width * height
    print("{0} x {1}长方形的面积:{2}".format(width, height, area))

# 使用位置参数调用函数:在调用函数时传递的实参与定义函数时的形参顺序一致,这是调用函数的基本形式。
r_area = rect_area(320, 480)  # 实参列表,顺序与形参一致
print("{0} x {1}长方形的面积:{2:.0f}".format(320, 480, r_area))
# 使用关键字参数调用函数:在调用函数时可以采用“关键字=实参”的形式,其中,关键字的名称就是定义函数时形参的名称。
r_area = rect_area(width=320, height=480)  # 关键词的名称就是定义函数时形参的名称
r_area = rect_area(height=480, width=320)  # 实参不再受形参的顺序限制

8.3 参数的默认值

def make_coffee(name="卡布奇诺"):  # 默认值
    return "制作一杯{0}咖啡。".format(name)

coffee1 = make_coffee("拿铁")  # 提供参数:制作一杯拿铁咖啡。
coffee2 = make_coffee()  # 提供参数:制作一杯卡布奇诺咖啡。

8.4 基于元组或字典的可变参数

Python中的函数可以定义接收不确定数量的参数,这种参数被称为可变参数。

可变参数有两种,即在参数前加*或**。

# *可变参数在函数中被组装成一个元组。
def sum(*numbers):  # 可变参数,多个参数被组装成元组numbers
    total = 0.0
    for number in numbers:
        total += number
    return total
print(sum(100.0, 20.0, 30.0))  # 输出150.0
print(sum(30.0, 80.0))  # 输出110.0

# **可变参数在函数中被组装成一个字典。
def show_info(**info):  # 可变参数
    print('-----show_info-----')
    for key, value in info.items():
        print('{0} - {1}'.format(key, value))
# 多个参数被组装成字典info,字典的键是name、age、sex,字典的值是'Tony'、18、True
show_info(name='tony', age=18, sex=True)
# 多个参数被组装成字典info,字典的键是student_name、student_no,字典的值是'Tony'、'1000'
show_info(student_name='tony', student_no='1000')

8.5 函数中变量的作用域

x = 20  # 全局变量

def print_value1():
    x = 10  # 函数变量
    print("函数中x = {0}".format(x))
print_value1()
print("全局变量x = {0}".format(x))

def print_value2():
    global x  # 将x变量提升为全局变量
    x = 100
    print("函数中x = {0}".format(x))
print_value2()
print("全局变量x = {0}".format(x))

8.6 函数类型

8.6.1 理解函数类型

Python中的任意一个函数都有数据类型,这种数据类型是function,被称为函数类型。

一个函数可以作为另一个函数返回值使用,也可以作为另一个函数参数使用。

# 定义加法函数:返回两个数字数据之和
def add(a, b):
    return a + b
# 定义减法函数:返回两个数字数据之差
def sub(a, b):
    return a - b
# 定义计算函数:返回function类型的数据,即另一个函数add()或sub()
def calc(opr):
    if opr == '+':
        return add
    else:
        return sub
f1 = calc('+')  # f1实际上是add()函数
f2 = calc('-')  # f1实际上是sub()函数
# f1(10, 5)是调用f1指向的add()函数,所以相当于调用add(10, 5)
print("10 + 5 = {0}".format(f1(10, 5)))
print("10 - 5 = {0}".format(f1(10, 5)))

8.6.2 过滤函数filter()

用于对容器中的元素进行过滤处理。

参数function是一个提供过滤条件的函数,返回布尔值。

参数iterable是容器类型的数据。

# 提供过滤条件的函数
def f1(x):
    return x > 50  # 找出大于50的元素
data1 = [66, 15, 91, 28, 98, 50, 7, 80, 99]
filtered = filter(f1, data1)
data2 = list(filtered)  # 转换为列表
print(data2)

8.6.3 映射函数map()

用于对容器中的元素进行映射(或变换)。

参数function是一个提供变换规则的函数,返回变换之后的元素。

参数iterable是容器类型的数据。

# 提供变换规则的函数
def f1(x):
    return x * 2  # 变换规则乘以2
data1 = [66, 15, 91, 28, 98, 50, 7, 80, 99]
mapped = map(f1, data1)
data2 = list(mapped)  # 转换为列表
print(data2)

8.7 匿名函数lambda()

使用lambda关键字定义匿名函数。lambda关键字定义的函数也被称为lambda函数。

def calc(opr):
    if opr == '+':
        return lambda a, b: (a + b) # 替代add()函数
    else:
        return lambda a, b: (a - b) # 替代sub()函数
f1 = calc('+')
f2 = calc('-')
print("10 + 5 = {0}".format(f1(10, 5)))
print("10 - 5 = {0}".format(f2(10, 5)))

8.8 使用更多的lambda()函数

# 使用lambda()函数替换f1()函数
data1 = [66, 15, 91, 28, 98, 50, 7, 80, 99]

filtered = filter(lambda x: (x > 50), data1)
data2 = list(filtered)
print(data2)

mapped = map(lambda x: (x * 2), data1)
data2 = list(mapped)
print(data2)

第九章 类与对象

9.1 面向对象

类和对象都是面向对象中的重要概念。是一种编程思想,即按照真实世界的思维方式构建软件系统。

9.4 类的成员

成员变量也被称为数据成员,保存了类或对象的数据。例如,学生的姓名和学号。

        - 实例变量:就是对象个体特有的“数据”,例如狗狗的名称和年龄等。

        - 类变量是属于类的变量,不属于单个对象。

构造方法:是一种特殊的函数,用于初始化类的成员变量。类中的__init__()方法用来创建和初始化实例变量,是一个非常特殊的方法。

成员方法:是在类中定义的函数。

        - 实例方法:实例方法与实例变量一样,都是某个实例(或对象)个体特有的方法。

        - 类方法:与类变量类似,属于类,不属于个体实例。

属性:是对类进行封装而提供的特殊方法。

class Dog:
    interest_rate = 0.0568  # 类变量
    # 构造方法,用来初始化实例变量
    # 第1个参数必须是self
    # 带有默认值的构造方法,能够给调用者提供多个不同版本的构造方法
    def __init__(self, name, age, sex='雌性'):
        self.name = name  # 创建和初始化实例变量
        self.age = age  # 创建和初始化实例变量
        self.sex = sex  # 创建和初始化实例变量
    # 实例方法:只有一个self参数
    def run(self):
        print("{}在跑...".format(self.name))
    # 实例方法:第1个参数是self,第2个参数是sound
    def speak(self, sound):
        print("{}在叫,{}...".format(self.name, sound))
    # 类方法:需要装饰器,以@开头,修饰函数、方法和类,用来约束它们
    # cls代表类自身,即Account类
    @classmethod
    def interest_by(cls, amt):
        return cls.interest_rate * amt
d1 = Dog('球球', 2)  # 创建对象调用构造方法,省略默认值
d2 = Dog('哈哈', 1, '雄性')
d3 = Dog(name='拖布', sex='雄性', age=3)  # 使用关键字参数调用构造方法
# 对实例变量通过“对象.实例变量”形式访问
print('我们家狗狗名叫{0},{1}岁了。'.format(d1.name, d1.age))
print('{0}:{1}岁{2}。'.format(d1.name, d1.age, d1.sex))
print('{0}:{1}岁{2}。'.format(d2.name, d2.age, d2.sex))
print('{0}:{1}岁{2}。'.format(d3.name, d3.age, d3.sex))
d1.run()  # 在调用时采用“对象.实例方法”形式,不需要传递参数
d1.speak('旺 旺 旺')  # 需要传递一个参数
interest = d1.interest_by(100.0)
print('狗狗平均年龄:{0:.4f}'.format(interest))

9.5 封装性

封装隐藏了对象的内部细节,只保留有限的对外接口,外部调用者不用关心对象的内部细节, 使得操作对象变得简单。

9.5.1 私有变量和私有方法

私有变量:为了防止外部调用者随意存取类的内部数据(成员变量),内部数据(成员变量) 会被封装为“私有变量”。私有变量,则在变量前加上双下画线(__)。

私有方法:与私有变量的封装是类似的,在方法前加上双下画线(__) 就是私有方法了。

class Account:
    __interest_rate = 0.0568  # 私有类变量
    def __init__(self, owner, amount):
        self.owner = owner  # 公有公有变量
        self.__amount = amount  # 私有实例变量
    # 私有方法
    def __get_info(self):
        return "{0} 金额:{1},利率:{2}。".format(self.owner, self.__amount, Account.__interest_rate)
    # 在类的内部可以访问私有变量
    def desc1(self):
        return "{0} 金额:{1},利率:{2}。".format(self.owner, self.__amount, Account.__interest_rate)
    # 在类的内部可以调用私有方法
    def desc2(self):
        print(self.__get_info())
account = Account('Tony', 800000.0)
account.desc1()
print('账户名:{0}'.format(account.owner))
print('账户金额:{0}'.format(account.amount))  # 错误发生
print('利率:{0}'.format(Account.__interest_rate))  # 错误发生
account.desc2()
account.__get_info()  # 错误发生

9.5.3 使用属性

为了实现对象的封装, 在一个类中不应该有公有的成员变量,这些成员变量应该被设计为私有的,然后通过公有的set(赋值)和get(取值)方法访问。

class Dog:
    # 构造方法
    def __init__(self, name, age, sex='雌性'):
        self.name = name  # 创建和初始化实例变量name
        self.__age = age  # 创建和初始化私有实例变量__age
    # 实例方法
    def run(self):
        print("{}在跑...".format(self.name))
    # get方法
    def get_age(self):  # 定义get()方法,返回私有实例变量__age
        return self.__age
    # set方法
    def set_age(self, age):  # 定义set()方法,通过age参数更新私有实例变量__age
        self.__age = age
dog = Dog('球球', 2)
print('狗狗年龄:{}'.format(dog.get_age()))  # 通过get()方法取值
dog.set_age(3)  # 通过set()方法赋值
print('修改后狗狗年龄:{}'.format(dog.get_age()))  # 通过get()方法取值

在上面的示例中,当外部调用者通过两个公有方法访问被封装的私有成员变量时,会比较麻烦。

class Dog:
    # 构造方法
    def __init__(self, name, age, sex='雌性'):
        self.name = name  # 创建和初始化实例变量
        # 私有变量__age,对应的属性名应该去除前面双下画线之后的名称,即age
        self.__age = age  # 创建和初始化私有实例变量
    # 实例方法
    def run(self):
        print("{}在跑...".format(self.name))
    @property
    # 定义age属性的get()方法,使用@property装饰器进行修饰,方法名就是属性名,即age
    def age(self):  # 替代get_age()
        return self.__age
    @age.setter
    # 定义age属性的set()方法,使用@age.setter装饰器进行修饰,age是属性名
    def age(self, age):  # 替代set_age()
        self.__age = age
d1 = Dog('球球', 2)
print('狗狗年龄:{0}'.format(d1.age))  # 可以通过属性取值,访问形式为“实例.属性”
d1.age = 3  # 可以通过属性赋值,访问形式为“实例.属性”
print('修改后狗狗年龄:{0}'.format(d1.age))

属性在本质上就是两个方法,在方法前加上装饰器使得方法成为属性。属性使用起来类似于公有变量,可以在赋值符(=)左边或右边,左边被赋值,右边取值。

9.6 继承性

9.6.1 Python中的继承

问:子类继承父类时,会把父类的所有成员变量和方法都能继承下来吗?

答:只有那些公有的成员变量和方法才可以被继承。

问:在子类构造方法中会调用父类构造方法,这个过程有些复杂,能解释一下吗?

答:构造方法的作用是初始化类的实例成员变量,在初始化子类时,也初始化父类的实例成员变量。

class Animal:  # 定义父类动物(Animal)
    def __init__(self, name):
        self.name = name  # 初始化父类的实例成员变量name
    def show_info(self):
        return "动物的名字:{0}".format(self.name)
    def move(self):
        print("动一动...")
class Cat(Animal):  # 定义子类猫(Cat)
    def __init__(self, name, age):
        super().__init__(name)  # 调用父类构造方法,初始化父类成品变量
        self.age = age  # 初始化子类的实例成员变量age
cat = Cat('Tom', 2)  # 在创建cat对象时,调用Cat类构造方法
cat.move()
print(cat.show_info())

9.6.2 多继承、方法重写

问:一个子类是否有多个父类?

答:从面向对象的继承性理论上讲,一个子类可以有多个父类。但是,如果在多个父类中有相同的方法,那么子类应该继承哪一个父类方法?这样会发生冲突。所以很多计算机语言都不支持多继承,而Python支持!

class Horse:
    def __init__(self, name):
        self.name = name  # 实例变量name
    def show_info(self):  # 相同方法show_info
        return "马的名字:{0}".format(self.name)
    def run(self):  # 相同方法run
        print("马跑...")
class Donkey:
    def __init__(self, name):
        self.name = name  # 实例变量name
    def show_info(self):  # 相同方法show_info
        return "驴的名字:{0}".format(self.name)
    def run(self):  # 相同方法run
        print("驴跑...")
    def roll(self):
        print("驴打滚...")
class Mule(Horse, Donkey):
    def __init__(self, name, age):
        super().__init__(name)
        self.age = age  # 实例变量age
m = Mule('骡宝莉', 1)
m.run()  # 继承父类Horse方法
m.roll()  # 继承父类Donkey方法
print(m.show_info())  # 继承父类Horse方法

9.6.3 方法重写

如果子类的方法名与父类的方法名相同,则在这种情况下,子类的方法会重写(ovenride)父类的同名方法。

# 接9.6.2的第1~20行数据
    def show_info(self):  # 重写父类方法show_info()
        return "骡:{0},{1}岁。".format(self.name, self.age)
m = Mule('骡宝莉', 1)
m.run()  # 继承父类Horse方法
m.roll()  # 继承父类Donkey方法
print(m.show_info())  # 调用子类Mule自己的方法

9.7 多态性

9.7.1 继承与多态

class Animal:
    def speak(self):
        print('动物叫,但不知道是哪种动物叫!')
class Dog(Animal):
    def speak(self):
        print('小狗:旺旺叫...')
class Cat(Animal):
    def speak(self):
        print('小猫:喵喵叫...')
an1 = Dog()
an2 = Cat()
an1.speak()
an2.speak()

9.7.2 鸭子类型测试与多态

def start(obj):  # 接收的obj对象具有speak()方法
    obj.speak()
class Animal:
    def speak(self):
        print('动物叫,但不知道是哪种动物叫!')
class Dog(Animal):
    def speak(self):
        print('小狗:旺旺叫...')
class Cat(Animal):
    def speak(self):
        print('小猫:喵喵叫...')
class Car:
    def speak(self):
        print('小汽车:嘀嘀叫...')
start(Dog())
start(Cat())
start(Car())

10.0 异常

在数学中,任何整数都不能除以0,如果在计算机程序中将整数除以0,则会引发异常。

# 自定义异常类
class ZiDingYiException(Exception):
    def __init__(self, message):
        super().__init__(message)
i = input('请输入数字:')  # input()函数从控制台获得用户输入的字符串
n = 8888
try:
    result = n / int(i)  # int()函数将字符串转换为整数
    print(result)
    print('{}除以{}等于{}'.format(n, i, result))
except (ZeroDivisionError, ValueError) as e:
    print('除数不能为0,异常:{}'.format(e))
    raise ZiDingYiException('除数不能为0.')
finally:
    print('资源释放...')

第十一章 常用的内置模块

11.1 数学计算模块 —— math

函数

说明

示例

pi

返回圆周率

pi,返回3.141592653589793

sqrt(x)

返回x的平方根

sqrt(9),返回3.0

pow(x, y)

返回x的y次幂的值

pow(5, 3),返回125.0

fabs(x)

返回x的绝对值

fabs(9),返回9.0

ceil(x)

返回x的向上取整

ceil(-6.6), ceil(6.6),返回-6, 7

floor(x)

返回x的向下取整

floor(-6.6), floor(6.6),返回-7, 6

11.2 日期时间模块 —— datetime

11.2.1 datetime类

语法:datetime.datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None)

参数

说明

取值范围

year

年,不可以省略

datetime.MINYEAR ≤ year ≤ datetime.MAXYEAR

month

月,不可以省略

1 ≤ month ≤ 12

day

日,不可以省略

1 ≤ day ≤ 给定年份和月份,这时该月的最大天数

hour

小时,可以省略

0 ≤ hour ≤ 24

minute

分钟,可以省略

0 ≤ minute ≤ 60

second

秒,可以省略

0 ≤ second ≤ 60

microsecond

微秒,可以省略

0 ≤ microsecond ≤ 1000000

tzinfo

时区

11.2.2 date类

语法:datetime.date(year, month, day)

11.2.3 time类

语法:datetime.time(hour=0, minute=0, second=0, microsecond=0, tzinfo=None)

11.2.4 计算时间跨度类 —— timedelta

语法:datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)

参数

说明

day

second

microsecond

微秒

milliseconds

毫秒

minute

分钟

hour

小时

weeks

11.2.5 将日期时间与字符串相互转换

指令

含义

示例

%y

两位年份表示

08、18

%Y

四位年份表示

2008、2018

%m

两位月份表示

01、 02、12

%d

两位表示月中的一天

01、02、03

%H

两位小时表示(24小时制)

00、01、23

%I

两位小时表示(12小时制)

01、02、12

%M

两位分钟表示

00、01、59

%S

两位秒表示

00、01、59

%f

以6位数表示微秒

000000,000001,…,999999

%p

AM或PM区域性设置

AM和PM

%z

=+HHMM或-HHMM形式的UTC偏移

+0000、-0400、+1030,如果没有设置时区,则为空

%Z

时区名称

UTC、EST、CST,如果没有设置时区,则为空

import datetime  # 导入模块datetime
# 模块名.类名
# datetime
print(datetime.datetime(2020, 2, 29))
print(datetime.datetime(2020, 2, 30))  # 指定的day参数范围,会发生ValueError异常
print(datetime.datetime(2020, 1, 29, 23, 59, 59, 10000))
print(datetime.datetime(2020, 1, 29, 23, 59, 60, 10000))  # 指定的minute参数超出范围,会发生异常
print(datetime.datetime.today())  # 返回当前的本地日期和时间
print(datetime.datetime.now(tz=None))  # 返回指定时区的当前日期和时间,参数tz用于设置时区,如果参数tz为None或省略,则等同于today()
# datetime.fromtimestamp(timestamp, tz=None)
print(datetime.datetime.fromtimestamp(999999999.999))  # 返回与UNIX时间戳对应的本地日期和时间。UNIX时间戳是从1970年1月1日00:00:00开始到现在为止的总秒数
# date
print(datetime.date(2020, 2, 29))
print(datetime.date(2020, 2, 30))  # 若指定的day参数超出范围,则会发生ValueError异常
# date.fromtimestamp(timestamp)
print(datetime.date.fromtimestamp(999999999.999))  # 返回与UNIX时间戳对应的本地日期
# time
print(datetime.time(23, 58, 59, 1999))
print(datetime.time(24, 58, 59, 1999))  # 指定的hour取值超出范围
# timedelta
d = datetime.date.today()  # 获取当前的本地日期
print(d)
delta = datetime.timedelta(weeks=1)  # 创建1周前的timedelta对象
d -= delta  # 当前日期前1周的日期
print(d)
delta = datetime.timedelta(10)  # 创建10天后的timedelta对象
d += delta  # 当前日期+10天
print(d)
# 格式化
d = datetime.datetime.today()
print(d.strftime('%Y-%m-%d'))
print(d.strftime('%Y-%m-%d %H:%M:%S'))  # 设置日期时间格式化,表示四位年、两位月、两位天、两位小时(24小时制)、两位分及两位秒
d = '2000-01-01 00:00:00'
print(datetime.datetime.strptime(d, '%Y-%m-%d %H:%M:%S'))  # 将一个字符串按照指定的格式解析为日期时间对象
print(datetime.datetime(2000, 1, 1, 00, 00, 00))

11.3 正则表达式模块 —— re

常用元字符

代码

说明

.

匹配除换行符以外的任意字符

\w

匹配字母或数字或下划线或汉字

\s

匹配任意的空白符

\d

匹配数字

\b

匹配单词的开始或结束

^

匹配字符串的开始

$

匹配字符串的结束

常用限定符

限定符

说明

举例

?

匹配前面的字符零次或一次

colou?r,该表达式可以匹配colour和color

+

匹配前面的字符一次或多次

go+gle,该表达式可以匹配的范围从gogle到goo...gle

*

匹配前面的字符零次或多次

go*gle,该表达式可以匹配的范围从ggle到goo...gle

{n}

匹配前面的字符n次

go{2}gle,该表达式只匹配google

{n,}

匹配前面的字符最少n次

go{2,}gle,该表达式可以匹配的范围从google到goo...gle

{n,m}

匹配前面的字符最少n次,最多m次

employe{0,2},该表达式可以匹配employ、employe和emmployee3种情况

常用标志

标志

说明

A 或 ASCII

对于\w、\W、\b、\B、\d、\D、\s和\S只进 ASCII 匹配(仅适用于 Python 3.x)

I 或 IGNORECASE

执行不区分字母大小写的匹配

M 或 MULTILINE

将^和$用于包括整个字符串的开始和结尾的每一行(默认情况下,仅适用于整个字符串的开始和结尾处)

S 或 DOTALL

使用(.)字符匹配所有字符,包括换行符

X 或 VERBOSE

忽略模式字符串中未转义的空格和注释

match(p,text)匹配函数:参数p是正则表达式,text是要验证的字符串。如果匹配成功,则返回一个Match对象(匹配对象),否则返回None。

search(p,text)查找函数:参数p是正则表达式,在text字符串中查找匹配的内容。如果找到,则返回第1个匹配的Match对象,否则返回None。

findall(p,text)查找函数:参数p是正则表达式,在text字符串中查找所有匹配的内容,如果找到则返回所有匹配的字符串列表,如果一个都没有匹配,则返回None。

sub(pattern, repl, string, count=0)替换函数:参数pattem是正则表达式,参数repl是用于替换的新字符串,参数string是即将被替换的旧字符串,参数count是要替换的最大数量,默认值为零,表示不限制替换数量。

split(pattern, string, maxsplit=0)分割函数:参数pattern是正则表达式,参数sting是要分割的字符串,参数maxsplit是最大分割次数,maxsplit的默认值为零,表示分割次数没有限制。

import re
p = r'\w+@abc\.com'  # 验证邮箱的正则表达式
print(re.match(p, 'you_xiang888@abc.com'))  # 返回非空的Match对象,说明匹配成功
print(re.match(p, 'you_xiang888@163.com'))  # 返回None,表示匹配失败
print(re.search(p, "Tony's email is you_xiang888@abc.com"))  # 查找成功,返回Match对象
p = r'Java|java|JAVA'  # 验证java单词的正则表达式,正则表达式中的竖线"|"字符表示“或”关系
print(re.findall(p, 'I like Java and java and JAVA.'))  # 返回匹配的字符串列表
p = r'\d+'  # 匹配数字(出现一次或多次)正则表达式
text = 'AB12CD34EF'
print(re.sub(p, ' ', text))  # sub()函数省略参数count时,表示不限制替换数量
print(re.sub(p, ' ', text, count=1))  # sub()函数指定count为1
print(re.sub(p, ' ', text, count=2))  # sub()函数指定count为2,2是最大可能的替换次数
print(re.split(p, text))  # 在split()函数中省略maxsplit参数,表示分割的次数没有限制
print(re.split(p, text, maxsplit=1))  # split()函数指定maxsplit为1,列表元素的个数是maxsplit + 1
print(re.split(p, text, maxsplit=2))  # split()函数指定maxsplit为2,2是最大可能的分割次数

第十二章 文件读写

# 打开文件,并处理异常
f = None
try:
    f = open('test.txt')  # 可能引发FileNotFoundError异常
    print('打开文件成功!')
    print(f.read())  # 可能引发OSError异常
except (FileNotFoundError, OSError) as e:
    print('读取文件失败!')
finally:
    if f is not None:  # 判断f变量是否有数据,如果文件有数据,则说明文件打开成功
        f.close()
        print('关闭文件成功!')

# with as代码块:自动释放资源(包括关闭文件的操作),可以替代finally,优化代码结构,提高其可读性
with open('test.txt') as f:
    print(f.read())

# 复制文本文件
with open('test.txt', 'r', encoding='gbk') as f:
    lines = f.readlines()
    with open('_test.txt', 'w', encoding='utf-8') as c_f:
        c_f.writelines(lines)
        print('文件复制成功!')

# 复制二进制文件
with open('test1.jpg', 'rb') as f:
    b = f.read()
    with open('test2.jpg', 'wb') as c_f:
        c_f.write(b)
        print('文件复制成功!')

12.1 打开/关闭文件

语法:open(file, mode='r', encoding=None, errors=None)

1.file参数:用于表示要打开的文件。

2.mode参数:用于设置要打开的模式。

字符串

说明

字符串

说明

r或rt

以只读模式打开文件。如果不存在则异常;如果已存在则覆盖。

rb

二进制文件,类似于rt

w或wt

以只写模式打开文件。如果不存在则创建;如果已存在则覆盖。

wb

二进制文件,类似于wt

x或xt

以独占创建模式打开文件。

xb

二进制文件,类似于xt

a或at

以追加模式打开文件。如果不存在则创建;如果已存在则追加。

ab

二进制文件,类似于at

r+

以读模式打开,可读写文件。如果不存在则异常;如果已存在则覆盖。

rb+

二进制文件,类似于r+

w+

以写模式打开,可读写文件。如果不存在则创建;如果已存在则覆盖。

wb+

二进制文件类似于w+

a+

以追加模式打开文件。如果不存在则创建;如果已存在则追加。

ab+

二进制文件,类似于a+

3.encoding参数:encoding用来指定打开文件时的文件编码,默认是UTF-8编码。

4.errors参数:errors参数用来指定在文本文件发生编码错误时如何处理。

12.3 读写文本/二进制文件

read(size=-1):从文件中读取内容,size是限制读取的字数,=-1没有限制。

readline(size=-1):在文件中读取并返回一行,size是限制读取的字数,=-1没有限制。

readlines():读取文件数据到列表中,每一行数据都是列表的一个元素。

write():将字符串或字节写入文件中,并返回写入的字符数或字节数。

writelines(lines):向文件中写入一个列表。不添加行分隔符,因此通常为每一行末尾都提供行分隔符。

flush():刷新写缓冲区,在文件没有关闭的情况下将数据写入文件中。

第十三章 图形用户界面

13.3 第一个wxPython程序

import wx
app = wx.App()  # 创建应用程序对象
# 创建窗口对象
# None:所在父窗口,None表示没有父窗口
# title:标题
# size:窗口的大小
# pos:窗口的位置
frm = wx.Frame(None, title='wxPython', size=(400, 300), pos=(100, 100))
frm.Show()  # 窗口默认隐藏,需要调用show()方法才能显示
app.MainLoop()  # 让应用程序进入主事件循环中

13.4 自定义窗口类

import wx
# 自定义窗口类
class MyFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title='wxPython', size=(400, 300), pos=(100, 100))
# 你的代码
app = wx.App()  # 创建应用程序对象
frm = MyFrame()  # 创建窗口对象
frm.Show()  # 显示窗口
app.MainLoop()  # 进入主事件循环

13.7 布局管理

13.7.1 盒子布局管理器

1、创建盒子布局管理器对象

wx.BoxSizer(wx.HORIZONTAL):设置为水平方向布局,默认值

wx.BoxSizer(wx.VERTICAL):设置为垂直方向布局

2、添加子窗口(或控件)到父窗口

Add(window, proportion=0, flag=0, border=0):添加到父窗口

Add(sizer, proportion=0, flag=0, border=0):添加到另外一个布局对象,用于布局嵌套

解释:

proportion参数:用于设置当前子窗口(或控件)在父窗口中所占的空间比例。

flag参数:是布局标志,用来控制对齐方式、边框和调整尺寸。

border参数:用于设置边框的宽度。

flag对齐标志如下表所示:

标志

说明

标志

说明

wx.ALIGN_TOP

顶对齐

wx.ALIGN_BOTTOM

底对齐

wx.ALIGN_LEFT

左对齐

wx.ALIGN_RIGHT

右对齐

wx.ALIGN_CENTER

居中对齐

wx.ALIGN_CENTRE

同wx.ALIGN_CENTER

wx.ALIGN_CENTER_VERTICAL

垂直居中对齐

wx.ALIGN_CENTRE_VERTICAL

同wx.ALIGN_CENTER_VERTICAL

wx.ALIGN_CENTER_HORIZONTAL

水平居中对齐

wx.ALIGN_CENTRE_HORIZONTAL

同wx.ALIGN_CENTER_HORIZONTAL

flag边框标志如下表所示:

标志

说明

wx.TOP

设置有顶部边框,边框的宽度需要通过Add()方法的border参数设置

wx.BOTTOM

设置有底部边框

wX.LEFT

设置有左边框

wx.RIGHT

设置有右边框

wx.ALL

设置4面全有边框

flag调整尺寸标志如下表所示:

标志

说明

wx.EXPAND

调整子窗口(或控件)完全填满有效空间

wx.SHAPED

调整子窗口(或控件)填充有效空间,但保存高宽比

wx.FIXED_MINSIZE

调整子窗口(或控件)为最小尺寸

wx.RESERVE_SPACE_EVEN_IF_HIDDEN

设置此标志后,子窗口(或控件)如果被隐藏,则所占空间保留

13.7.3 动动手 —— 盒子布局管理器嵌套示例

import wx
# 自定义窗口类
class MyFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title='wxPython', size=(400, 300), pos=(100, 100))
        # 在窗口中添加控件
        panel = wx.Panel(parent=self)
        self.statictext = wx.StaticText(parent=panel, label='Hello World!', pos=(10, 20))
        # 事件处理
        b1 = wx.Button(parent=panel, id=1, label='Button1', pos=(10, 50))
        self.Bind(wx.EVT_BUTTON, self.on_click, b1)
        b2 = wx.Button(parent=panel, id=2, label='Button2', pos=(10, 100))
        self.Bind(wx.EVT_BUTTON, self.on_click, b2)

        h_box = wx.BoxSizer(wx.HORIZONTAL)  # 创建水平方向的盒子布局管理器h_box对象
        # 添加b1, b2到h_box布局管理
        h_box.Add(b1, proportion=1, flag=wx.EXPAND | wx.ALL, border=20)
        h_box.Add(b2, proportion=1, flag=wx.EXPAND | wx.ALL, border=20)

        v_box = wx.BoxSizer(wx.VERTICAL)  # 创建重直方向的盒子布局管理器v_box对象
        v_box.Add(self.statictext, proportion=1, flag=wx.LEFT | wx.EXPAND | wx.TOP, border=20)  # 添加静态文本到v_box布局管理器
        v_box.Add(h_box, proportion=1, flag=wx.EXPAND)  # 将水平h_box布局管理器对象到重直v_box布局管理器对象

        panel.SetSizer(v_box)  # 设置面板(panel)采用v_box布局管理器

    def on_click(self, event):
        event_id = event.GetId()  # 获得绑定按钮的id
        # 根据id判断单击了哪一个按钮
        if event_id == 1:
            self.statictext.SetLabelText('我单击了“Button01”按钮!')
        elif event_id == 2:
            self.statictext.SetLabelText('我单击了“Button02”按钮!')
        print(event_id)

app = wx.App()  # 创建应用程序对象
frm = MyFrame()  # 创建窗口对象
frm.Show()  # 显示窗口
app.MainLoop()  # 进入主事件循环

13.8 控件

13.8.1 文本输入控件

import wx
# 自定义窗口类
class MyFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title='wxPython', size=(400, 300))
        panel = wx.Panel(parent=self)

        tc1 = wx.TextCtrl(panel)
        tc1.SetValue('tony')
        print('读取用户ID号:{0}.'.format(tc1.GetValue()))
        userid = wx.StaticText(panel, label='用户ID号:')

        tc2 = wx.TextCtrl(panel, style=wx.TE_PASSWORD)
        pwd = wx.StaticText(panel, label='密码:')

        tc3 = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
        content = wx.StaticText(panel, label='多行文本:')

        v_box = wx.BoxSizer(wx.VERTICAL)
        v_box.Add(userid, flag=wx.EXPAND | wx.LEFT | wx.TOP, border=10)
        v_box.Add(tc1, flag=wx.EXPAND | wx.ALL | wx.TOP, border=10)
        v_box.Add(pwd, flag=wx.EXPAND | wx.LEFT | wx.TOP, border=10)
        v_box.Add(tc2, flag=wx.EXPAND | wx.ALL | wx.TOP, border=10)
        v_box.Add(content, flag=wx.EXPAND | wx.LEFT | wx.TOP, border=10)
        v_box.Add(tc3, flag=wx.EXPAND | wx.ALL | wx.TOP, border=10)

        panel.SetSizer(v_box)

app = wx.App()  # 创建应用程序对象
frm = MyFrame()  # 创建窗口对象
frm.Show()  # 显示窗口
app.MainLoop()  # 进入主事件循环

13.8.2 单选按钮、复选框和列表

import wx
# 自定义窗口类
class MyFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title="wxPython", size=(400, 300))
        panel = wx.Panel(parent=self)

        st1 = wx.StaticText(panel, label='选择性别:')
        radio1 = wx.RadioButton(panel, id=1, label='男', style=wx.RB_GROUP)
        radio2 = wx.RadioButton(panel, id=2, label='女')
        self.Bind(wx.EVT_RADIOBUTTON, self.on_radio_click, id=1)
        self.Bind(wx.EVT_RADIOBUTTON, self.on_radio_click, id=2)

        st2 = wx.StaticText(panel, label='选择喜欢的编程语言:')
        cb1 = wx.CheckBox(panel, id=3, label='Python')
        cb2 = wx.CheckBox(panel, id=4, label='Java')
        cb3 = wx.CheckBox(panel, id=5, label='C++')
        cb3.SetValue(True)
        self.Bind(wx.EVT_CHECKBOX, self.on_checkbox_click, id=3)
        self.Bind(wx.EVT_CHECKBOX, self.on_checkbox_click, id=4)
        self.Bind(wx.EVT_CHECKBOX, self.on_checkbox_click, id=5)

        st3 = wx.StaticText(panel, label='选择你喜欢的编程语言:')
        list3 = ['Python', 'C++', 'Java']
        lb3 = wx.ListBox(panel, choices=list3, style=wx.LB_SINGLE)  # 单选列表控件
        self.Bind(wx.EVT_LISTBOX, self.on_listbox_SINGLE, lb3)

        st4 = wx.StaticText(panel, label='选择你喜欢吃的水果:')
        list4 = ['苹果', '橘子', '香蕉']
        lb4 = wx.ListBox(panel, choices=list4, style=wx.LB_EXTENDED)  # 多选列表控件,需要按住Ctrl或Shift键时选择项目
        self.Bind(wx.EVT_LISTBOX, self.on_listbox_EXTENDED, lb4)

        hbox1 = wx.BoxSizer()
        hbox1.Add(st1, flag=wx.LEFT | wx.TOP, border=15)
        hbox1.Add(radio1, flag=wx.LEFT | wx.TOP, border=15)
        hbox1.Add(radio2, flag=wx.LEFT | wx.TOP, border=15)

        hbox2 = wx.BoxSizer()
        hbox2.Add(st2, flag=wx.LEFT | wx.TOP, border=5)
        hbox2.Add(cb1, flag=wx.LEFT | wx.TOP, border=5)
        hbox2.Add(cb2, flag=wx.LEFT | wx.TOP, border=5)
        hbox2.Add(cb3, flag=wx.LEFT | wx.TOP, border=5)

        hbox3 = wx.BoxSizer()
        hbox3.Add(st3, proportion=1, flag=wx.LEFT | wx.TOP, border=5)
        hbox3.Add(lb3, proportion=1)

        hbox4 = wx.BoxSizer()
        hbox4.Add(st4, proportion=1, flag=wx.LEFT | wx.TOP, border=5)
        hbox4.Add(lb4, proportion=1)

        vbox = wx.BoxSizer(wx.VERTICAL)
        vbox.Add(hbox1, flag=wx.ALL, border=10)
        vbox.Add(hbox2, flag=wx.ALL, border=20)
        vbox.Add(hbox3, flag=wx.ALL | wx.EXPAND, border=5)
        vbox.Add(hbox4, flag=wx.ALL | wx.EXPAND, border=5)

        panel.SetSizer(vbox)  # 设置面板(panel)采用vbox布局管理器

    def on_radio_click(self, event):
        cb = event.GetEventObject()
        print('第一组{0}被选中.'.format(cb.GetLabel()))

    def on_checkbox_click(self, event):
        cb = event.GetEventObject()
        print('我选择了{0},状态{1}.'.format(cb.GetLabel(), cb.IsChecked()))

    def on_listbox_SINGLE(self, event):
        listbox = event.GetEventObject()
        print('我选择了{0}.'.format(listbox.GetSelection()))  # 返回单个选中项目的索引序号

    def on_listbox_EXTENDED(self, event):
        listbox = event.GetEventObject()
        print('我选择了{0}.'.format(listbox.GetSelections()))  # 返回多个选中项目的索引序号列表

app = wx.App()  # 创建应用程序对象
frm = MyFrame()  # 创建窗口对象
frm.Show()  # 显示窗口
app.MainLoop()  # 进入主事件循环

13.8.4 静态图片控件

问:为什么要使用self.panel.Layout()语句重新设置panel面板布局呢?

答:在图片替换后,需要重写绘制窗口,否则布局会发生混乱。

import wx

class MyFrame(wx.Frame):
    # 创建wx.Bitmap图片对象的列表
    def __init__(self):
        super().__init__(None, title='静态图片控件', size=(400, 380))
        self.panel = wx.Panel(parent=self)  # 创建一个面板,它是该类的实例变量

        self.bmps = [
            wx.Bitmap('images/001.jpg', wx.BITMAP_TYPE_JPEG),
            wx.Bitmap('images/002.jpg', wx.BITMAP_TYPE_JPEG),
            wx.Bitmap('images/003.jpg', wx.BITMAP_TYPE_JPEG),
        ]

        b1 = wx.Button(self.panel, id=1, label='Button1')
        b2 = wx.Button(self.panel, id=2, label='Button2')
        self.Bind(wx.EVT_BUTTON, self.on_click, id=1, id2=2)

        self.image = wx.StaticBitmap(self.panel, bitmap=self.bmps[0])  # 静态图片控件对象,self.bmps[0]是静态图片控件要显示的图片对象

        vbox = wx.BoxSizer(wx.VERTICAL)  # 创建垂直方向的布局管理器对象vbox
        # 添加标控件到布局管理器对象vbox
        vbox.Add(b1, proportion=1, flag=wx.EXPAND)
        vbox.Add(b2, proportion=1, flag=wx.EXPAND)
        vbox.Add(self.image, proportion=3, flag=wx.EXPAND)

        self.panel.SetSizer(vbox)

    def on_click(self, event):
        event_id = event.GetId()
        # 重新设置图片,实现图片切换
        if event_id == 1:
            self.image.SetBitmap(self.bmps[1])
        else:
            self.image.SetBitmap(self.bmps[2])
        self.panel.Layout()  # 重新设置panel面板布局

app = wx.App()  # 创建应用程序对象
frm = MyFrame()  # 创建窗口对象
frm.Show()  # 显示窗口
app.MainLoop()  # 进入主事件循环

第十四章 网络通信

14.1 requests

import requests
from requests.auth import HTTPBasicAuth
params = { 'id': : 8888 }
headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36', 'my-test': 'Hello' }
auth = HTTPBasicAuth('账号', '密码')  # 自带身份验证功能
if False:
    req = requests.get('https://httpbin.org/get', params=params, headers=headers, auth=auth)  # 发送一个get请求,并得到响应
else:
    req = requests.post('https://httpbin.org/post', params=params, headers=headers, auth=auth)  # 发送带有请求参数的post请求,并得到响应
print('--------------------\r\n{}'.format(req.url))  # url。str类型
print('--------------------\r\n{}'.format(req.text))  # 响应内容。str类型
print('--------------------\r\n{}'.format(req.content))  # 响应内容。bytes类型
print('--------------------\r\n{}'.format(req.json()))  # 响应内容。dict类型
print('--------------------\r\n{}'.format(req.headers))  # 响应头。dict类型
print('--------------------\r\n{}'.format(req.history))  # 请求历史。list类型
print('--------------------\r\n{}'.format(req.status_code))  # 响应状态码。int类型
print('--------------------\r\n{}'.format(req.cookies))  # cookies对象。RequestsCookieJar[]类型
for key, value in req.cookies.items():  # 遍历cookies
    print('--------------------\r\n{0}'.format(key + ':' + value))

14.2 搭建自己的Web服务器

1、安装JDK:https://www.oracle.com/java/technologies/downloads/#java8-windows

2、配置环境:计算机--属性--高级系统设置--高级--环境变量

      1. 配置“用户变量”:JAVA_HOME,变量值:C:\Program Files (x86)\Java\jdk-1.8\

      2. 配置“用户变量”:CLASSPATH,变量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;

      3. 配置“系统变量”:Path,变量值:;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin

3、测试是否安装成功:输入java -version,显示java版本则说明jdk安装成功

4、安装Tomcathttps://tomcat.apache.org/download-80.cgi

5、配置环境:计算机--属性--高级系统设置--高级--环境变量

      1. 配置“用户变量”:TOMCAT_HOME,变量值:C:\Program Files (x86)\Apache Software Foundation\Tomcat 8.5_Tomcat

      2. 配置“系统变量”:CATALINA_HOME,变量值:C:\Program Files (x86)\Apache Software Foundation\Tomcat 8.5_Tomcat

      3. 配置“系统变量”:Path,变量值:;%TOMCAT_HOME%\bin;%CATALINA_HOME%\lib

6、启动Tomcat服务器:切换到tomcat/bin目录下,输入startup.bat,运行如下图所示

7、测试Tomcat服务器是否安装成功:

      在浏览器中输入 http://localhost:8080 或 http://127.0.0.1:8080,安装成功,运行如下图所示

8、将tomcat作为服务启动,即关闭命令行窗口也可以访问tomcat

      进入tomcat/bin目录下,输入:service.bat install

9、问题:配置好环境变量后,点击bin目录中的startup.bat进行启动,中文显示为乱码

解决办法:

  • 进入tomcat的conf目录,打开logging.properties,将java.util.logging.ConsoleHandler.encoding的值改成GBK,然后重新启动即可。

  • 以上是解决控制台也就是黑窗口乱码,下面操作是解决启动后项目内容乱码,bin目录中找到catalina.bat文件,加上这么一句话(set JAVA_OPTS=-Dfile.encoding=UTF-8)即可。

14.3 urllib.request模块

14.3.1 发送GET请求

import urllib.request
url = 'http://localhost:8080/NoteWebService/note.do'
req = urllib.request.Request(url)
with urllib.request.urlopen(req) as response:
    data = response.read()
    json_data = data.decode()
    print(json_data)

14.3.2 发送POST请求

import urllib.request
url = 'http://localhost:8080/NoteWebService/note.do'
# 准备HTTP参数
params_dict = { 'action': 'query', 'id': '10' }  # 准备将参数放到字典中
params_str = urllib.parse.urlencode(params_dict)  # 将字典参数转换为字符串,形式为action=query$id=1
print(params_str)
# 字符串转换为字节序列对象
params_bytes = params_str.encode()  # 发送POST请求时的参数,要以字节序列形式发送
req = urllib.request.Request(url, data=params_bytes)  # 创建Request对象,其中提供了data参数,这种请求是POS请求
with urllib.request.urlopen(req) as response:
    data = response.read()
    json_data = data.decode()
    print(json_data)

14.4 JSON数据

14.4.1 JSON文档的结构

构成JSON文档的两种结构为:JSON对象(obiect)和JSON数组(array)。

在JSON对象和JSON数组中都有JSON数值,JSON数值有字符串、数字、true、false、null、对象或数组。true和false是布尔值,null表示空的对象,而且对象和数组可以嵌套。

14.4.2 JSON数据的解码

JSON数据的解码(decode)指将JSON数据转换为Python数据,当从网络中接收或从磁盘中读取JSON数据时,需要将其解码为Python数据。

在编码过程中,JSON数据被转换为Python数据。

  • JSON对象:{ "name": "a.htm", "size": 345, "saved": true, }

  • JSON数组:[ "text", "html", "css", ]

JSON数组类似于Python中的列表类型,示例如下:

JSON

Python

JSON

Python

JSON

Python

对象

字典

字符串

字符串

null

None

数组

列表

整数数字

整数

true

True

实数数字

浮点

false

False

14.5 动动手 —— 上传/下载图片示例

import urllib.request
# 上传图片
files = { 'file': open('favicon.ico', 'rb') }  # 以二进制方式读取当前目录下的favicon.ico文件,并将其赋给file
r = requests.post('http://httpbin.org/post', files=files)  # 进行上传
print(r.text)
# 下载图片
url = 'https://www.baidu.com/favicon.ico'
# 方法01
r = requests.get(url)  # 向资源url发送一个get请求
with open('favicon.ico','wb') as f:
  f.write(r.content)
# 方法02
req = urllib.request.Request(url)
with urllib.request.urlopen(req) as response:
    data = response.read()
    with open('favicon.ico', 'wb') as f:  # 以写入方式打开二进制文件
        f.write(data)  # 写入数据
        print('下载文件成功.')

14.6 动动手 —— 返回所有备忘录信息

import urllib.request
import json
url = 'http://localhost:8080/NoteWebService/note.do'
req = urllib.request.Request(url)
with urllib.request.urlopen(req) as response:
    data = response.read()
    json_data = data.decode()
    print('JSON字符串:', json_data)
    py_dict = json.loads(json_data)  # 解码json字符串,返回字典
    record_array = py_dict['Record'] # JSON数组
    for record_obj in record_array:
        print('--------------------备忘录记录--------------------')
        print('备忘录ID号:', record_obj['id'])
        print('备忘录日期:', record_obj['cDate'])
        print('备忘录内容:', record_obj['Content'])
        print('用户ID号:', record_obj['userID'])
{
    "ResultCode": 0, 
    "Record": [
        { "Id": "01" "cDate": "2018/12/01", "Content": "发布Python", "UserID": "tony-01", }, 
        { "Id": "02" "cDate": "2018/12/02", "Content": "发布Python", "UserID": "tony-02", }, 
        ......
        { "Id": "30" "cDate": "2018/12/30", "Content": "发布Python", "UserID": "tony-30", }, 
        { "Id": "31" "cDate": "2018/12/31", "Content": "发布Python", "UserID": "tony-31", }, 
    ]
}

第十五章 访问数据库

15.4 动动手 —— 数据库的CRUD操作示例

15.4.2 条件查询

import sqlite3
str = input('请输入生日(yyyyMMdd):')  # 从控制台中输入查询条件
try:
    con = sqlite3.connect('school_db.db')  # 建立数据库连接
    cursor = con.cursor()  # 创建游标对象
    sql = 'select s_id, s_name, s_sex, s_birthday from student where s_birthday < ?'  # 执行SQL查询操作
    cursor.execute(sql, [str])  # 在执行时,为占位符传递实参,实参被放到一个元组或列表中
    result_set = cursor.fetchall()  # 提取结果集
    # 遍历结果集
    for row in result_set:
        print('学号:{},姓名:{},性別:{},生日:{}.'.format(row[0], row[1], row[2], row[3]))
except sqlite3.Error as e:
    print('数据査询发生错误:{}.'.format(e))
finally:
    if cursor:
        cursor.close()  # 5.关闭游标
    if con:
        con.close()  # 6.关闭数据连接

15.4.4 插入/更新/删除数据

import sqlite3
# 从控制台输入要插入的数据
s_id = input('请输入要删除学生的【学号】:')
s_name = input('请输入【姓名】:')
s_sex = input('请输入【性别】(1表示男,0表示女):')
s_birthday = input('请输入【生日】(yyyyMMdd):')
try:
    con = sqlite3.connect('school_db.db')
    cursor = con.cursor()
    insert_sql = 'insert into student(s_name, s_sex, s_birthday) values (?, ?, ?)'  # 要插入的数据使用古位符占位
    update_sql = 'update student set s_name = ?, s_sex = ?, s_birthday = ? where s_id = ?'
    delete_sql = 'delete from student where s_id = ?'
    cursor.execute(sql, [s_id, s_name, s_sex, s_birthday])  # 替换占位符的实参
    con.commit()  # 操作成功,提交事务
    print('数据操作成功.')
except sqlite3.Error as e:
    print('数据操作失败:{}.'.format(e))
    con.rollback()  # 操作失败,回滚事务
finally:
    if cursor:
        cursor.close()
    if con:
        con.close()

第十六章 多线程

16.2 线程模块 —— threading

import threading
t = threading.current_thread()  # 返回当前的Thread对象
print(t.name)  # 当前线程名
print(threading.active_count())  # 返回当前处于活动状态的线程个数
t = threading.main_thread()  # 返回主线程对象
print(t.name)  # 主线程名

16.3 创建子线程

16.3.1 自定义函数实现线程体

import threading
import time
def thread_body():
    t = threading.current_thread()  # 当前线程对象
    for n in range(5):
        print('第{0}次执行线程{1}.'.format(n + 1, t.name))  # 当前线程名
        time.sleep(1)  # 线程休眠
    print('线程{0}执行完成!'.format(t.name))
# 主线程
t1 = threading.Thread(target=thread_body, name='MyThread1')  # 创建线程对象t1
t2 = threading.Thread(target=thread_body, name='MyThread2')  # 创建线程对象t2
t1.start()  # 启动线程t1
t2.start()  # 启动线程t2

16.3.2 自定义线程类实现线程体

import threading
import time
# 自定义线程类,继承Thread类
class SmallThread(threading.Thread):
    def __init__(self, name=None):  # 定义线程类的构造方法,name参数是线程名
        super().__init__(name=name)
    def run(self):  # 线程体函数,重写父类Thread的run()方法
        t = threading.current_thread()  # 当前线程对象
        for n in range(5):
            print('第{0}次执行线程{1}.'.format(n + 1, t.name))  # 当前线程名
            time.sleep(1)  # 线程休眠
        print('线程{0}执行完成!'.format(t.name))
# 主线程
t1 = SmallThread(name='MyThread1')  # 创建线程对象t1
t2 = SmallThread(name='MyThread2')  # 创建线程对象t2
t1.start()  # 启动线程t1
t2.start()  # 启动线程t2

16.4 线程管理

16.4.1 等待线程结束

import threading
import time
value = []  # 共享变量,多个线程都可以访问
def thread_body():  # 线程体函数
    print('t1子线程开始...')  # 当前线程对象
    for n in range(2):
        print('t1子线程执行...')
        value.append(n)  # 在子线程中修改变量value的内容
        time.sleep(2)  # 线程休眠
    print('t1子线程结束.')
print('主线程开始执行...')  # 主线程
t1 = threading.Thread(target=thread_body)  # 创建线程对象t1
t1.start()  # 启动线程t1
t1.join()  # 主线程被阻塞,等待t1线程结束
print('value = {0}.'.format(value))
print('主线程继续执行...')

16.4.2 线程停止

import threading
import time
isrunning = True  # 创建一个线程停止变量,控制线程结束
def workthread_body():  # 工作线程体函数:执行一些任务
    while isrunning:  # 工作线程体“死循环”
        print('工作线程执行中..')  # 线程开始工作
        time.sleep(5)  # 线程休眠
    print('工作线程结束.')
def controlthread_body():  # 控制线程体函数:从控制台读取指令,根据指令修改线程停止变量
    global isrunning  # 由于需要在线程体中修改变量,因此需要将变量声明为global
    while isrunning:  # 控制线程体“死循环”
        command = input('请输入停止指令:')  # 从键盘输入停止指令exit
        if command == 'exit':
            isrunning = False
        print('控制线程结束.')
# 主线程
workthread = threading.Thread(target=workthread_body)  # 创建工作线程对象:用来执行一些任务
workthread.start()  # 启动线程
controlthread = threading.Thread(target=controlthread_body)  # 创建控制线程对象:控制修改线程停止变量
controlthread.start()  # 启动线程

16.5 动动手 —— 下载图片示例

import threading
import time
import urllib.request
isrunning = True  # 线程停止变量
def workthread_body():  # 工作线程体函数
    while isrunning:
        # 线程开始工作
        print('工作线程执行下载任务...')
        download()  # 在工作线程中执行下载任务,这个下载任务每5秒调用一次
        time.sleep(5)  # 线程休眠
    print('工作线程结束.')
def controlthread_body():  # 控制线程体函数
    global isrunning
    while isrunning:
        command = input('请输入停止指令:')  # 从键盘输入停止指令exit
        if command == 'exit':
            isrunning = False
            print("控制线程结束.")
def download():  # 下载函数,由工作线程调用
    reg = urllib.request.Request('https://www.baidu.com/favicon.ico')
    with urllib.request.urlopen(reg) as response:
        data = response.read()
        with open('favicon.ico', 'wb') as f:
            f.write(data)
            print('下载文件成功.')
# 主线程
workthread = threading.Thread(target=workthread_body)  # 创建工作线程对象
workthread.start()  # 启动线程
controlthread = threading.Thread(target=controlthread_body)  # 创建控制线程对象
controlthread.start()  # 启动线程

  • 25
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值