Python学习笔记

(寒假照着一本书入门了一下Python,在文档里整理了一些基本语法,贴出来以供大家参考)

# 输出:

# 直接输出字符串或变量是这样的
print("Hello Python world!")
message = "Hello Python world!"
print(message)

# 输出带变量的字符串是这样的
print(f"message is : {message}")



# 变量:

# 变量是可以赋给值的标签(指向特定值的指针),不是盒子

# 单引号和双引号是一样的
string1 = "Hello Python world!"
string2 = 'Hello Python world!'

#可以把两个字符串直接拼起来
string3 = f"{string1} and {string2} are same."

# 数字是这样的
int_number = 12
float_number = 12.3

# 数字可以用下划线分组,不影响实际数值
number = 14_000_000_000
number = 140_00_0000_00

# 可以同时给多个变量赋值
x, y, z = 1, 2, 3



# 字符串:
name = 'bob love alice'

# 自动调整字符串中每个单词的首字母大写和大小写:
name.title()
name.upper()
name.lower()

# 换行符与制表符:
sentence1 = 'bob\nlove\nalice'
sentence2 = 'bob\tlove\talice'

# 删除字符串的头/尾/头和尾部空白(空格和换行):
word = ' lover '
word.lstrip()
word.rstrip()
word.strip()

# 下面演示了一种创建多行字符串的方式
prompt = "If you tell us who you are, we can personalize the messages you see."
prompt += "\nWhat is your first name? \n"
name = input(prompt)
print(f"Hello, {name}!")

# 可以用int函数将字符串转换成整数
age = input("How old are you?\n")
print(age)
age = int(age) + 1
print(age)

# 可以使用方法split将字符串按照某个字符分隔开来(一般是空格)
# 该方法的返回值是一个以字符串为元素的列表
string = "1 2 3 4 5"
numbers = string.split(' ')
print(numbers)

# 注释可以写成文档字符串的形式
""" 文档字符串用三引号括起,Python使用他们来生成有关程序中函数的文档 """

# 可以结合使用字符串和列表以获取字符串的某一部分
string = "abcdefghijklmnopqrstuvwxyz"
print(string[0:4])

# 可以使用方法replace将字符串中的特定单词都替换为另一个单词
# 该方法的返回值是替换后的字符串
message = "I really like dogs and dogs."
new_message = message.replace('dogs', 'cats')
print(new_message)


# 运算:

# 整数可以直接运算
2 + 3
3 - 2
2 * 3
# **是平方
3 ** 2

# 任何除法的结果都是小数,不管能否整除
3 / 2
4 / 2

# 整数可以相互取模
3 % 2
4 % 3

# 小数也可以直接运算
0.1 + 0.1
0.2 + 0.2

# 有时候小数的运算会产生多余小数位的bug
0.2 + 0.1
3 * 0.1

# 在任何运算中,如果有小数参与运算,那么结果是小数
1 + 2.0
3.0 * 2



# 列表:

# 用方括号表示列表,类似于数组
cars = ['Benz', 'BMW', 'Audi', 'Toyota']
numbers = [1, 2, 3, 123]

# 可以输出整个列表也可以只输出一个元素
print(cars)
print(numbers[3])

# 假设列表中有n个元素,那么列表的下标范围是[-n,n-1],共有两个循环
print(cars[-4].title())
print(cars[3].upper())
print(cars[0].lower())

# 可以直接通过指针修改列表中的值
cars[3] = 'Honda'

# append可以在列表末尾添加元素,也可以动态创建列表
cars.append('Porsche')

# insert可以在列表指定位置的前面添加一个元素,也就是说插入的元素就在指定位置
cars.insert(2, 'Tesla')

# del可以永久删除列表中某个特定位置的元素,并且无法访问删除的值
del cars[2]

# pop可以永久删除列表中某个特定位置的元素,并且可以访问删除的值
# 如果不指定位置则默认删除尾部元素
car1 = cars.pop()
car2 = cars.pop(0)

# remove可以根据值删除元素,只删除这个值第一次出现的位置,并且可以访问删除的值
cars.remove('Audi')
# 如果这个值不在列表里就会报错
# cars.remove('Tesla')

# sort可以对列表永久排序
# 如果不指定排序方式则默认按字典序从小到大
cars.sort()
# 也可以从大到小
cars.sort(reverse = True)

# sorted可以对列表临时排序
newlist = sorted(cars)
# 同样也可以倒序
newlist = sorted(cars, reverse = True)
print(newlist)

# reverse可以将列表元素的顺序翻转
cars.reverse()

# len可以获得列表的长度
length = len(cars)
print(length)



# for循环:

# 可以使用循环遍历列表,是直接访问指针,无需使用下标
names = ['machao', 'lixin', 'laofuzi', 'mengtian']
# 注意python的循环内部语句的标识不是靠括号而是靠缩进
# for循环的运行逻辑可能是将迭代器指向对应的列表后开始向后迭代
# 这个逻辑导致如果在for循环里修改列表可能会导致循环出现问题
# 如果迭代至for后面的条件不满足则退出循环,否则继续迭代
for name in names:
    print(name.title())
    print(name.upper())
print("They are my favorite hero.")

# 可以用range来实现一个区间内整数的遍历
# 注意这个区间是左闭右开区间
for value in range(0, 5):
    print(value)
# 可以指定步长
for value in range(0, 5, 2):
    print(value)

# 可以用range创建一个列表
numbers = list(range(0, 5))

# 可以用函数直接获得数字列表的最大值,最小值和总和
min_num = min(numbers)
max_num = max(numbers)
sum_num = sum(numbers)

# 可以用循环嵌套的方式生成列表
numbers = [value ** 2 for value in range(0, 5)]
print(numbers)

# 可以通过切片直接获取列表的一个部分,返回值同样是一个列表
names = ['machao', 'lixin', 'laofuzi', 'mengtian']
# 注意这里仍然是左开右闭区间
print(names[0:3])
# 第一个索引默认为0
print(names[:3])
# 第二个索引默认为总长度
print(names[1:])
# 可以指定步长
print(names[::2])
# 可以是负数,用法和列表下标是一样的
print(names[-3:])
# 可以用for循环遍历切片
for name in names[0:3]:
    print(name)
# 可以通过切片直接复制列表,复制得到的列表和之前的列表占用不同的空间
spare_names = names[:]
# 如果不通过切片复制,那么相当于只复制了指针,前后两个列表占用相同的空间
spare_names = names

# 可以判断某个特定值在/不在列表里
print('machao' in names)
print('machao' not in names)

# 可以判断某个列表是不是空的
names = []
if names:
    print('非空')
else:
    print('')



# 元组:

# 是列表的常量版本
constant = (0, 100)

# 修改操作是禁止的
# constant[0] = 1

# 其他的操作与列表一致



# 条件语句:

# if语句的基本格式如下(最后一部分的else可以省略)
car = 'Audi'
company = 'Volkswagen'
if (car.lower() == 'benz') and (company.lower() == 'mercedes'):
    print('梅奔')
elif (car.lower() == 'lexus') or (company.lower() == 'toyota'):
    print('雷车')
else:
    print('奥迪')



# 字典:

# 字典类似于C++中的map(由一系列键-值对组成),其基本格式如下
car = {
    'company': 'toyota',
    'name': 'corolla',
    }
print(car['company'].title())
print(car['name'].title())

# 可以直接添加键值对
car['price'] = 20_0000
print(car)

# 可以修改键值对
car['company'] = 'honda'
print(car)

# 可以使用del删除键值对(类似于列表)
del car['company']
print(car)

# 可以使用get访问键值对,并且在键不存在时避免error
message = car.get('company', 'No company value assigned.')
print(message)

# 可以使用for循环来遍历字典的所有键值对
for key, value in car.items():
    print(f"{key}: {value}")
# 也可以单独遍历字典的键/值(其中的keys和values两个函数的返回值都是一个列表)
for key in sorted(car.keys()):
    print(f"Key: {key}")
for value in car.values():
    print(f"Value: {value}")

# 列表的元素可以是字典
cars = []
for number in range(0, 4):
    car = {
        'company': 'toyota',
        'name': 'corolla',
        'price': 200_000,
    }
    cars.append(car)
print(cars)

# 字典的值的元素可以是列表
car = {
    'company': ['Mercedes', 'Benz'],
    'name': 'G63',
}
print(car)

# 字典的值的元素可以是字典
users = {
    'Arthur': {
        'first': 'Arthur',
        'last': 'Morgan',
        },
    'John': {
        'first': 'John',
        'last': 'Marston',
        },
    }
print(users)



# 集合:

# 可以调用set函数对一个列表去重
numbers = [1, 1, 2, 4]
print(set(numbers))

# 也可以直接使用花括号定义一个set(注意和字典的定义方式区分)
numbers = {1, 1, 2, 4}
print(numbers)



# 输入:

# 可以调用input函数进行输入,其中传递的参数是要向输入用户显示的提示或说明
message = input(f"Tell me sth, and I'll repeat back to you:\n")
print(message)



# while循环:

# for循环用于针对集合中的每个元素都执行一个代码块
# 而while循环则不断运行,直到指定的条件不满足为止
current_number = 1
while current_number <= 5:
    print(current_number)
    current_number += 1

# 可以使用break语句以退出循环
# 可以使用continue语句跳过当前循环
while True:
    message = input()
    if message == 'break':
        break
    elif message == 'continue':
        continue
    else:
        print(message)

# 不应在for循环中修改列表,否则将导致python难以跟踪其中的元素
# 要在遍历列表的同时对其进行修改,可使用while循环
users = ['alice', 'bob', 'carol']
confirmed_users = []
while users:
    current_user = users.pop()
    print(f"Verifying user: {current_user.title()}")
    confirmed_users.append(current_user)

# 使用while循环删除为特定值的所有列表元素
pets = ['dog', 'cat', 'goldfish', 'cat', 'rabbit', 'cat']
print(pets)
while 'cat' in pets:
    pets.remove('cat')
print(pets)

#使用用户输入来填充字典
responses = {}
polling_active = 1
while polling_active:
    name = input("\nWhat is your name? ")
    response = input("Which mountain would you like to climb someday? ")
    responses[name] = response
    repeat = input("Would you like to let another person respond?(yes/no) ")
    if repeat == 'no':
        polling_active = 0
print("\n--- Poll Results ---")
for name, response in responses.items():
    print(f"{name} would like to climb {response}.")



# 函数:

# 可以使用def语句定义函数
def greet_user():
    print("Hello!")

greet_user()

# 可以向函数传递参数
# 其中在定义处的参数叫做形参(parameter)
# 在调用处的参数叫做实参(argument)
def greet_user(user_name):
    print(f"Hello! {user_name.title()}")

greet_user('Frank')

# 实参和形参的关联方式有很多种,最简单的一种是基于实参的顺序,称为位置实参
def greet_user(user_name1, user_name2):
    print(f"Hello! {user_name1.title()} and {user_name2.title()}")

greet_user('Alice', 'Bob')

# 另外一种是关键字实参,无需考虑顺序
# 注意一个书写习惯是实参和形参的等号不要空格
greet_user(user_name2='Alice', user_name1='Bob')

# 定义函数时可以预先指定某个形参的默认值,后续不需要再次传递该参数
def greet_user(user_name1, user_name2='Bob'):
    print(f"Hello! {user_name1.title()} and {user_name2.title()}")

# 在有默认值时以下两句话是等价的
greet_user('Alice')
greet_user(user_name1='Alice')

# 可以为函数指定返回值
def get_formatted_name(first_name, last_name):
    full_name = f"{first_name} {last_name}"
    return full_name.title()

name = get_formatted_name('jimi', 'hendrix')
print(name)

# 可以让实参变成可选的
def get_formatted_name(first_name, last_name, middle_name=''):
    if middle_name:
        full_name = f"{first_name} {middle_name} {last_name}"
    else:
        full_name = f"{first_name} {last_name}"
    return full_name.title()

name = get_formatted_name('jimi', 'hendrix')
print(name)

# 函数的返回值可以是字典
def get_formatted_name(first_name, last_name, age=None):
    person = {'first': first_name, 'last': last_name}
    if age:
        person['age'] = age
    return person

person = get_formatted_name('jimi', 'hendrix', 27)
print(person)

# 可以将列表作为实参传递给函数
def greet_users(names):
    for name in names:
        message = f"Hello, {name.title()}!"
        print(message)

user_names = ['alice', 'bob', 'carol']
greet_users(user_names)

# 传递时既可以传递原本的列表,也可以传递一个副本
# 这决定了在函数中修改列表时是否会影响到原本的列表
greet_users(user_names)
greet_users(user_names[:])

# 函数可以从调用语句中收集任意数量的实参
# 下面的函数将收集到的实参封装到一个名为names的元组中
def greet_users(*names):
    print(names)

greet_users('Alice', 'Bob', 'Carol')

# 可以混合使用位置实参和任意数量实参
def greet_users(age, *names):
    print(age)
    print(names)

greet_users(18, 'Alice', 'Bob', 'Carol')

# 函数可以从调用语句中收集任意数量的关键词实参
# 下面的函数将收集到的关键字实参封装到一个名为user_info的字典中
def greet_users(age, *names, **user_info):
    user_info['age'] = age
    user_info['first_name'] = names[0].title()
    user_info['last_name'] = names[1].title()
    return user_info

user_profile = greet_users(18, 'albert', 'einstein', location='princeton', field='physics')
print(user_profile)

# 可以将函数存储在称为模块的独立文件中
# 使用import打开对应的文件
import model

user_profile = model.greet_users(18, 'albert', 'einstein', location='princeton', field='physics')
print(user_profile)

# 也可以导入模块中的特定函数
from model import greet_users

user_profile = greet_users(18, 'albert', 'einstein', location='princeton', field='physics')
print(user_profile)

# 导入函数时可以使用as给函数指定别名
from model import greet_users as gu

user_profile = gu(18, 'albert', 'einstein', location='princeton', field='physics')
print(user_profile)

# 导入模块时可以使用as给模块指定别名
import model as m

user_profile = m.greet_users(18, 'albert', 'einstein', location='princeton', field='physics')
print(user_profile)

# 可以导入模块中的所有函数
from model import *

user_profile = greet_users(18, 'albert', 'einstein', location='princeton', field='physics')
print(user_profile)



# 类:

# 面向对象编程编程是最有效的软件编写方法之一
# 在面向对象编程中,我们编写表示现实世界中的事物和情景的类,并基于这些类来创建对象
# 编写类时,我们定义一大类对象都有的通用行为
# 基于类创建对象时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性
# 根据类来创建对象称为实例化,这让我们能够使用类的实例

# 下面来编写一个表示小狗的简单类Dog,这个类让Python知道如何创建表示小狗的对象
# 编写这个类后,我们将使用它来创建表示特定小狗的实例
# 根据约定,在Python中,首字母大写的名称指的是类
# 这个类定义中没有圆括号,因为要从空白创建这个类
class Dog:

    # 类中的函数称为方法,有关函数的一切都适用于方法

    # 此处的__init__是一个特殊方法,每当我们根据Dog类创建新实例时,Python都会自动运行它
    # 务必确保该方法名称两边有且仅有两个下划线,否则它将不被视为特殊方法
    # 在这个方法的定义中,形参self必不可少,而且必须位于其他形参的前面
    # 这是因为Python调用这个方法时将会自动传入实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法
    # 每当根据Dog类创建实例时,都只需给最后两个形参提供值
    def __init__(self, name, age):
        
        """初始化属性name和age"""
        # 此处定义的两个变量都有前缀self,以self为前缀的变量可供类中的所有方法使用,可以通过类的任何实例来访问
        # self.name = name获取与形参name相关联的值,并将其赋给变量name,然后该变量被关联到当前创建的实例
        # 像这样可以通过实例访问的变量称为属性
        self.name = name
        self.age = age

        # 属性可以指定默认值
        self.color = 'brown'

    # 此处的两个方法不是特殊方法,所以名称两边不要有且仅有两个下划线
    # 它们执行时不需要额外的信息,因此它们只有一个形参self
    def sit(self):
        """模拟小狗收到命令时蹲下"""
        print(f"{self.name.title()} is now sitting.")

    def roll_over(self):
        """模拟小狗收到命令时打滚"""
        print(f"{self.name.title()} rolled over!")

    # 可以通过方法修改属性的值
    def update_age(self, new_age):
        self.age = new_age

# 下面来创建一个表示特定小狗的实例
# 这里Python使用实参'Willie'和6调用Dog类的方法__init__()创建一个表示特定小狗的实例,并使用提供的值来设置属性name和age
# 接下来,Python返回一个表示这条小狗的实例,而我们将这个实例赋值给了变量my_dog
# 在这里,命名约定很有用:通常认为首字母大写的名称(如Dog)指的是类,而小写的名称(如my_dog)是根据类创建的实例
my_dog = Dog('Willie', 6)

# 可以使用句点表示法访问属性
print(f"My dog's name is {my_dog.name}.")
print(f"My dog is {my_dog.age} years old.")

# 可以使用句点表示法调用方法
my_dog.sit()
my_dog.roll_over()

# 可以直接修改属性的值
my_dog.age = 9
print(f"My dog is {my_dog.age} years old.")

# 可以通过方法修改属性的值
my_dog.update_age(12)
print(f"My dog is {my_dog.age} years old.")

# 编写类时,并非总是要从空白开始
# 如果要编写的类是另一个现成类的特殊版本,可使用继承
# 一个类继承另一个类时,将自动获得另一个类的所有属性和方法
# 原有的类称为父类,而新类称为子类
# 子类继承了父类的所有属性和方法,同时还可以定义自己的属性和方法

# 例如,下面来模拟柯基犬,柯基犬是一种特殊的狗,因此可在前面创建的Dog类的基础上创建新类CorgiDog
# 下面创建CorgiDog类的一个简单版本,它具备Dog类的所有功能

# 创建子类时,父类必须包含在当前文件中,且位于子类前面

# 定义子类时,必须在圆括号内指定父类的名称,
class CorgiDog(Dog):
    def __init__(self, name, age):

        # 此处的super是一个特殊函数,让我们能够调用父类的方法
        super().__init__(name, age)

        # 可以添加区分子类和父类所需的新属性和新方法
        self.butt = 'soft'

    def walking(self):
        print(f"{self.name.title()}'s {self.butt} butt is moving.")

my_dog = CorgiDog('maika', 3)
print(f"{my_dog.name.title()} is {my_dog.age} years old.")
my_dog.walking()

# 此处无需声明,子类可以使用父类的所有属性和方法
my_dog.roll_over()

# 实例可以用作属性(类之间可以嵌套)
class Pets:
    def __init__(self, name, age):
        self.dog = CorgiDog(name, age)

my_pet = Pets('maika', '3')
print(f"{my_pet.dog.name.title()} is {my_pet.dog.age} years old.")

# Python允许将类存储在模块中,然后在主程序中导入所需的模块
# 下面导入模块car中的Car类
from car import Car

my_new_car = Car('audi', 'a4', 2019)
print(my_new_car.get_descriptive_name())

my_new_car.odometer_reading = 23
my_new_car.read_odometer()

# 同一个模块中可以存储多个类,同样也可以导入多个类
from car import ElectricCar,Car

my_tesla = ElectricCar('tesla', 'model s', 2019)

print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()

# 可以导入整个模块,然后使用句点表示法访问需要的类
import car

my_new_car = car.Car('audi', 'a4', 2019)
print(my_new_car.get_descriptive_name())

my_tesla = car.ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())

# 导入模块中的每个类还可以使用下面的语句
# 但是这样使用容易导致混淆,一般不使用这类语句
# from car import *

# 可以在一个模块中导入另一个模块

# 可以在导入时使用别名
from car import ElectricCar as EC

my_tesla = EC('tesla', 'model s', 2019)

print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()

# 可以使用Python标准库中的任何函数和类
from random import randint
print(randint(1, 6))

from random import choice
players = ['alice', 'bob', 'carol', 'dave']
print(f"{choice(players).title()}")

# 一些需要注意的编码风格问题:
# 类名应该采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线
# 实例名和模块名都采用小写格式,并且在单词之间加上下划线

# 对于每个类,都应该紧跟在类定义后面包含一个文档字符串
# 这种文档字符串简要地描述类的功能,并遵循编写函数的文档字符串时采用的格式约定
# 每个模块也都应包含一个文档字符串,对其中的类可用于做什么进行描述

# 可使用空行来组织代码,但不要滥用
# 在类中,可使用一个空行来分隔方法;而在模块中,可使用两个空行来分隔类

# 需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的import语句
# 再添加一个空行,然后编写导入你自己编写的模块的import语句



# 文件与异常:

# 下面演示如何读取文件,并将文件内容作为一个长字符串context存储
with open('words.txt', 'r') as file_object:
    context = file_object.read()

print(context.title())

# 可以使用绝对路径读取文件
# 代码中可以使用斜杠和反斜杠,如果使用反斜杠需要写成\\而不是\
with open('C:/Users/yin_s/Desktop/Code/python/words.txt', 'r') as file_object:
    context = file_object.read()

print(context.title())

# 可以逐行读取文件中的内容
with open('words.txt', 'r') as file_object:
    for line in file_object:
        print(line.rstrip().title())

# 可以创建一个包含文件各行内容的列表
with open('words.txt', 'r') as file_object:
    lines = file_object.readlines()

print(lines)

# 下面演示如何将程序的输出写入文件(文件原本的内容会被完全覆盖掉)
with open('out.txt', 'w') as file_object:
    file_object.write("I love programming.")

# 写入多行时需要注意write函数不会在文件的末尾添加换行符(不同于print)
with open('out.txt', 'w') as file_object:
    file_object.write("I love programming.\n")
    file_object.write("I love creating new games.\n")

# 如果要给文件添加内容(而不是覆盖原有的内容),可以以附加模式'a'打开文件
with open('out.txt', 'a') as file_object:
    file_object.write('I also love finding meaning in large datasets.\n')

# Python使用称为异常的特殊对象来管理程序执行期间发生的错误
# 每当发生让Python不知所措的错误时,它都会创建一个异常对象
# 如果你编写了处理该异常的代码,程序将继续运行
# 如果未对异常进行处理,程序将停止并显示traceback,其中包含有关异常的报告

# 异常是使用trace-except-else代码块处理的,下面演示如何用它处理除0错
a = 5
b = 0
try:
    ans = int(a) / int(b)
except ZeroDivisionError:
    # Python有一个pass语句可以执行“什么都不做”的操作
    pass
else:
    print(ans)



# json模块的使用:

# 模块json能让我们将结构简单的python数据转储到文件中,并在程序再次运行时加载该文件中的数据
# 还可以使用json在python程序之间分享数据
# 更重要的是,JSON数据格式并非Python专用的,这让我们能够将以JSON格式存储的数据与使用其他编程语言的人分享
# 注意:JSON格式最初是为JavaScript开发的,但随后成了一种常见格式,被包括Python在内的众多语言采用

# 下面演示如何使用json.dump来存储数字列表
import json

numbers = [2, 3, 5, 7, 11, 13]

with open('numbers.json', 'w') as f:
    json.dump(numbers, f)

# 下面演示如何使用json.load将列表读取到内存中
with open('numbers.json', 'r') as f:
    numbers = json.load(f)

print(numbers)



# 测试:

# 编写函数或类时,还可为其编写测试
# 通过测试,即可确定代码面对各种输入都能够按要求的那样工作

# Python标准库中的模块unittest提供了代码测试工具
# 单元测试用于核实函数的某个方面没有问题
# 测试用例是一组单元测试,它们一道核实函数在各种情形下的行为都符合要求
# 全覆盖的测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式

# 下面演示如何检查函数get_formatted_name在给定名和姓时能否正确工作
import unittest
from test import get_formatted_name

class NamesTestCase(unittest.TestCase):
    """测试test.py"""
    def test_first_last_name(self):
        formatted_name = get_formatted_name('janis', 'joplin')
        # 此处使用断言方法核实得到的结果是否与期望的结果一致
        self.assertEqual(formatted_name, 'Janis Joplin')
    
    def test_first_middle_last_name(self):
        formatted_name = get_formatted_name('wolfgang', 'mozart', 'amadeus')
        self.assertEqual(formatted_name, 'Wolfgang Amadeus Mozart')

# 很多测试框架都会先导入测试文件再运行
# 导入文件时,解释器将在导入的同时执行它
# 此处的if代码块检查特殊变量__name__,这个变量是在程序执行时设置的
# 如果这个文件作为主程序执行,变量__name__将被设置为'__main__',此时需要调用unittest.main()来运行测试用例
# 如果这个文件被测试框架导入,变量__name__的值将不是'__main__',因此不会调用unittest.main()
if __name__ == '__main__':
    unittest.main()

# 下面来演示如何编写针对类的测试
import unittest
from anonymoussurvey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    """针对AnonymousSurvey类的测试"""
    def test_store_single_response(self):
        """测试单个答案会被妥善地存储"""
        question = "What language did you first learn to speak?"
        my_survey = AnonymousSurvey(question)
        my_survey.store_response('English')
        self.assertIn('English', my_survey.responses)

    """针对AnonymousSurvey类的测试"""
    def test_store_three_response(self):
        """测试三个答案会被妥善地存储"""
        question = "What language did you first learn to speak?"
        my_survey = AnonymousSurvey(question)
        responses = ['English', 'Spanish', 'Mandarin']
        for response in responses:
            my_survey.store_response(response)
        
        for response in responses:
            self.assertIn(response, my_survey.responses)

if __name__ == '__main__':
    unittest.main()

# 在前面的测试中,我们在每个测试方法中都创建了一个AnonymousSurvey实例,并在每个方法中都创建了答案
# unittest.TestCase类包含的方法setUp()让我们只需创建这些对象一次,就能在每个测试方法中使用
# 如果在TestCase类中包含了方法setUp(),Python将先运行它,再运行各个以test_打头的方法

# 下面演示如何使用setUp()来创建一个调查对象和一组答案
import unittest
from anonymoussurvey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    """针对AnonymousSurvey类的测试"""

    def setUp(self):
        """创建一个调查对象和一组答案,供使用的测试方法使用"""
        question = "What language did you first learn to speak?"
        self.my_survey = AnonymousSurvey(question)
        self.responses = ['English', 'Spanish', 'Mandarin']
    
    def test_store_single_response(self):
        """测试单个答案会被妥善地存储"""
        self.my_survey.store_response(self.responses[0])
        self.assertIn(self.responses[0], self.my_survey.responses)

    """针对AnonymousSurvey类的测试"""
    def test_store_three_response(self):
        """测试三个答案会被妥善地存储"""
        for response in self.responses:
            self.my_survey.store_response(response)
        for response in self.responses:
            self.assertIn(response, self.my_survey.responses)

if __name__ == '__main__':
    unittest.main()

 

posted @ 2023-02-24 20:51  Fugtemypt  阅读(26)  评论(0编辑  收藏  举报