Python编程:从入门到时间 第九、十、十一章学习笔记

创建与使用类

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 为前缀的变量都可供类中的所有方法使用,我们还可以通过类的任何实例来访问这些变量。

根据类创建实例

首字母大写的名称指的是类,而小写的名称指的是根据类创建的实例。

  1. 访问属性:
my_dog = Dog('willie',6)
my_dog.name
  1. 调用方法:
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()

修改属性的值

  1. 直接通过实例进行修改
my_new_car = Car('audi','a4',2016)
my_new_car.odometer_reading = 23
  1. 通过方法进行设置
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)
  1. 通过方法进行递增
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()

  1. 函数 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)
  1. 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() 方法中创建一系列实例并设置它们的属性,再在测试方法中直接使用这些实例。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值