摘录自Python编程:从入门到实践
1. 变量和简单数据类型
变量规范:
- 变量只能包含字母、数字和下划线,但不能以数字开头;
- 变量名不能包含空格;
- 不要使用python关键字和函数名作为变量名。
#字符串 name = "ada LoveLace" print(name.title())#title()用于大写首字母(未改变原字符串) print(name.upper())#upper()用于大写全部字母 print(name.lower())#lower()用于小写全部字母
Python使用加号(+)来合并字符串。
Python能够找出字符串开头和末尾多余的空白。要确保字符串末尾没有空白,可使用方法rstrip()。你还可以剔除字符串开头的空白,或同时剔除字符串两端的空白。为此,可分别使用方法lstrip()和strip()。
Python使用两个乘号表示乘方运算。
str()函数:
#强转字符型 age = 23 message = "Happy " + str(age) + "rd Birthday!" print(message)
2. 列表
2.1 基本操作
列表由一系列按特定顺序排列的元素组成,其中的元素之间可以没有任何关系。
colors = ['blue', 'yellow', 'green', 'red'] colors.append('black')#向列表末尾加入新元素(改变了原列表) colors.insert(0,'white')#向列表中插入新元素 del colors[0]#通过索引删除元素 popped_colors = colors.pop()#pop弹出列表中的元素,无参数则弹出列表最后一个元素 colors.remove('blue')#删除指定元素
实际上,你可以使用pop()来删除列表中任何位置的元素,只需在括号中指定要删除的元素的索引即可。
2.2 列表排序
使用方法sort()对列表进行永久性排序,只需向sort()方法传递参数reverse=True,就可以按与字母顺序相反的顺序排列列表元素。
使用函数sorted()对列表进行临时排序,也可向函数sorted()传递参数reverse=True。
要(永久性地)反转列表元素的排列顺序,可使用方法reverse()。
使用函数len()可快速获悉列表的长度。
2.3 遍历列表
magicians = ['alice', 'david', 'carolina'] for magician in magicians: print(magician)
alice david carolina
2.4 数值列表
numbers = list(range(1,6)) print(numbers)
[1, 2, 3, 4, 5]
squares = [] for value in range(1,6): square = value**2 squares.append(square) print(squares)
[1, 4, 9, 16, 25]
列表解析:(只需一行代码)
squares = [value**2 for value in range(1,6)]
2.5 切片
- [0:2]:前两个;
- [:4]:没有指定起始索引,从列表开头开始;
- [-3:]:最后3个元素。
- [:]:复制列表
- 直接复制实际上是让Python将新变量关联到原的列表,因此两个变量都指向同一个列表。
2.6 元组
元组看起来犹如列表,但使用圆括号而不是方括号来标识。定义元组后,就可以使用索引来访问其元素,就像访问列表元素一样。
dimensions = (200, 50) print(dimensions[0])
试图修改元组的操作是被禁止的,因此Python不能给元组的元素赋值。给元组变量整体赋值是合法的。
3. if语句
Python使用and和or表示与或关系。
要判断特定的值是否已包含在列表中,可使用关键字in。
elif是Python中的else if。
在if语句中将列表名用在条件表达式中时,Python将在列表至少包含一个元素时返回True,并在列表为空时返回False。
4. 字典
4.1 基本操作
在Python中,字典是一系列键——值对。每个键都与一个值相关联,你可以使用键来访问与之相关联的值。与键相关联的值可以是数字、字符串、列表乃至字典。事实上,可将任何Python对象用作字典中的值。
alien_0 = {'color': 'green', 'points': 5} print(alien_0['color'])
新增键值对:
alien_0['x_position'] = 0 alien_0['y_position'] = 25 print(alien_0)
使用del删除键值对。
4.2 遍历
user_0 = { 'username': 'efermi', 'first': 'enrico', 'last': 'fermi', } for key, value in user_0.items(): print(" Key: " + key) print("Value: " + value)
Python不关心键—值对的存储顺序,而只跟踪键和值之间的关联关系。
在不需要使用字典中的值时,方法keys()用于获取所有的键。使用方法values()可以返回一个值列表。
为剔除重复项,可使用集合(set)。集合类似于列表,但每个元素都必须是独一无二的。
5. 用户输入
函数input()让程序暂停运行,等待用户输入一些文本。获取用户输入后,Python将其存储在一个变量中,以方便后续使用。
message = input("Tell me something, and I will repeat it back to you: ") print(message)
为解决这个问题,可使用函数int(),它让Python将输入视为数值。
6. while循环
current_number = 1 while current_number <= 5: print(current_number) current_number += 1
要立即退出while循环,不再运行循环中余下的代码,也不管条件测试的结果如何,可使用break语句。
以while True打头的循环将不断运行,直到遇到break语句。
要返回到循环开头,并根据条件测试结果决定是否继续执行循环,可使用continue语句。
7. 函数
7.1 操作列表
将列表传递给函数后,函数就可对其进行修改。在函数中对这个列表所做的任何修改都可以是永久性的,这让你能够高效地处理大量的数据。
# 首先创建一个列表,其中包含一些要打印的设计 unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron'] completed_models = [] # 模拟打印每个设计,直到没有未打印的设计为止 # 打印每个设计后,都将其移到列表completed_models中 while unprinted_designs: current_design = unprinted_designs.pop() #模拟根据设计制作3D打印模型的过程 print("Printing model: " + current_design) completed_models.append(current_design) # 显示打印好的所有模型 print(" The following models have been printed:") for completed_model in completed_models: print(completed_model)
有时候,需要禁止函数修改列表。此时可向函数传递列表的副本而不是原件;这样函数所做的任何修改都只影响副本,而丝毫不影响原件。
要将列表的副本传递给函数,可以像下面这样做:
function_name(list_name[:])
7.2 任意实参
有时候,你预先不知道函数需要接受多少个实参,好在Python允许函数从调用语句中收集任意数量的实参。
def make_pizza(size, *toppings): """概述要制作的比萨""" print(" Making a " + str(size) + "-inch pizza with the following toppings:") for topping in toppings: print("- " + topping) make_pizza(16, 'pepperoni') make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
Making a 16-inch pizza with the following toppings: - pepperoni Making a 12-inch pizza with the following toppings: - mushrooms - green peppers - extra cheese
形参名*toppings中的星号让Python创建一个名为toppings的空元组,并将收到的所有值都封装到这个元组中。
有时候,需要接受任意数量的实参,但预先不知道传递给函数的会是什么样的信息。
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)
{'first_name': 'albert', 'last_name': 'einstein', 'location': 'princeton', 'field': 'physics'}
7.3 存储在模块中
要让函数是可导入的,得先创建模块。模块是扩展名为.py的文件,包含要导入到程序中的代码。
import module_name
import module_name as mn
from module_name import function_name
from module_name import function_name as fn
from module_name import *
所有的import语句都应放在文件开头,唯一例外的情形是,在文件开头使用了注释来描述整个程序。
9. 类
9.1 创建和使用类
class Dog(): """一次模拟小狗的简单尝试""" def __init__(self, name, age): """初始化属性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__()
类中的函数称为方法。__init__()是一个特殊的方法,每当你根据Dog类创建新实例时,Python都会自动运行它。方法__init__()定义包含三个形参:self、name和age。在这个方法的定义中,形参self必不可少,还必须位于其他形参的前面。
以self为前缀的变量都可供类中的所有方法使用,我们还可以通过类的任何实例来访问这些变量。
my_dog = Dog('willie', 6) print("My dog's name is " + my_dog.name.title() + ".") print("My dog is " + str(my_dog.age) + " years old.")
My dog's name is Willie. My dog is 6 years old.
要访问实例的属性,可使用句点表示法。
根据Dog类创建实例后,就可以使用句点表示法来调用Dog类中定义的任何方法。
my_dog.sit()
my_dog.roll_over()
Willie is now sitting. Willie rolled over!
9.2 继承
创建子类的实例时,Python首先需要完成的任务是给父类的所有属性赋值。为此,子类的方法__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 = str(self.year) + ' ' + self.make + ' ' + self.model return long_name.title() def read_odometer(self): print("This car has " + str(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): """Represent aspects of a car, specific to electric vehicles.""" def __init__(self, make, model, year): """ 电动汽车的独特之处 初始化父类的属性,再初始化电动汽车特有的属性 """ super().__init__(make, model, year) self.battery_size = 70 def describe_battery(self): """打印一条描述电瓶容量的消息""" print("This car has a " + str(self.battery_size) + "-kWh battery.") my_tesla = ElectricCar('tesla', 'model s', 2016) print(my_tesla.get_descriptive_name()) my_tesla.describe_battery()
2016 Tesla Model S This car has a 70-kWh battery.
super()是一个特殊函数,帮助Python将父类和子类关联起来。这行代码让Python调用ElectricCar的父类的方法__init__(),让ElectricCar实例包含父类的所有属性。父类也称为超类(superclass),名称super因此而得名。
让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。
对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名。这样,Python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。
使用代码模拟实物时,你可能会发现自己给类添加的细节越来越多:属性和方法清单以及文件都越来越长。在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。你可以将大型类拆分成多个协同工作的小类。
class Battery(): """一次模拟电动汽车电瓶的简单尝试""" def __init__(self, battery_size=70): """初始化电瓶的属性""" self.battery_size = battery_size def describe_battery(self): """打印一条描述电瓶容量的消息""" print("This car has a " + str(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', 'model s', 2016) my_tesla.battery.describe_battery()
This car has a 70-kWh battery.
类可以从文件导入。
类名应采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线。
10. 文件和异常
10.1 从文件读取数据
with open('pi_digits.txt') as file_object: contents = file_object.read() print(contents)
关键字with在不再需要访问文件后将其关闭。也可以调用open()和close()来打开和关闭文件,但这样做时,如果程序存在bug,导致close()语句未执行,文件将不会关闭。未妥善地关闭文件可能会导致数据丢失或受损。如果在程序中过早地调用close(),会导致更多的错误。通过使用前面所示的结构,可让Python去确定:你只管打开文件,并在需要时使用它,Python自会在合适的时候自动将其关闭。
逐行读取:
with open('pi_digits.txt') as file_object: for line in file_object: print(line.rstrip())
10.2 写入文件
保存数据的最简单的方式之一是将其写入到文件中。通过将输出写入文件,即便关闭包含程序输出的终端窗口,这些输出也依然存在:你可以在程序结束运行后查看这些输出,可与别人分享输出文件,还可编写程序来将这些输出再次读取到内存中并进行处理。
filename = 'programming.txt' with open(filename, 'w') as file_object: file_object.write("I love programming.")
Python只能将字符串写入文本文件。要将数值数据存储到文本文件中,必须先使用函数str()将其转换为字符串格式。
如果你要给文件添加内容,而不是覆盖原有的内容,可以附加模式'a'打开文件。你以附加模式打开文件时,Python不会在返回文件对象前清空文件,而你写入到文件的行都将添加到文件末尾。如果指定的文件不存在,Python将为你创建一个空文件。
10.3 异常
Python使用被称为异常的特殊对象来管理程序执行期间发生的错误。每当发生让Python不知所措的错误时,它都会创建一个异常对象。如果你编写了处理该异常的代码,程序将继续运行;如果你未对异常进行处理,程序将停止,并显示一个traceback,其中包含有关异常的报告。
1. ZeroDivisionError 异常
当你认为可能发生了错误时,可编写一个try-except代码块来处理可能引发的异常。你让Python尝试运行一些代码,并告诉它如果这些代码引发了指定的异常,该怎么办。
try: print(5/0) except ZeroDivisionError: print("You can't divide by zero!")
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: ") try: answer = int(first_number) / int(second_number) except ZeroDivisionError: print("You can't divide by 0!") else: print(answer)
2. FileNotFoundError 异常
使用文件时,一种常见的问题是找不到文件:你要查找的文件可能在其他地方、文件名可能不正确或者这个文件根本就不存在。对于所有这些情形,都可使用try-except代码块以直观的方式进行处理。
filename = 'alice.txt' try: with open(filename) as f_obj: contents = f_obj.read() except FileNotFoundError: msg = "Sorry, the file " + filename + " does not exist." print(msg)
方法split()以空格为分隔符将字符串分拆成多个部分,并将这些部分都存储到一个列表中。
有时候你希望程序在发生异常时一声不吭,就像什么都没有发生一样继续运行。要让程序在失败时一声不吭,可在except代码块中使用pass语句,让Python什么都不要做。
10.4 存储数据
很多程序都要求用户输入某种信息,如让用户存储游戏首选项或提供要可视化的数据。不管专注的是什么,程序都把用户提供的信息存储在列表和字典等数据结构中。用户关闭程序时,你几乎总是要保存他们提供的信息;一种简单的方式是使用模块json来存储数据。
JSON(JavaScript Object Notation)格式最初是为JavaScript开发的,但随后成了一种常见格式,被包括Python在内的众多语言采用。
使用json.dump()来存储数据,使用json.load()读取数据。
import json numbers = [2, 3, 5, 7, 11, 13] filename = 'numbers.json' with open(filename, 'w') as f_obj: json.dump(numbers, f_obj)
filename = 'numbers.json' with open(filename) as f_obj: numbers = json.load(f_obj) print(numbers)
11. 测试代码
11.1 测试函数
Python标准库中的模块unittest提供了代码测试工具。单元测试用于核实函数的某个方面没有问题;测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。
import unittest def get_formatted_name(first, last): """Generate a neatly formatted full name.""" full_name = first + ' ' + last return full_name.title() class NamesTestCase(unittest.TestCase): """测试name_function.py""" def test_first_last_name(self): """能够正确地处理像Janis Joplin这样的姓名吗?""" formatted_name = get_formatted_name('janis', 'joplin') self.assertEqual(formatted_name, 'Janis Joplin') unittest.main()
---------------------------------------------------------------------- Ran 1 test in 0.001s OK
创建一个类并继承unittest.TestCase类,这样Python才知道如何运行你编写的测试。
11.2 测试类
断言方法 | 用途 |
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中 |
import unittest 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 self.responses: print('- ' + self.response) class TestAnonmyousSurvey(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) unittest.main()
11.3 setUp()
import unittest class 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) def test_store_three_responses(self): """测试三个答案会被妥善地存储""" for response in self.responses: self.my_survey.store_response(response) for response in self.responses: self.assertIn(response, self.my_survey.responses) unittest.main()
unittest.TestCase类包含方法setUp(),让我们只需创建这些对象一次,并在每个测试方法中使用它们。
方法setUp()做了两件事情:创建一个调查对象;创建一个答案列表。存储这两样东西的变量名包含前缀self(即存储在属性中),因此可在这个类的任何地方使用。这让两个测试方法都更简单,因为它们都不用创建调查对象和答案。方法test_store_three_response()核实 self.responses 中的第一个答案——self.responses[0]—— 被妥善地存储,而方法test_store_three_response()核实self.responses中的全部三个答案都被妥善地存储。