Python 学习笔记[3]

八、函数

1.定义函数

def greet_user():
    """显示简单的问候语"""
    print("Hello! ")


greet_user()

Hello!


使用关键字 def 来告诉python,要定义一个函数。
def 函数名():

() 内可以有信息,但是 () 必不可少。
定义以冒号结尾。
紧跟在函数后面的所有缩进进行构成了函数体。
“”" “”" 中的文本称为文档字符串( docstring )的注释,描述了函数是做什么的。

  • 在函数定义中,变量是一个形参( parameter ),即函数完成工作所需的信息;
  • 值是一个实参( argument ),即调用函数时传递给函数的信息。

2.传递实参

函数定义中可能包含多个形参,因此函数调用中也可能包含多个实参。

位置实参:要求实参的顺序与形参的顺序相同
关键字实参:每个实参都由变量名和值组成
使用列表和字典

2.1位置实参

def describe_pet(animal_type, pet_name):
    """显示宠物信息"""
    print(f"I have a {animal_type}.")
    print(f"My {animal_type}'s name is {pet_name.title()}.")


describe_pet('hamster', 'harry')

I have a hamster.
My hamster’s name is Harry.


2.2关键字实参

def describe_pet(animal_type, pet_name):
    """显示宠物信息"""
    print(f"I have a {animal_type}.")
    print(f"My {animal_type}'s name is {pet_name.title()}.")


describe_pet(animal_type='hamster', pet_name='harry')
describe_pet(pet_name='harry', animal_type='hamster')	# 不需要顺序也可

I have a hamster.
My hamster’s name is Harry.
I have a hamster.
My hamster’s name is Harry.


3.默认值

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

def describe_pet(pet_name, animal_type='dog'):
    """显示宠物信息"""
    print(f"I have a {animal_type}.")
    print(f"My {animal_type}'s name is {pet_name.title()}.")


describe_pet('harry')
describe_pet(pet_name='Lynn', animal_type='hamster')
# 或者 describe_pet('Lynn', 'hamster')

I have a dog.
My dog’s name is Harry.
I have a hamster.
My hamster’s name is Lynn.


4.返回值

函数可以处理一些数据,并返回一个或一组值。函数返回的值称为返回值。在函数中,可使用 return 语句返回到调用函数的代码行。

4.1返回简单值

def get_formatted_name(first_name, last_name, middle_name=''):
    """返回整洁的名字"""
    if middle_name:     # python将非空的字符串解读为True
        full_name = f"{first_name} {middle_name} {last_name}"
    else:
        full_name = f"{first_name} {last_name}"
    return full_name.title()


musician = get_formatted_name('jimi', 'hendrix')
print(musician)
musician = get_formatted_name('john', 'hooker', 'lee')
print(musician)

Jimi Hendrix
John Lee Hooker


4.2返回字典

函数可返回任何类型的值,包括列表和字典等复杂的数据结果

def build_person(first_name, last_name, age=None):
    """返回一个字典,其中包含有关一个人的信息"""
    person = {'first': first_name, 'last': last_name}
    if age:
        person['age'] = age
    return person


musician = build_person('jami', 'hendrix', 27)
print(musician)

{‘first’: ‘jami’, ‘last’: ‘hendrix’, ‘age’: 27}


在函数定义中,新增了一个可选的形参 age ,并将其默认值设置为特殊值 None (表示变量没有值)。可将 None 视为占位值。在测试条件中,None 相当于 False。

5.传递列表

5.1在函数中修改列表

在函数中对这个列表所做的任何修改都是永久性的。

def print_models(unprinted_designs, completed_models):
    """模拟打印每个设计,直到没有未打印的设计为止
    打印每个设计后,都将其移到列表completed_models中"""
    while unprinted_designs:
        current_design = unprinted_designs.pop()
        print(f"Printing model: {current_design}")
        completed_models.append(current_design)


def show_completed_models(completed_models):
    """显示打印好的所有模型"""
    print("\nThe following models have been printed:")
    for model in completed_models:
        print(model)


unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
completed_models = []

print_models(unprinted_designs, completed_models)
show_completed_models(completed_models)
print(unprinted_designs)	#检验是否被修改

Printing model: dodecahedron
Printing model: robot pendant
Printing model: phone case

The following models have been printed:
dodecahedron
robot pendant
phone case
[]


5.2禁止函数修改列表

有时候需要禁止函数修改列表,可向函数传递列表的副本而非原件。
形如:function_name(List_name[:])
除非有充分的理由,否则还是应该将原始列表传递给函数。这是因为让函数使用现成的列表可避免花时间和内存创建副本,从而提高效。

6.任意数量的实参

6.1使用任意数量的位置实参

下面的函数只有一个形参 *toppings,但不管调用语句提供了多少实参,这个形参会将它们都收入囊中。
形参名*toppings中的星号让 python 创建一个名为 toppings 的空元组,并将收到的所有值都封装到这个元组中,即函数只收到一个值。

def make_pizza(*toppings):
    """打印顾客点的所有配料"""
    print(toppings)


make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')

(‘pepperoni’,)
(‘mushrooms’, ‘green peppers’, ‘extra cheese’)


如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。python先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中。

def make_pizza(size, *toppings):
    """打印顾客点的所有配料"""
    print(f"\nMaking a {size}-inch pizza with the following toppings:")
    for topping in toppings:
        print(f"-{topping}")


make_pizza(15, 'pepperoni')
make_pizza(20, 'mushrooms', 'green peppers', 'extra cheese')

Making a 15-inch pizza with the following toppings:
-pepperoni

Making a 20-inch pizza with the following toppings:
-mushrooms
-green peppers
-extra cheese


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

形参**user_info中两个星号让 python 创建一个名为 user_info 的空字典,并将收到的所有名称值对都放在这个字典中。

def build_profile(first, last, **user_info):
    """创建一个空字典,包括用户的一切"""
    user_info['first_name'] = first
    user_info['last_name'] = last
    return user_info


user = build_profile('albert', 'einstein',
                     location='princeton', field='physics')
print(user)

{‘location’: ‘princeton’, ‘field’: ‘physics’, ‘first_name’: ‘albert’, ‘last_name’: ‘einstein’}


7.将函数存储在模块中

将模块存储在称为模块的独立文件中,再将模块导入到主程序中。import 语句允许在当前运行的程序文件中使用模块中的代码。

7.1导入整个模块

模块是扩展名为 .py 的文件,包含要导入到程序中的代码。
在同一个目录下,创建 pizza.py 和 making_pizzas.py 两个文件, pizza.py 作为模块, making_pizzas.py 作为主函数。

pizza.py 文件

def make_pizza(size, *toppings):
    """打印顾客点的所有配料"""
    print(f"\nMaking a {size}-inch pizza with the following toppings:")
    for topping in toppings:
        print(f"-{topping}")

making_pizzas.py 文件

import pizza

pizza.make_pizza(15, 'pepperoni')
pizza.make_pizza(20, 'mushrooms', 'green peppers', 'extra cheese')

Making a 15-inch pizza with the following toppings:
-pepperoni

Making a 20-inch pizza with the following toppings:
-mushrooms
-green peppers
-extra cheese


代码行 import pizza 让 python 打开文件 pizza.py ,并将其中的所有函数都复制到这个函数中(看不到复制的代码)。
调用被导入模块中的函数,可指定被导入模块的名称函数名,并用句点分隔。

7.2导入特定的函数

导入模块中的特定函数

from module_name import function_name

通过用逗号分隔,导入任意数量的函数

from module_name import function_0, function_1, function_2

使用上述语法时,调用函数无需使用句点,指定名称即可。

7.3使用as给模块/函数指定别名

模块:

import pizza as p
p.make_pizza(……)

函数:

from pizza import make_pizze as mp
mp(……)

7.4导入模块中所有函数

使用星号(*)运算符可导入模块中所有函数。

import pizza *

由于导入了每个函数,可通过名称来调用每一个函数,而无需使用句点表示法。
导入所有函数可能会导致遇到多个名称相同的函数或变量,进而覆盖函数,产生错误。

7.5函数编写指南

每个函数都注释,并使用文档字符串格式
形参指定默认值/调用关键字实参时,等号两边不要有空格
形参列表过长,在函数定义输入左括号后打回车键,并在下一行按两次 tab 键
相邻函数用两行空行分开

九、类

1.创建 Dog 类

class Dog:
	""""一次模拟小狗的简单测试"""

	def __init__(self, name, age):
		"""初始化属性 name 和 age"""
		self.name = name
		self.age = age
	
	def sit(self):
		"""模拟小狗收到命令蹲下"""
		print(f"{self.name} is now sitting.")
	
	def roll_over(self):
		"""模拟小狗收到命令时打滚"""
		print(f"{self.name} rolled over!")

在python中,首字母大写的名称指的是类。类中的函数称为方法

__init__()是一个特殊的方法,每当根据 Dog 类创建新实例时,python都会自动运行它。在这个方法中,开头和末尾各有两个下划线,这是一种约定,旨在避免python默认方法与普通方法发生名称冲突。

在这个方法定义中,形参 self 必不可少,而且必须位于其他形参的前面。因为python调用这个方法来创建 Dog 实例时,将自动传入实参 self 。每个与实例相关联的方法调用都自动传递实参 self ,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。

以 self 为前缀的变量(self.name)可供类中的所有方法使用,可以通过类的任何实例来访问。像这样可通过实例访问的变量称为属性

2.根据类创建实例

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

class 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’s name is willie.
My dog is 6 years old.
willie is now sitting.
willie rolled over!


2.1访问属性

要使用实例的属性,可使用句点表示法 my_dog.name 。在这里,python先找到实例 my_dog ,再查找与该实例相关的属性 name 。

2.2调用方法

要调用方法,可指定实例的名称和要调用的方法,并用句点分隔。形如 my_dog.sit()

3.使用类和实例

3.1给属性指定默认值

class Car:
	"""模拟汽车"""

	def __init__(self, make, model, year):
		"""初始化描述汽车属性"""
		self.make = make
		self.model = model
		self.year = year
		self.odometer_reading = 0		# 给属性指定默认值

	def get_descriptive_name(self):
		"""返回整洁的描述性信息"""
		long_name = f"{self.year} {self.make} {self.model}"
		return long_name.title()

	def read_odometer(self):
		"""打印一条汽车里程的信息"""
		print(f"This car has {self.odometer_reading} miles on it.")


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


2020 Audi A4
This car has 0 miles on it.


3.2修改属性的值

3.2.1直接修改属性的值

通过实例直接访问它。

my_new_car = Car('audi', 'a4', 2020)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 25		# 直接修改属性的值
my_new_car.read_odometer()

2020 Audi A4
This car has 25 miles on it.


3.2.2 通过方法修改属性的值
class Car:
	--snip--
	
	def update_odometer(self, mileage):
		"""将里程表读数设定为指定的值"""
		self.odometer_reading = mileage

my_new_car = Car('audi', 'a4', 2020)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(27)		# 通过方法修改属性的值
my_new_car.read_odometer()

2020 Audi A4
This car has 27 miles on it.


可对方法 update_odometer() 进行扩展,使其在修改里程表读数时做些额外的工作。

class Car:
	--snip--
	
	def update_odometer(self, mileage):
		"""
		将里程表读数设定为指定的值。
		禁止将里程表的数据往回调。
		"""
		if mileage >self.odometer_reading:
			self.odometer_reading = mileage
		else:
			print("You can't roll back an odometer!")
3.3.3 通过方法对属性的值进行增值
class Car:
	--snip--
	
	def increment_odometer(self, miles):
		"""将里程表读书增加指定的量"""
		self.odometer_reading += miles

4.继承

一个类继承另一个类时,将自动获得另一个类的所有属性和方法。原有的类称为父类,而新类称为子类

4.1子类的方法__init__()

在既有类的基础上编写新类时,通常要调用父类的方法 __init()__ 。这将初始化在父类 __init()__ 方法中定义的属性,从而让子类包含这些属性。

class Car:
	"""模拟汽车"""

	def __init__(self, make, model, year):
		"""初始化描述汽车属性"""
		self.make = make
		self.model = model
		self.year = year
		self.odometer_reading = 0		# 给属性指定默认值

	def get_descriptive_name(self):
		"""返回整洁的描述性信息"""
		long_name = f"{self.year} {self.make} {self.model}"
		return long_name.title()

	def read_odometer(self):
		"""打印一条汽车里程的信息"""
		print(f"This car has {self.odometer_reading} miles on it.")

	def update_odometer(self, mileage):
		"""
		将里程表读数设定为指定的值。
		禁止将里程表的数据往回调。
		"""
		if mileage > self.odometer_reading:
			self.odometer_reading = mileage
		else:
			print("You can't roll back an odometer!")

	def increment_odometer(self, miles):
		"""将里程表读书增加指定的量"""
		self.odometer_reading += miles

# 子类
class ElectricCar(Car):
	"""电动汽车的独特之处"""
	def __init__(self, make, model, year):
		"""初始化父类的的属性"""
		super().__init__(make, model, year)


my_tesla = ElectricCar('tesla', 's', 2018)
print(my_tesla.get_descriptive_name())

2018 Tesla S


定义子类时,必须在圆括号内指定父类的名称。方法 __init()__ 接受创建 Car 实例所需的信息。

super()是一个特殊函数,让你能够调用父类的方法。super().__init__(make, model, year) 这行代码python调用父类的方法 __init()__ ,让 ElectricCar 实例包括这个方法定义的所有属性。父类也称为超类(superclass)。

4.2给子类定义属性和方法

让一个类继承另一个类后,就可以添加独属于子类的新属性和新方法了。

class Car:
	--snip--

class ElectricCar(Car):
	"""电动汽车的独特之处"""
	def __init__(self, make, model, year):
		"""
		初始化父类的的属性
		在初始化电动汽车独有属性
		"""
		super().__init__(make, model, year)
		self.battery_size = 75		# 独属子类的属性

	def describe_battery(self):		# 独属子类的方法
		"""打印一条描述电瓶容量的信息"""
		print(f"This car has a {self.battery_size}-kwh battery.")


my_tesla = ElectricCar('tesla', 's', 2018)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()

2018 Tesla S
This car has a 75-kwh battery.


4.3重新父类的方法

对于父类的方法,只要它不符合子类模拟的实物行为,都可以进行重写。为此,可在子类中定义一个与要重写的父类方法同名的方法。这样,python将不会考虑这个父类方法,而是只关注在子类中定义的相应方法。

4.4将类用作另一个类的属性

当自己给类添加的细节越来越多时,可能需要将类的一部分提取出来,作为一个单独的类。

class Car:
	--snip--

class Battery:
	"""描述电瓶信息"""
	def __init__(self, battery_size=75):		# 给予默认值75
		"""初始化电瓶属性"""
		self.battery_size = battery_size

	def describe_battery(self):
		"""打印一条描述电瓶容量的信息"""
		print(f"This car has a {self.battery_size}-kwh battery.")


class ElectricCar(Car):
	"""电动汽车的独特之处"""
	def __init__(self, make, model, year):
		"""
		初始化父类的的属性
		在初始化电动汽车独有属性
		"""
		super().__init__(make, model, year)
		self.battery = Battery()		# 将类用作另一个类的属性


my_tesla = ElectricCar('tesla', 's', 2018)

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

2018 Tesla S
This car has a 75-kwh battery.


5.导入类

将 Car 类存储在一个名为 car.py 的模块中(只包含类的相关内容),在文件开头包含一个模块级的文档字符串。

  • 从一个模块中导入多个类
    from car import Car, ElectricCar
  • 导入整个模块
    import car
    此做法调用函数时需要用句点式,如car.Car()访问 Car 类。
  • 导入模块中所有类(不建议)
    from car import *
    可能会出现名称方面冲突的情况。
  • 在模块中导入另一个模块
    当一个模块中的类依赖与另一个模块中的类,可在前一个模块中导入必要的类。
    from car import Car

6.python标准库

模块 random 的两个函数 random()choie()

  • 函数 random()
    它将两个整数作为参数,并随机返回一个位于这两个整数之间(含)的整数。

>>> from random import randint
>>> randint(1,6)
3


  • 函数 choie()
    它将一个列表或元组作为参数,并随机返回其中的一个元素。

>>> from random import choice
>>> palyers = [‘s’, ‘a’, ‘r’, ‘h’, ‘p’]
>>> choice(palyers)
‘s’


十、文件与异常

1. 从文件中读取数据

1.1读取整个文件

首先创建一个文件( pi_digits.txt ),然后在程序中使用 open() 函数。

3.1415926535  
  8979323846  
  2643383279  
with open('pi_digits.txt') as f:
	contents = f.read()
print(contents)

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

关键字 with 在不再需要访问文件后将其关闭。

结果:

3.1415926535  
  8979323846  
  2643383279    
  

相比与原始文件,该输出唯一不同的地方是末尾多了一个空行。因为 read() 到达文件末尾时返回一个空字符串,而将这个空字符串显示出来时就是一个空行。要删除空行,可在函数调用 print() 中使用 rstrip()

print(contents.rstrip())

1.2文件路径

程序文件存储在了文件夹 python_work 中,而在该文件夹中有一个名为 text_files 的文件夹用于存储程序文件操作的文本文件。

  • with open('text_files/filename.py') as file_object

这行代码可让 python 在文件夹 python_work 下的文件夹 text_files 中去查找指定的 .txt 文件。

注意:显示文件路径时,Windows 系统使用反斜杠(\)而不是斜杠(/),但在代码中依然可以使用斜杠。

将文件在计算机中的准确位置告诉 python ,这样就不用关心当前运行的程序存储在什么地方了,这称为绝对文件路径。通过使用绝对路径,可读取系统中任何地方的文件。

注意:如果在文件路径中使用反斜杠,将可能引发错误,因为反斜杠用于对字符串中的字符进行转义。

1.3逐行读取

with open('pi_digits.txt') as f:
	for line in f:
		print(line)
3.1415926535  
     
  8979323846  
    
  2643383279  
     

打印每一行时,发现空白行更多了。因为在这个文件中,每行末尾都有一个看不见的换行符,而函数 print() 也会加上一个换行符,相当与有两个换行符。要消除多余的空白行,可在函数调用 print() 中使用 rstrip()

print(line.rstrip())

3.1415926535  
  8979323846  
  2643383279  

1.4创建一个包含文件各行内容的列表

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

方法 readlines() 从文件中读取每一行,并将其存储在一个列表中。

filename = 'pi_digits.txt'
with open(filename) as f:
	lines = f.readlines()

for line in lines:
	print(line.rstrip())

1.5使用文件的内容

filename = 'pi_digits.txt'
with open(filename) as f:
	lines = f.readlines()

pi_string = ''
for line in lines:
	pi_string += line.strip()

print(pi_string)
print(len(pi_string))

3.141592653589793238462643383279
32


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

2. 写入文件

2.1写入空文件

filename = 'programming.txt'
with open(filename, 'w') as f:
	f.write("I love programming.")

本例中,调用 open() 时提供两个参数。第一个实参是文件名称,第二个实参(‘w’)告诉python要以写入模式打开这个文件。

如果文件不存在,函数 open() 将自动创建它。
如果文件已存在,python 将在返回文件对象前清空该文件的内容。

模式字母
读取模式r
写入模式w
附加模式a
读写模式r+

如果省略了模式实参,将以默认的只读模式打开文件。

2.2写入多行

函数 write() 不会在写入的文本末尾添加换行符,需要在方法调用时包含换行符。

filename = 'programming.txt'
with open(filename, 'w') as f:
	f.write("I love programming.\n")
	f.write("I love creating new games.\n")

在文件 programming.txt 查看


I love programming.
I love creating new games.


2.3附加到文件

如果要给文件添加内容,而不是覆盖原有的内容,可以以附加模式打开文件。如果指定的文件不存在,将自动创建一个空文件。

filename = 'programming.txt'
with open(filename, 'a') as f:
	f.write("I also love finding meaning in large datasets.\n")
	f.write("balabala\n")

在文件 programming.txt 查看


I love programming.
I love creating new games.
I also love finding meaning in large datasets.
balabala


3.异常

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

异常是使用 try—except 代码块处理的。 try—except 代码块让 python 执行指定的操作,同时告诉 python 发生异常时怎么办。使用 try—except 代码块时,即便出现异常,程序也将继续运行。

3.1处理异常

  • ZeroDivisionError 异常

print(5/0)

Traceback (most recent call last):  
  File "D:\work_python\text.py", line 1, in <module>    
    print(5/0)    
ZeroDivisionError: division by zero     

  • FileNotFoundError 异常
filename = "alice.txt"

with open(filename) as f:
    content = f.read()
Traceback (most recent call last):
  File "D:\work_python\text.py", line 3, in <module>
    with open(filename) as f:
FileNotFoundError: [Errno 2] No such file or directory: 'alice.txt'
  • 使用 try—except 代码块
try:
    print(5/0)
except ZeroDivisionError:
    print("You can't divide by zero!")

You can’t divide by zero!


3.2 else 代码块

print("Give me two numbers, and I'll divide them.")
print("Enter 'q' to quit.")

while True:
    first_number = input("First number:")
    if first_number == 'q':
        break
    second_number = input("Second number:")
    if second_number == 'q':
        break

    try:
        answer = int(first_number)/int(second_number)
    except ZeroDivisionError:
        print("You can't divide by zero!")
    else:
        print(answer)

在本例中,如果除法运算成功,就使用 else 代码块来打印结果。如果第二个数输入零,不会出现 trackback 的情况,程序继续运行,避免崩溃。


Give me two numbers, and I’ll divide them.
Enter ‘q’ to quit.
First number:5
Second number:2
2.5
First number:9
Second number:0
You can’t divide by zero!
First number:8
Second number:2
4.0
First number:q


3.3静默失败

有时候希望程序发生异常时保持静默,就像什么都没发生一样继续运行。在 except 代码块中明确告诉python什么都不要做(使用 pass 语句)。

pass 语句还充当了占位符,提醒你在某个地方什么都没做,并且以后也许在这里做些什么。

try:
	--snip--
except FileNotFoundError:
	pass

4.存储数据

用户关闭程序时,几乎总是要保持他们提供的信息。一种简单的方式是使用 json 来存储数据。

JSON(JavaScript Object Notation)格式最初是为 JavaScript 开发的,但随后成了一种常见格式,被包括 Python 在内的众多语言采用。

4.1 使用 json.dump()json.load()

函数 json.dump() 接受两个实参:要存储的数据,以及可用于存储数据的文件对象。
通常使用的**文件扩展名 .json **来指出文件存储的数据为 JSON 格式。

import json

numbers = [1, 2, 3, 5]

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

这个程序没有输出,但可以打开 numbers.json 文件查看内容。
数据的存储格式与 Python 中一样。


[1, 2, 3, 5]


下面再编写一个函数,使用 json.load() 将列表读取到内存中:

import json

filename = 'numbers.json'
with open(filename) as f:
    numbers = json.load(f)

print(numbers)

[1, 2, 3, 5]


这是一种在程序之间共享数据的简单方式。

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

import json

# 如果以前存储了用户名,就加载它,并用 else 语句打印出来;
# 否则,提示用户输入用户名并存储它。
filename = 'username.json'
try:
    with open(filename) as f:
        username = json.load(f)
except FileNotFoundError:
    username = input("What is your name? ")
    with open(filename, 'w') as f:
        json.dump(username, f)
        print(f"We'll remember you when you come back, {username}")
else:
    print(f"Welcome back, {username}")

无论是执行的是 except 还是 else 代码块,都会显示用户名和合适的问候语。

用户名存储过:


What is your name? json
We’ll remember you when you come back, json


用户名存储过了:(这是程序至少运行过一次时的输出)


Welcome back, json


4.3 重构

代码能够正确地运行,但通过将其划分为一系列完成具体工作的函数,还可以改进。这样的过程称为重构。重构让代码更清晰、更易于理解、更容易扩展。

在这个最终版中,每一个函数都执行单一而清晰的任务。

import json

filename = 'username.json'


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


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


def greet_user():
    """问候用户,并指出其名字"""
    username = get_stored_username()    # 获取文件 username.json 中的数据
    if username:                        # 用户存储过
        print(f"Welcome back, {username}")
    else:                               # 用户没存储过
        username = get_new_username()   # 调用函数录入用户名
        print(f"We'll remember you when you come back, {username}")


greet_user()
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值