类
创建与使用类
class Dog(): #首字母大写
def _init_(self,name,age): #默认方法
"""初始化属性name和age"""
self.name = name
self.age = age
def sit(self): #形参只有self
"""模拟小狗蹲下"""
print(self.name.title() + " sits") #前缀self
首字母大写的名称指的是类。
类中的函数被称为方法,_init_()
是一个特殊的方法,每当你根据 Dog 类创建新实例时,Python都会自动运行它。在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突。
在_init_()
方法中形参self必不可少,且必须位于其他形参前面。每个与类相关联的方法调用都自动传递实参 self ,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
以 self 为前缀的变量都可供类中的所有方法使用,我们还可以通过类的任何实例来访问这些变量。
根据类创建实例
首字母大写的名称指的是类,而小写的名称指的是根据类创建的实例。
- 访问属性:
my_dog = Dog('willie',6)
my_dog.name
- 调用方法:
my_dog.sit()
使用类和实例
给属性指定默认值
在方法 init() 内指定这种初始值是可行的;如果你对某个属性这样做了,就无需包含为它提供初始值的形参。
class Car():
def __init__(self, make, model, year):
"""初始化描述汽车的属性"""
self.make = make
self.model = model
self.year = year
#在方法内设定某个属性的默认值
self.odometer_reading = 0
def read_odometer(self):
print(str(self.odometer_reading))
my_new_car = Car('audi','a4',2016)
my_new_car.read_odometer()
修改属性的值
- 直接通过实例进行修改
my_new_car = Car('audi','a4',2016)
my_new_car.odometer_reading = 23
- 通过方法进行设置
class Dog():
...
#在类中添加更新属性的方法
def update_odometer(self,mileage):
if mileage > self.odometer_reading:
self.odometer_reading = mileage
else:
print("Wrong mileage")
...
my_new_car.update_odometer(23)
- 通过方法进行递增
class Car():
...
#通过方法对属性进行增加
def increment_odometer(self,miles):
self.odometer_reading += miles
...
my_new_car.increment_odometer(100)
继承
个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新类称为子类。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
子类的__init_()方法
class Car():
def _init_(self,make,model,year):
...
class ElectricCar(Car): #括号内指定父类的名称
def _init_(self,make,model,year):
super()._init_(make,model,year)
创建子类时,父类必须包含在当前文件中,且位于子类前面。
父类也称为超类(superclass),super()函数让子类调用父类的方法。
给子类定义属性和方法
class Car():
def _init_(self,make,model,year):
...
class ElectricCar(Car): #括号内指定父类的名称
def _init_(self,make,model,year):
super()._init_(make,model,year)
self.battery_size = 70 #子类添加新属性
#添加新方法
def describe_battery(self):
Print(str(self.battery_size))
重写父类的方法
在子类中定义与重写的父类方法同名的方法即可。
将实例用作方法
大型类拆分成多个协同工作的小类。
class Car():
...
class Battery():
def _init_(slef,battery_size=70):
self.battery_size = battery_size
def describe_battery(self):
print(str(self.battery_size))
class ElectriCar(Car):
def _init_(self,make,model,year):
super()._init_(make,model,year)
self.battery = Battery() #添加属性并创建Battery新实例
my_tesla = ElectricCar('tesla','modle s',2016)
#查找属性 battery在该属性中的Battery实例调用方法describe_battery
my_tesla.battery.describe_battery()
导入类
将类存储在模块中,然后在主程序中导入所需的模块。
导入单个类
模块开头应该包含一个模块级文档字符串,对该模块内容做简要描述。
"""一个用于表示汽车的类"""
#命名为car.py
class Car():
from car import Car #导入模块car中的Car类
在一个模块中存储多个类
"""一组用于表示燃油汽车与电动车的类"""
class Car():
...
class ElectricCar():
...
class Battery():
...
从一个模块中导入多个类
from car import Car,ElectricCar
导入整个模块
导入整个模块,再使用句点表示法访问需要的类。创建类实例的代码都包含模块名,因此不会与当前文件使用的任何名称发生冲突。
import car
my_beetle = car.Car('volkswagen','beetle',2016)
my_tesla = car.ElectricCar('tesla','roadstar',2016)
导入模块中所有类(不推荐)
from module_name import *
需要从一个模块中导入很多类时,最好导入整个模块,并使用 module_name.class_name 语法来访问类。
在一个模块中导入另一个模块
一个模块中的类依赖于另一个模块中的类。在这种情况下,可在前一个模块中导入必要的类。
在子类模块中导入父类模块。
Python标准库
Python标准库是一组模块,使用标准库中的任何函数和类,为此只需在程序开头包含一条简单的 import 语句。
创建字典并记录其中的键 — 值对的添加顺序,可使用模块 collections 中的 OrderedDict 类。兼具列表和字典的主要优点。
类编码风格
类名应采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线。
每个类/模块,都应紧跟在类定义后面包含一个文档字符串。
空行来组织代码,类中使用一个空行来分隔方法;模块中可使用两个空行来分隔类。
同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的 import 语句,再添加一个空行,然后编写导入你自己编写的模块的 import 语句。
文件与异常
从文件中读取数据
读取整个数据
with open('pi_digits.txt') as file_object:
contents = file_object.read()
print(contents)
print(contents.rstrip())
函数 open() 接受一个参数:要打开的文件的名称。Python在当前执行的文件所在的目录中查找指定的文件。函数 open()返回一个表示文件的对象。
关键字 with 在不再需要访问文件后将其关闭。
方法 read()读取这个文件的全部内容,并将其作为一个字符串存储在变量 contents 中。 read() 到达文件末尾时返回一个空字符串,删除多出来的空行,可在 print 语句中使用 rstrip()。
文件路径
使用相对文件路径来打开该文件夹中的文件,该位置是相对于当前运行的程序所在目录的。
#当前文件夹为python_work,需要打开文件在text_file中
#添加文件路径
with open('text_file\filename.txt') as file_object
绝对文件路径:
#文件位于other_files中
file_path = 'C:\Users\ehatthes\other_files\text_files\filename.txt'
with open(file_path) as file_object
逐行读取(for)
#将要读取的文件的名称存储在变量 filename 中
filename = 'pi_digits.txt'
with open(filename) as file_object:
for line in file_object: #for逐行读取
print(line.rstrip()) #去除每行末尾换行符
创建一个包含文件各行内容的列表
要在 with 代码块外访问文件的内容,可在 with 代码块内将文件的各行存储在一个列表中,并在 with 代码块外使用该列表。
filename = 'pi_digits.txt'
with open(filename) as file_object:
#方法readlines()从文件中读取每一行,并将其存储在一个列表中
lines = file_object.readlines()
#在with代码块外使用
for line in lines:
print(line.rstrip())
使用文件的内容
...
pi_string = ''
for line in lines:
pi_string += line.strip() #strip删除每行左边的空格
# 打印结果 3.1415926...
print(pi_string)
读取文本文件时,Python将其中的所有文本都解读为字符串。如果你读取的是数字,并要将其作为数值使用,就必须使用函数 int() 将其转换为整数,或使用函数 float() 将其转换为浮点数。
包含一百万位的大型文件
...
print(pi_string[:52]) #打印前51位
写入文件
写入空文件
filename = 'programming.txt'
#open()第一个参数是要打开文件名称,第二个参数是以什么模式打开,读取模式( 'r' )、写入模式( 'w' )、附加模式( 'a' )或让你能够读取和写入文件的模式( 'r+' ),默认是只读模式。
with open(filename,'w') as file_object:
file_object.write("I love programming.")
Python只能将字符串写入文本文件。要将数值数据存储到文本文件中,必须先使用函数str() 将其转换为字符串格式。
写入多行
函数 write() 不会在你写入的文本末尾添加换行符。要让每个字符串都单独占一行,需要在 write() 语句中包含换行符。
...
#还可使用制表符、空格、空行设置输出格式.
file_object.write("I love programming.\n")
附加到文件
#附加模式写入文件按最后,如果文件不存在将自动创建。
...
with open(filename,'a') as file_object:
...
异常
Python使用被称为异常的特殊对象来管理程序执行期间发生的错误。异常是使用 try-except 代码块处理的。 try-except 代码块让Python执行指定的操作,同时告诉Python发生异常时怎么办。
使用 try-except 代码块
try:
print(5/0)
#指定的错误与引发的错误相同
except ZeroDivisionError:
print("You can't divide by zero!")
else 代码块
依赖于 try 代码块成功执行的代码都应放到 else 代码块中。
分析文本
方法 split() 以空格为分隔符将字符串分拆成多个部分,并将这些部分都存储到一个列表中。
filename = 'alice.txt'
try:
with open(filename) as f_obj:
contents = f_obbj.read()
except FileNotFoundError:
print("file don't exist")
else:
words = contents.split()
num_words = len(words)
print(len(words))
使用多个文件
def count_words(filename):
"""计算一个文件大致包含多少个单词"""
try:
with open(filename) as f_obj:
contents = f_obj.read()
except FileNotFoundError:
msg = "Sorry, the file " + filename + " does not exist."
print(msg)
else:
# 计算文件大致包含多少个单词
words = contents.split()
num_words = len(words)
print("The file " + filename + " has about " + str(num_words) +
" words.")
filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
for filename in filenames:
count_words(filename)
Python有一个 pass 语句,可在代码块中使用它来让Python什么都不要做。
try:
...
except ...:
pass
else:
...
存储数据
使用模块 json 来存储数据。
使用json.dump()
和json.load()
- 函数 json.dump() 接受两个实参:要存储的数据以及可用于存储数据的文件对象
import json
numbers = [2, 3, 5, 7, 11, 13]
filename = 'numbers.json'
with open(filename, 'w') as f_obj:
json.dump(numbers,f_obj)
- json.load() 将这个列表读取到内存中
import json
filename = 'numbers.json'
with open(filename) as f_obj1:
numbers = json.load(f_obj1)
print(numbers)
重构
代码能够正确地运行,但可做进一步的改进-将代码划分为一系列完成具体工作的函数。这样的过程被称为重构。
测试代码
测试函数
单元测试和测试用例
Python标准库中的模块 unittest 提供了代码测试工具。单元测试用于核实函数的某个方面没有问题;测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。
全覆盖式测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。对于大型项目,要实现全覆盖可能很难。通常,最初只要针对代码的重要行为编写测试即可,等项目被广泛使用时再考虑全覆盖。
可通过的测试
为函数编写测试用例,可先导入模块 unittest 以及要测试的函数,再创建一个继承 unittest.TestCase 的类,并编写一系列方法对函数行为的不同方面进行测试。
#导入了模块 unittest 和要测试的函数 get_formatted_ name()
import unittest
from name_function import get_formatted_name
#创建名为NamesTestCase的类,包含一系列针对get_formatted_name() 的单元测试,命名最好与测试函数有关且包含字样Test,必须继承unittest.TestCase类
class NameTestCase(unittest.TestCase):
"""测试name_function.py"""
#运行 test_name_function.py 时,所有以 test_ 打头的方法都将自动运行。
def test_first_last_name(self):
"""能正确处理姓名吗"""
formatted_name = get_formatted_name('janis', 'joplin')
#断言方法用来核实得到的结果是否与期望的结果一致。
self.assertEqual(formatted_name, 'Janis Joplin')
#运行这个文件中的测试
unittest.main()
测试类
各种断言方法
方法 | 用途 |
---|---|
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中 |
一个要测试的类
#survey.py
class AnonymousSurvey():
def __init__(self, question):
self.question = question
self.responses = []
def show_question(self):
print(self.question)
def store_response(self,new_response):
self.responses.append(new_response)
def show_results(self):
print("Survey results:")
for response in responses:
print("- " + response)
#language_survey.py
from survey import AnonymousSurvey
question = "What language did you learn to speak?"
my_survey = AnonymousSurvey(question)
my_survey.show_question()
while True:
response = input("language: ")
if response == 'quit':
break
my_survey.store_response(response)
my_survey.show_results()
测试 AnonymousSurvey
类
#test_survey.py
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
def test_store_single_response(self):
question = "What's language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
my_survey.store_response('English')
self.assertIn('English',my_survey.responses)
unittest.main()
方法setUp()
unittest.TestCase
类包含方法 setUp()
,让我们只需创建这些对象一次,并在每个测试方法中使用它们。
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
def setUp(self):
question = "What's 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.respons
def test_store_three_response(self):
for response in responses:
self.my_survey.store_response(response)
for response in self.responses:
self.assertIn(response,self.my_survey.responses)
unittest.main()
测试自己编写的类时,方法 setUp() 让测试方法编写起来更容易:可在 setUp() 方法中创建一系列实例并设置它们的属性,再在测试方法中直接使用这些实例。