python编程:从入门到实践--基础知识笔记

字符串:

title() 将每个单词的首字母都改为大写。

upper() 将每个字母都改为大写。

lower() 将每个字母都改为小写。

删除空白:rstrip() 删除字符串末尾空白

lstrip() 删除字符串开头空白

strip() 同时删除字符串两边的空白

列表:

在列表中添加元素:append()、extend()

在列表中插入元素:insert()

在列表中删除元素:

             1、使用 del 语句删除元素

             list1 = [1,2,3,4]

             del list1[2]        # 删除3

             2、使用pop方法删除列表末尾的元素

             list1 = [1,2,3,4]

             list1.pop()         # 删除最后一个元素4

             3、弹出列表中任何位置处的元素,在pop括号内指定要删除元素的索引

             list1 = [1,2,3,4]

             list1.pop(2)         # 删除元素3

             4、根据值删除元素,remove()

             list1 = [1,2,3,4]

             list1.remove('2')         # 删除元素2

             注意:使用 remove() 方法只删除第一个指定的值,如果要删除的值可能在列表中出             现多次,就需要使用循环来判断是否删除了所有这样的值。

列表排序:

             1、使用sort()方法对列表进行永久性排序

             list1 = [1,2,3,4]

             list1.sort()

             还可以按与字母相反的顺序排列列表元素

             list1.sort(reverse=True)

             2、使用sorted()对列表进行临时排序

             sorted(list1)

             3、倒着打印列表,方法reverse()永久性的修改列表元素的排列顺序。

             list1.reverse()

遍历整个列表:

             for i in list1:    print(i)

             squares = [value**2 for value in range(1,11)]

复制列表:

             list2 = listt1[:]

代码格式:建议每行不超过79个字符

协作编写程序时,大多数编辑器中都可设置一个视觉标志--通常是一条竖线。

if语句:

             if-elif-else结构,有一个测试满足条件后,就会跳过余下的测试。

             if  if  if 就可以测试多个条件。

             如果只想执行一个代码块,就是用 if-elif-else 结构,如果要运行多个代码块,就使            用一系列独立的if语句。

 字典:

            字典是一系列键-值对。每个键都与一个值相关联,可以使用键来访问与之相关联的    值。与键相关联的值可以是数字、字符串、列表乃至字典。事实上,可将任何python对象用作字典中的值。

            注意,键-值对的排列顺序与添加顺序不同,python不关心键-值对的添加顺序,只关  心键和值之间的关联关系。

删除键值对:

            alien={'color':'green','point':5}

            del alien['point']

            将键'point'从字典alien中删除,同时删除与这个键相关联的值。其他键值对不受影响

遍历键值对:

            dict = {'name':'John','age':18}

            for key,value in dict.items():

                        print(key,value)

            注意,即便遍历字典时,键值对的返回顺序也与存储顺序不同。

遍历字典中所有键: dict.keys(),返回一个列表,其中包含字典中所有键。

            按顺序遍历字典中所有键:for i in sorted(dict.keys())

遍历字典中所有值: dict.values(),返回一个列表,其中包含字典中所有值。这个方法没有考            虑重复,可以使用set(集合)剔除重复元素。

嵌套:

            在列表中嵌套字典

                        alien_0 = {'color','green','point':'5'}

                        alien_1 = {'color','yellow','point':'10'}

                        alien_2 = {'color','red','point':'2'}

                        alien = [alien_0,alien_1,alien_2]

            在字典中嵌套列表

                        dict2 = {'name':'Jerry','hobby': [basketball,dance] }

            在字典中嵌套字典           

 用户输入input():

            程序等待用户输入,并在用户按回车键后继续运行。

            提示超过一行的话:可先将提示存储在一个变量中,再将该变量传递给函数input()

            prompt = 'hello'

            promt += '\nwhat is your name'

            name = input(prompt)

 while循环:

            使用标志:在要求很多条件都满足才继续运行的程序中,可定义一个变量,用于判断整个程序是否处于活动状态。这个变量称为标志,充当了程序的交通信号灯。这样,在while语句中就只需检查一个条件---标志的当前值是否为true,并将所有测试都放在其他地方,从而让程序变得更加整洁。

            break不再运行循环中余下的代码直接退出循环。

            continue返回到循环开头,并根据条件测试结果决定是否继续执行循环。

while循环来处理列表:

            在列表之间移动元素:

unconfirmed_users = ['alice','brain','candance']
confirmed_users = []

while unconfirmed_users:
    current_user = unconfirmed_users.pop()
    confirmed_users.append(current_user)
print('unconfirmed_users:',unconfirmed_users)
print('confirmed_users:',confirmed_users)

            删除包含特定值的所有元素列表:

pets = ['dog','cat','dog','goldfish','cat','rabbit','cat']
print(pets)
while 'cat' in pets:
    pets.remove('cat')
print(pets)

while循环-使用用户输入来填充字典:  

responses = {}
pooling_active = True

while pooling_active:
    name = input('What is your name?  ')
    response = input('How old are you?  ')
    responses[name] = response
    repeat = input('Would you like to let another person respond?(yes/no)  ')
    if repeat == 'no':
        pooling_active = False
# for name,response in responses.items():
#     print(name,response)
responses

函数:

            形参:函数完成其工作所需的一项信息。

            实参:调用函数时传递给函数的信息。

            传递实参(可混用位置实参、关键字实参和默认值):

            1、位置实参:要求实参的顺序与形参的顺序相同。

            2、关键字实参:要求每个实参都由变量名和值组成,无需考虑函数调用中的实参顺            序,还清楚地指出了函数调用中各个值的用途。

            注意,使用关键字实参时,务必准确地指定函数定义中的形参名。

            3、编写函数时,可给每个形参指定默认值。使用默认值时,在形参列表中必须先列            出没有默认值的形参,再列出有默认值的实参。这让python依然能够正确地解读位置            实参。

            返回值:return语句,调用返回值的函数时,需要提供一个变量,用于存储返回的            值。

            让实参变成可选的:给可选的实参指定默认值--空字符串,将其移到形参列表的末            尾。

def get_formatted_name(first_name, last_name, middle_name=''):
    if middle_name:
        full_name = first_name + '' + middle_name + '' + last_name
    else:
        full_name = first_name + '' + last_name
    return full_name.title()
musician = get_formatted_name('jimi','hendrix')
print(musician)
musician1 = get_formatted_name('john','hooker','lee')
print(musician1)

             如果想要禁止函数修改列表(参数是列表),可以将列表的副本(list1[:])传递给函数。这样函数所做的任何修改都只影响副本。

            虽然向函数传递列表的副本可以保留原始列表的内容,但除非有充分的理由需要传递副本,否则还是应该将原始列表传递给函数,因为让函数使用现成列表可以避免花费时间和内存创建副本,从而提高效率,在处理大型列表时尤其如此。

            传递任意数量的实参:

            形参名*toppings中的星号让python创建一个名为toppings的空元祖,并将收到的所有值都封装到这个元组中。注意,python将实参封装到一个元组中,即便函数只收到一个值也是如此。

def make_pazza(*toppings):
    print(toppings)
make_pazza('pepperoni')
make_pazza('mushrooms','green peppers','extra cheese')

            结合使用位置实参和任意数量的实参

            使用任意数量的关键字实参

函数build_profile()的定义要求提供名和姓,同时允许用户根据需要提供任意数量的名称-值对。形参**user_info中的两个星号让python创建一个名为user_info的空字典,并将收到的所有名称-值对都封装到这个字典中。在这个函数中,可以像访问其他字典那样访问user_info中的名称-值对。

def build_profile(first,last,**user_info):
    profile = {}
    profile['first_name'] = first
    profile['last_name'] = last
    for key,value in user_info.items():
        profile[key] = value
    return profile
user_profile = build_profile('albert','einstein',location = 'princeton',field='physics')
print(user_profile)

 函数编写指南:

            给形参指定默认值时,等号两边不要有空格

            对于函数调用中的关键字实参,也应遵循这种约定。

类:

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

创建Dog类:

            它表示的不是简单的小狗,而是任何小狗,每个狗都有名字和年龄,只有宠物狗会蹲下和打滚。根据约定,在python中,首字母大写的名称指的是类,在这个类定义中的括号是空的,因为我们要从空白创建这个类。

class Dog():
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def sit(self):
        print(self.name.title() + 'is now sitting.')
    def roll_over(self):
        print(self.name.title() + 'rolled over!')

            类中的函数称为方法。__init__()是一个特殊的方法,每当你根据Dog类创建新实例时,python都会自动运行它。形参self必不可少,还必须位于其他形参的前面。每个与类相关联的方法调用都自动传递实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。每当我们根据Dog类创建实例时,都只需给最后两个形参(name和age)提供值。

            以self为前缀的变量都可供类中的所有方法使用,还可以通过类的任何实例来访问这些变量。self.name = name获取存储在形参name中的值,并将其存储到变量name中,然后该变量被关联到当前创建的实例。像这样可通过实例访问的变量称为属性。

根据类创建实例:

            可以将类视为有关如何创建实例的说明。Dog类是一系列说明,让python知道如何创建表示特定小狗的实例。下面来创建一个表示特定小狗的实例:

my_dog = Dog('willie',6)
print(my_dog.name.title())
print(my_dog.age)

            遇到这行代码时,python使用'willie'和6调用Dog类中的方法__init__(),方法__init__()创建一个表示特定小狗的示例,并使用我们提供的值来设置属性name和age。方法__init__()并未显式地包含return语句,但python自动返回一个表示这条小狗的实例。我们将这个实例存储在变量my_dog中。

            在这里,命名约定很有用:我们通常可以认为首字母大写的名称(如Dog)指的是类,而小写的名称(如my_dog)指的是根据类创建的实例。

            1、访问属性:

            要访问实例的属性,可使用句点表示法。my_dog.age,在这里,python先找到实例my_dog,再查找与这个实例相关联的属性age。在Dog类中引用这个属性时,使用的是self.name。

            2、调用方法

            根据Dog类创建实例后,就可以使用句点表示法来调用Dog类中定义的任何方法。要调用方法,可指定实例的名称(如my_dog)和要调用的方法,并用句点分隔他们。遇到代码my_dog.sit()时,python在类Dog中查找方法sit()并运行其代码。

            3、创建多个实例

            可按需求根据类创建任意数量的实例,条件是将每个实例都存储在不同的变量中,或占用列表或字典不同的位置。

 使用类和实例

python编程:从入门到实践--基础知识笔记_第1张图片

 给属性设定默认值

  1. class Car():
  2.     def __init__(self,make,model,year):
  3.         self.make = make
  4.         self.model = model
  5.         self.year = year
  6.         self.odometer_reading = 0
  7.     def read_odometer(self):
  8.         return self.odometer_reading
  9. my_new_car = Car('audi','a4',2016)
  10. my_new_car.read_odometer()

修改属性的值

            1、直接修改属性的值

            要修改属性的值,最简单的方式是通过实例直接访问它。

            2、通过方法修改属性的值

  1.  class Car():
  2.     def __init__(self,make,model,year):
  3.         self.make = make
  4.         self.model = model
  5.         self.year = year
  6.         self.odometer_reading = 0
  7.     def read_odometer(self):
  8.         return self.odometer_reading
  9.     def update_odometer(self,mileage):
  10.         self.odometer_reading = mileage
  11. my_new_car = Car('audi','a4',2016)
  12. my_new_car.update_odometer(23)
  13. my_new_car.read_odometer()

      out: 23

            3、通过方法对属性的值进行递增

  1. class Car():
  2.     def __init__(self,make,model,year):
  3.         self.make = make
  4.         self.model = model
  5.         self.year = year
  6.         self.odometer_reading = 10
  7.     def read_odometer(self):
  8.         return self.odometer_reading
  9.     def increment_odometer(self,miles):
  10.         self.odometer_reading += miles
  11. my_new_car = Car('audi','a4',2016)
  12. my_new_car.increment_odometer(100)
  13. my_new_car.read_odometer()

      out: 110

继承:

            一个类继承另一个类时,它将自动获得另一个类的所有属性和方法,原有的类称为父类,而新类称为子类。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。

              创建子类的实例时,python首先需要完成的任务是给父类的所有属性赋值。为此,子类的方法__init__()需要父类施以援手。创建子类时,父类必须包含在当前文件中,且位于子类前面。定义子类时,必须在括号内指定父类的名称。方法__init__()接受创建Car实例所需的信息。super()是一个特殊的函数,帮助python将父类和子类关联起来。这行代码让python调用ElectricCar的父类的方法__init__(),让ElectricCar实例包含父类的所有属性。父类也称为超类(superclass)。 my_tesla = EletricCar('tesla','model s',2016),这行代码调用    ElectricCar类中定义的方法__init__(),后者让python调用父类Car中定义的方法__init__()   

python编程:从入门到实践--基础知识笔记_第2张图片

              给子类定义属性和方法:

              让一个类继承另一个类之后,可添加区分子类和父类所需的新属性和新方法。

              在下面代码里,我们添加了self.battery_size,并设置其初始值70,根据ElectricCar类创建的所有实例都将包含这个属性,但所有Car实例都不包括它。对于ElectricCar类的特殊化程度没有任何限制,可以根据所需的准确程度添加任意数量的属性和方法。

python编程:从入门到实践--基础知识笔记_第3张图片

              重写父类的方法:

              对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可以在子类中定义一个这样的方法,即它与要重写的父类方法同名。如果有人对电动汽车调用这个重写的方法,python将忽略Car类中的方法,转而运行电动汽车类里面的代码。使用继承时,可让子类保留从父类那里继承来的精华,并剔除不需要的糟粕。

              将实例用作属性:

              使用代码模拟实物时,你可能会发现自己给类添加的细节越来越多:属性和方法清单以及文件都越来越长,这时候可能就需要将类的一部分作为一个独立的类提取出来。你可以将大型类拆分成多个协同工作的小类。

              首先我们定义了一个名为Battery的新类,它没有继承任何类。在ElectricCar类中,我们添加了一个名为self.battery的属性,这行代码让python创建一个新的Battery实例(由于没有指定尺寸,因此默认值为70),并将该实例存储在属性self.battery中。每当方法__init__()被调用时,都将执行该操作;因此现在每个ElectricCar实例都包含一个自动创建的Battery实例。

python编程:从入门到实践--基础知识笔记_第4张图片

               python标准库--有序字典python编程:从入门到实践--基础知识笔记_第5张图片

 类的编码风格:

              类名应该采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线。

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

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

              需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的import语句,再添加一个空行,然后编写导入你自己编写的模块的import语句。在包含多条import语句的程序中,这种做法让人很容易明白程序使用的各个模块都来自何方。

文件:

with open('xiyouji.txt') as file_object:
    contents = file_object.read()
    print(contents)

python编程:从入门到实践--基础知识笔记_第6张图片

              函数open()打开文件,它接受一个参数:要打开的文件的名称,python在当前执行的文件所在的目录中查找指定的文件,函数open()返回一个表示文件的对象。

              有空白行是因为read()到达文件末尾时返回一个空字符串,而将这个空字符串显示出来就是一个空行。要消除空白行,可在print语句中使用rstrip()。

              关键字with在不再需要访问文件后将其关闭。当然也可以调用open()和close()来打开和关闭文件,但这样做时,如果程序存在bug,导致close()语句未执行,文件将不会关闭。这看似微不足道,但未妥善地关闭文件可能会导致数据丢失或受损。如果在程序中过早地调用close(0,你会发现需要使用文件时它已关闭(无法访问),这会导致更多的错误。并非在任何情况下都能轻松确定关闭文件的恰当时机,但通过使用前面所示的结构,可以让python去确定:你只管打开文件,并在需要时使用它,python自会在合适的时候自动将其关闭。

              使用read()读取文件的全部内容,并将其作为一个长长的字符串存储在变量contents中。

              文件路径有相对路径和绝对路径两种,文件路径中使用反斜杠(\),绝对路径通常比相对路径长,因此将其存储在一个变量中,再将该变量传递给open()函数,通常使用绝对路径,可读取系统任何地方的文件。

              逐行读取--for循环:

              变量filename表示的并非实际文件--他只是一个让python知道到哪里去查找文件的字符串,调用open后,将一个表示文件及其内容的对象存储到了变量file_object中,这里也使用了关键字with,让python负责妥善地打开和关闭文件。

              出现空白行的原因:因为在这个文件中,每行的末尾都有一个看不见的换行符,而print语句也会加上一个换行符,因此每行末尾都有两个换行符:一个来自文件,一个来自print语句。要消除这些空白行,可在print语句中使用rstrip()。

filename = 'pi_digits.txt'
with open(filename) as file_object:
    for line in file_object:
        print(line)

python编程:从入门到实践--基础知识笔记_第7张图片

              使用关键字with时,open()返回的文件对象只在with代码块内可用,如果要在with代码块外访问文件的内容,可以在with代码块内将文件的各行存储在一个列表中,并在with代码块外使用该列表。

filename = 'pi_digits.txt'
with open(filename) as file_object:
    lines = file_object.readlines()
pi_string = ''
for line in lines:
    pi_string += line.strip()
print(pi_string)

              注意,读取文本文件时,python将其中所有文本都解读为字符串。如果读取的是数字,并要将其作为数值使用,就必须使用函数int()将其转换为整数,或使用函数float()将其转换为浮点数。

              写入文件:  

filename = 'pi_digits.txt'
with open(filename,'w') as file_object:
    file_object.write('I love writting')

              调用open()时提供了两个实参,第一个实参就是要打开的文件的名称,第二个实参w告诉python,我们要以写入模式打开这个文件。打开文件时,可指定读取模式('r'),写入模式('w'),附加模式('a')(在文件末尾添加内容)或能够读取和写入文件的模式('r+')。如果你忽略了模式实参,python将以默认的只读模式打开文件。

              如果你要写入的文件不存在,那么open()将会自动创建它。然而,以写入模式打开文件时千万要小心,因为如果指定的文件已存在,python将在返回文件对象前清空该文件。

              使用文件对象的方法write()将一个字符串写入文件。这个程序没有终端输出,只能打开txt文件去看。

              python只能将字符串写入文本文件。要将数值数据存储到文本文件中,必须先使用函数str()将其转换为字符串格式。

 异常:

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

              异常是使用try-except代码块处理的。try-except代码块让python执行指定的操作,同时告诉python发生异常怎么办。使用try-except代码块时,即便出现异常,程序也将继续运行:显示你编写的友好的错误信息,而不是令用户迷惑的traceback。

1、ZeroDivisionError异常

              下面代码指出的错误ZeroDivisionError是一个异常对象,python无法按照你的要求做时,就会创建这种对象。在这种情况下,python将停止运行程序,并指出引发了哪种异常,我们可以根据这些信息对程序进行修改。

python编程:从入门到实践--基础知识笔记_第8张图片

 使用try-except代码块

              如果try代码块中的代码运行起来没有问题,python将跳过except代码块;如果try代码块中的代码导致了错误,python将查找这样的except代码块,并运行其中的代码,即其中指定的错误与引发的错误相同。

python编程:从入门到实践--基础知识笔记_第9张图片

 使用异常避免崩溃

              发生错误时,如果程序还有工作没有完成,妥善地处理错误就尤其重要。这种情况经常会出现在 要求用户提供输入的程序中,如果程序能妥善地处理无效输入,就能再提示用户提供有效输入,而不至于崩溃。

python编程:从入门到实践--基础知识笔记_第10张图片

 else代码块:

              通过将可能引发错误的代码放在try--except代码块中,可提高这个程序抵御错误的能力。依赖于try代码块成功执行的代码都应放到else代码块中。在这个例子中,如果除法运算成功,我们就使用else代码块来打印结果。

              except代码块告诉python,出现ZeroDivisionError异常时该怎么办,如果try代码块因除0错误而失败,我们就打印出一条友好的消息,告诉用户如何避免这种错误。程序将继续运行,用户根本看不到traceback。

              try-except-else代码块的工作原理大致如下:python尝试执行try代码块中的代码,只有可能引发异常的代码才需要放在try语句中。有时候,有一些仅在try代码块成功执行时才需要运行的代码,这些代码应放在else代码块中。except代码块告诉python,如果它尝试运行try代码块中的代码引发了指定的异常,该怎么办。

              通过预测可能发生错误的代码,可编写健壮的程序,它们即便面临无效数据或缺少资源,也能继续运行,从而能够抵御无意的用户错误和恶意的攻击。

python编程:从入门到实践--基础知识笔记_第11张图片

 2、FileNotFoundError异常

python编程:从入门到实践--基础知识笔记_第12张图片

              这个错误是函数open()导致的,因此要处理这个错误,必须将try语句放在包含open()的代码行之前:

 python编程:从入门到实践--基础知识笔记_第13张图片

 分析文本:

              方法split()以空格为分隔符将字符串分拆成多个部分,并将这些部分都存储到一个列表中。

 python编程:从入门到实践--基础知识笔记_第14张图片

python编程:从入门到实践--基础知识笔记_第15张图片 失败时一声不吭:

              在except代码块中写pass语句。

 存储数据:

              使用json模块,模块json让你能够将简单的python数据结构转储到文件中,并在程序再次运行时加载该文件中的数据。还可以使用json在python之间分享数据。更重要的是,JSON数据格式并非python专用,这让你能够将以JSON格式存储的数据与使用其他编程语言的人分享。

存储 json.dump()和读取 json.load():

              函数 json.dump() 接受两个实参:要存储的数据以及可用于存储数据的文件对象。通常使用文件扩展名.json来指出文件存储的数据为JSON格式。这个程序没有输出,我们可以打开文件number.json,看看其内容。

import json
numbers = [1,2,3,4,5,6,7,8,8]
filename = 'number.json'
with open(filename,'w') as f_obj:
    json.dump(numbers,f_obj)

python编程:从入门到实践--基础知识笔记_第16张图片

              使用json.load()将这个列表读取到内存中:

python编程:从入门到实践--基础知识笔记_第17张图片

保存和读取用户生成的数据:

              我们提示输入用户名,并将其存储在一个变量中。调用json.dump(),将用户名存储到文件中。

python编程:从入门到实践--基础知识笔记_第18张图片

              再编写一个程序,向其名字被存储的用户发出问候:

python编程:从入门到实践--基础知识笔记_第19张图片

              将这两个程序合并为一个:

python编程:从入门到实践--基础知识笔记_第20张图片

重构:

              经常会遇到一种情况:代码能够正常运行,但可做进一步的改进--将代码划分为一系列完成具体工作的函数。这样的过程被称为重构。重构让代码更清晰、更易于理解、更容易扩展。

              我们可以看到上面代码重点是问候用户,因此我们把所有代码放在一个名为greet_user()的函数中:

python编程:从入门到实践--基础知识笔记_第21张图片

              函数greet_user()所做的不仅仅是问候用户,还在存储了用户名时获取它,而在没有存储用户名时提示用户输入一个,接下来我们重构greet_user(),让它不执行这么多任务:

python编程:从入门到实践--基础知识笔记_第22张图片

              新增的函数get_stored_username()目标明确,如果存储了用户名,这个函数就获取并返回它;如果文件username.json不存在,这个函数就返回None。这是一种不错的做法:函数要么返回预期的值,要么返回None;这让我们能够使用函数的返回值做简单测试。

              我们还需将greet_user()中的另一个代码块提取出来:将没有存储用户名时提示用户输入的代码放在一个独立的函数中: 

import json
def get_stored_username():
    """如果存储了用户名,就获取它"""
    try:
        with open(filename) as f_obj:
            username = json.load(f_obj)
    except FileNotFoundError:
        return None
    else:
        return username

def get_new_name():
    """提示用户输入用户名"""
    filename = 'username.json'
    username = input('What is your name? ')
    with open(filename,'w') as f_obj:
        json.dump(username,f_obj)
    return username

def greet_user():
    """问候用户,并指出其名字"""
    username = get_stored_username()
    if username:
        print('Welcome back, '+ username +' !')
    else:
        username = get_new_name()
        print('We will remember you, '+ username +' !')
greet_user()

              在最终版本中,每个函数都执行单一而清晰的任务。我们调用greet_user(),它打印一条合适的消息:要么欢迎老用户回来,要么问候新用户。为此,它首先调用get_stored_username(),这个函数只负责获取存储的用户名(如果存储了的话),再在必要时调用get_new_name(),这个函数只负责获取并存储新用户的用户名。要编写出清晰而易于维护和扩展的代码,这种划分工作必不可少。

 测试代码------使用python模块unittest:

              要测试的代码如下 name_function.py:

def get_formatted_name(first_name, last_name):
    """Generate a neatly formatted full name"""
    full_name = first_name + ' ' + last_name
    return full_name.title()

              函数get_formatted_name()将名和姓合并成姓名,在名和姓之间加上一个空格,并将它们首字母大写,再返回结果。

              单元测试用于核实函数的某个方面没有问题,测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。良好的测试用例考虑到了函数可能收到的各种输入,包含针对所有这些情形的测试。全覆盖式测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。

              要为函数编写测试用例,可先导入模块unittest以及要测试的函数,再创建一个继承unittest.TestCase的类,并编写一系列方法对函数行为的不同方面进行测试。

              下面是只包含一个方法的测试用例 test_name_function.py,它检查函数get_formatted_name()在给定名和姓时能否正确的工作:

python编程:从入门到实践--基础知识笔记_第23张图片

              你可以随便给这个类命名,但最好让它看起来与要测试的函数相关,并包含字样Test。这个类必须继承unittest.TestCase类,这样python才知道如何运行你编写的测试。

              我们运行test_name_function.py时,所有以test_打头的方法都将自动运行。

              断言方法用来核实得到的结果是否与期望的结果一致。我们调用unittest的方法assertEqual(),并向它传递参数。代码行self.assertEqual(formatted_name,'Janis Joplin')意思是说:将'formatted_name'的值同字符串'Janis Joplin'进行比较,若相等就万事大吉,不相等就返回错误。

              代码行unittest.main(argv=['first-arg-is-ignored'],exit=False)让python运行这个文件中的测试。

              第1行的句点表明有一个测试通过了。接下来的一行指出python运行了一个测试,消耗的时间不到0.001秒。最后的OK表明该测试用例中的所有单元测试都通过了。

              不能通过的测试:

              下面是get_formatted_name()的新版本,它要求通过一个实参指定中间名:

python编程:从入门到实践--基础知识笔记_第24张图片

python编程:从入门到实践--基础知识笔记_第25张图片

              测试未通过怎么办?

              测试未通过时,不要修改测试,而应该修复导致测试不能通过的代码:检查刚对函数所做的修改,找出导致函数行为不符合预期的修改。

              修改代码,将middle_name设为可选的:

python编程:从入门到实践--基础知识笔记_第26张图片

              现在,测试用例通过了。

              添加新测试--用于测试包含中间名的姓名:

              方法名(test_first_last_middle_name())必须以test_打头,这样它才会在我们运行test_name_function.py时自动运行。在TestCase类中使用很长的方法名是可以的,这些方法的名称必须是描述性的,这才能让你明白测试未通过时的输出,这些方法由python自动调用,你根本不用编写调用它们的代码。

python编程:从入门到实践--基础知识笔记_第27张图片

测试类:

              下面表描述了6个常用的断言方法。使用这些方法可以核实返回的值等于或不等于预期的值、返回的值为True或False、返回的值是否在列表中。你只能在继承unittest.TestCase的类中使用这些方法。

各种断言方法
方法 用途
assertEqual(a,b) 核实 a==b
assertNotEqual(a,b) 核实 a!=b
assertTrue(x) 核实 x为True
assertFalse(x) 核实 x为False
assertIn(item,list) 核实 item在list中
assertNotIn(item,list) 核实 item不在list中

 方法setUp():

              unittest.TestCase类中包含方法setUp(),让我们只需要创建这些对象一次,再运行各个以test_打头的方法。这样,在你编写的每个测试方法中都可使用在方法setUp()中创建的对象了。

              方法setUp()创建的变量名前面都含有前缀self,因此可在这个类中的任何地方使用。

              运行测试用例时,每完成一个单元测试,python都打印一个字符:测试通过时打印一个句点;测试引发错误时打印一个E;测试导致断言失败时打印一个F。如果测试用例包含很多单元测试,需要运行很长时间,就可通过观察这些结果来获悉有多少个测试通过了。

你可能感兴趣的:(python基础,python,开发语言)