第二章 编程基础那点事
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 == b | a等于b时返回True,否则返回False |
!= | 不等于 | a != b | 与==相反 |
< | 小于 | a < b | a小于b时返回True,否则返回False |
> | 大于 | a > b | a大于b时返回True,否则返回False |
<= | 小于等于 | a <= b | a小于等于b时返回True,否则返回False |
>= | 大于等于 | a >= b | a大于等于b时返回True,否则返回False |
4.3 逻辑运算符
逻辑运算符
运算符 | 名称 | 实例 | 描述 |
and | 逻辑与 | a and b | a、b全为True时,计算结果为True,否则为False |
or | 逻辑或 | a or b | a、b全为False时,计算结果为False,否则为True |
not | 逻辑非 | not a | a为True时,值为False,a为False时,值为True |
成员运算符
运算符 | 实例 | 描述 |
in | a in list | 用于测试是否包含某一个元素 |
not in | a not in list | 用于测试是否不包含某一个元素 |
身份运算符
运算符 | 实例 | 描述 |
is | a is b | 判断两个标识符是不是引用自一个对象 |
is not | a 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 | <, <=, >, >=, <>, !=, == | 比较 |
12 | not | 逻辑非 |
13 | and,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, '[email protected]')) # 返回非空的Match对象,说明匹配成功
print(re.match(p, '[email protected]')) # 返回None,表示匹配失败
print(re.search(p, "Tony's email is [email protected]")) # 查找成功,返回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、安装Tomcat:https://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() # 启动线程
标签:name,format,Python,self,笔记,学习,print,def,wx
From: https://blog.csdn.net/wuguanfeng888/article/details/139647921