《Python编程从入门到实践》笔记吐血整理

本笔记基于Eric Matthes著的 《Python编程从入门到实践》 整理而成。
书中习题答案可在 https://www.ituring.com.cn/book/1861 下载

1 起步

Python安装

  • 官网下载慢:国内镜像源,比如阿里的。http://npm.taobao.org/mirrors/python/
  • 环境配置:我最后选择了 vscode + Python插件,搜索vscode python安装即可。

运行

  • 新建应选择main.py
  • SyntaxError: Non-UTF-8 code starting with ‘\xb9’ in file 练习.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details:编码错误,文档/设置文档编码/Unicode/UTF-8仅变量可以
  • SyntaxError: invalid character in identifier:可能夹杂中文输入法标点(仅有变量和字符串可用汉字)

2 变量和简单数据类型

命名

  • 首字母大写…title() 全部大写.upper() 全部小写.lower()
  • \t制表符 \n换行符(在字符串内)
  • 去除变量中字符串的空格.strip() 字符前端空格.lstrip() 后端空格rstrip()

引号

  • 字符串引号单双无所谓,但不能与字符串中撇号或者引号冲突

数字

  • 浮点数产生原因:小数点后数字无法使用二进制完全表示,只能采取近似运算,由此产生不同算法
  • 数字变量需要明确为字符串,使用函数.str()

注释

  • 单行使用#,python会自动屏蔽这行内容,以此来进行注释
  • 多行使用"“”,即三引号,python会识别为一个字符串

3 列表简介

列表是什么

列表由一系列按特定顺序排列的元素组成

格式:

Bicycles = ['trek', 'cannondale', 'redline', 'specialized']
Print(Bicyles)

索引

  • Print(Bycycle[0]) 注意索引都是从0开始
  • [-1]为最后一个列表元素,类推

修改、添加、删除

  • 修改:给列表中的元素赋值
  • 插入:
list.append(element) 列表末尾添加元素
list.insert(location,element)
  • 删除
del list[location]
list.pop(location) 弹出末尾元素并且使用
list.remove(element) 删除列表中第一个该值,也可以使用

组织列表

  • 永久性排序:list.sort(),可用reverse=True参数反向排序
  • 临时性排序:sorted(list) ,可用reverse=True参数反向排序
  • 翻转列表排序(永久):list.reverse()
  • 列表长度:len(list) 可得知列表有几个元素

避免索引错误

  • 差1错误:索引从0开始

4 操作列表

遍历整个列表

  • For循环:for item in list_of_items:(注意该冒号不能少)
  • 缩进错误:IndentationError

创建数字列表

  • 函数range(start_number,end_number(,step))
    • 注意此处存在差1,如输入range(1,5)只会输出[1,2,3,4]
  • 生成列表的方法:
Numbers=list(range())
Squares=[]
For value in range(1,11):
Squares.append(value**2)

等同于

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

使用列表的一部分:切片

Players=[]
Print(players[1,3])
Print(players[:4]) # 表示从第一个元素到第五个元素
Print(players[4:]) # 表示从第5个元素到最后一个元素

遍历切片:使用for循环
复制列表:注意列表不能进行赋值,要将列表作为切片复制给列表变量名

Foods = vegetable[:]

元组(不可变的列表) tuple

  • 使用圆括号
dimension = (200,50)
  • 索引时还是使用方括号如:
print( dimension[0] )
  • 不能更改单一元素,唯一办法是对整个元组赋值
dimension = (300, 100)

5 If

实例

cars = ['bmw', 'audi', 'toyota']
for car in cars # cars记录了车企名字的list
    if car == 'bmw'
        ...
    elif:
        ...
    else:
        ...

条件测试

  • 相等==

  • 不相等!=

  • 其余<, >, <=, >=

  • 与,或:and, or

  • 关键字in检查是否特定值是否在列表中

'suzuki' in cars
False
  • 同理关键字 not in 检查是否不再列表内

使用if语句处理列表

可以实现的功能:

  • 确定元素是否在列表中
  • 确定列表是否为空
  • 使用多个列表,判断一个列表的元素是否在另一个列表中

6 字典

一个例子

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

print(alien['color'])
print(alien['points'])

返回结果如下:

green
5

使用字典

什么是字典:一系列 key - value 的对应。
由上述例子可以看出,由大括号{}表示一个字典,‘key’来给一个关键字命名,’:‘来对应key 和 value,’,'来表示并列的关键字

在引用时,我们使用"dictionary[‘key’]"来引用关键字key。

添加键值对

直接使用赋值,关键字将自动在字典内创建。

alien['x_position'] = 0
alien['y_position'] = 100

可以通过先创建一个空字典,再向其中添加键值对。

修改字典中的值

同样是通过赋值语句

删除键值对

通过del语句实现

del alien['x_position']

遍历字典

使用for语句,格式如下

user = {
    'username' = 'Yilin',
    'regist_date' = '2022.07.06',
    'major' = 'physics'

for key, value in user.items():
    print("\nKey" + key)
    print("Value: " + value)
}

得到的输出为:

Key: username
Value: Yilin

Key: regist_date
Value: 2022.07.06

Key: major
Value: physics

可以看出,探测键值对是否在字典中,通过key和key对应的value值来进行判断,同时还需要在字典名后加上.item()。

值得注意的是,这个方法遍历输出的键值对顺序与存储顺序不一定相同,具体原因是因为python使用散列表(哈希表)来存储。

遍历所有键keys()

for name in user.keys():
    print(name)

key()对于不需要value时能够很好地使用。在for 和 in 中间使用单个变量名,同样能够实现只输出key的效果,使用.keys()只是能够增加可读性

按顺序遍历字典中的所有键

使用sorted()

for name in sorted(favorite_languages.keys()):
    print(name.title() + ", thank you for taking the poll.")

遍历所有值values()

for language in favorite_languages.values():
    print(language.title())

这条语句能够提取字典中所有的值,但是不能判断是否重复,为了简便性,我们一般还使用set()来剔除重复项

for language in set(favourite_languages.values()):
    print(language.title())

嵌套

考虑以下情况:

  • 将列表作为值存储在字典中
  • 将一系列字典存储在列表中

这就是为什么我们需要 嵌套

将字典放入列表

for alien_number in range(30):
    new_alien = {'color': 'green', 'point': 5, 'speed': 'slow'}
    aliens.append(new_alien)

将列表放入字典

pizza = {
    'crust': 'thick',
    'toppings': ['mushrooms', 'extra cheese'],
}

将字典放入字典

这么做真的很酷hhh

users = {
    'aeinstein': {
        'first': 'albert',
        'last': 'einstein',
        'location': 'princeton',
    }
    'mcurie': {
        'first': 'marie',
        'last': 'curie',
        'location': 'paris',
    }
}

7 用户输入和while循环

7.1 input()的工作原理

在括号内输入文字提示

message = input("Tell me something, and I will repeat it back to you: ")
print(message)
  • int()获取数值输入
height = input("How tall are you, in inches?")
height = int(height)

7.2 while循环

不断运行直到不满足条件

number = 1
while number <= 5:
    print(number)
    number += 1

使用tag

当有多个条件作为while语句停止运行的条件是,使用一长串 and 是一件很繁琐的事情。此时可以使用tag作为统一的退出条件。

active = True # 布尔变量作为tag
while active:
    message = input(prompt)

    if message == 'quit':
        active = False
    else:
        print(message)

使用break退出循环

break使python立刻跳出整个循环,不在执行。可以用于while,for。

类似的表达在C里也有,此时可以不用考虑while处的条件判断语句。

while True:
    message = input(prompt)

    if message == 'quit':
        break
    else:
        print(message)

在循环中使用continue

continue可以使python跳出当前的循环,并且立即执行下一个循环。

current_number = 0
while current_number < 10:
    current_number += 1
    if current_number % 2 == 0:
        continue

    print(current_number)

避免无限的循环

总结上述结束循环的方式,有如下几种:

  • while处的条件语句配合递增或者递减的语句如number += 1
  • 使用布尔变量作为tag来简化多条件退出循环的语句
  • 使用break跳出整个循环
  • 使用continue跳出当前循环并且执行下一次循环

7.3 使用while循环来处理列表和字典

能够实现的操作:

  • 在列表之间移动元素.pop()
  • 删除包含特定值的所有列表元素.remove()
  • 使用用户输入来填充字典input()和字典操作

8 函数

8.1 定义函数

定义函数和调用函数的基本语法

def greet_user():
    """问候"""
    print("Hello!")

greet_user()

向函数传递信息

注意形参和实参的关系,比如有这么一条语句

name = 'Amy'

那么如果我们调用一个函数

show_name(name)
show_name('Amy')

那么第一行就调用了形参,第二行调用了实参。
具体关于实参和形参的定义请自行搜索。

8.2 传递实参

位置实参

在函数中预先定义的变量(形参)需要与实际信息(实参)进行对应,这种关联方式基于实参的顺序
比如:

def describe_pet(animal_type, pet_name):
    print(pet_name.title() + " is a " + animal_type + ".")

describe_pet('dog', 'wangcai')
describe_pet('wangcai', 'dog')

你希望旺财是一只狗,而不是狗是一只旺财,因此调用函数需要采用第一种调用方式。
这体现了位置实参的顺序十分重要。

关键字实参

可以直接将输入的实参与形参对应起来,这样顺序就不那么重要了。
下面两行代码是等价的:

describe_pet(animal_type = 'dog', pet_name = 'wangcai')
describe_pet(pet_name = 'wangcai', animal_type = 'dog')

默认值

可以通过在定义函数时就加入形参的默认值,在没有输入指定形参时python会自动用默认值代替。

def describe_pet(animal_type = 'dog', pet_name):
    print(pet_name.title() + " is a " + animal_type + ".")

describe_pet('wangcai')

混合调用

基于上述的三种方式,可以实现不同的函数调用方式。

8.3 返回值

返回简单值

def get_formatted_name(first_name, last_name):
    full_name = first_name + ' ' + last_name
    return full_name.title()

musician = get_formatted_name('jimi', 'hendrix')
print(musician)

可以看出,这里函数返回了字符串full_name,同时通过调用函数将full_name赋值给了musician,因此能够通过print将该字符串输出。

实参变为可选

如果存在中间名,我们需要输出;但是不是所有人都有中间名,因此我们将中间名的默认值设为一个空串。

def get_formatted_name(first_name, middle_name="", last_name):
    full_name = first_name + ' ' + middle_name + ' ' + last_name
    return full_name.title()

或者使用if语句来判断实参非默认值

def get_formatted_name(first_name, middle_name="", last_name):
    if middle_name:
        full_name = first_name + ' ' + middle_name + ' ' + last_name
    else:
        full_name = first_name + ' ' + last_name
    return full_name.title()

返回字典

def build_person(first_name, last_name):
    person = {
        'first' = first_name,
        'last' = last_name,
    }
    return person

8.4 传递列表

python能够将列表作为参数传递给函数,我们可以在函数内实现列表的遍历等操作,以此实现大量数据的处理

def greet_users(names):
    for name in names:
        msg = "Hello, " + name.title() + " !"
        print(msg)

但是记住只有while能够对列表进行修改,此时修改其中内容需要用到最原始的 list_name[n] = xxxx 来实现

在函数中修改列表

这里就不再赘述列表修改的操作了,具体操作可以看前面几章的笔记

禁止函数修改列表

可以在函数调用的时候使用列表的切片

print_models(unprinted_design[:], completed_models)

对于大型的列表尽量使用原始列表,这样能够节省创建切片时产生的内存和时间占用。

8.5 传递任意数量的实参

对于预先未知数量的实参,可以在形参名上加一个’*'。星号的作用是让python创建一个空元组,将所有输入的实参封装到 元组

def make_pizza(*toppings):
    print(toppings)

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

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

在同时使用位置实参和任意数量实参时,我们需要将任意数量实参放在函数的最后。

def make_pizza(size, *toppings)

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

在参数前面加上两个星号’**',python能够创造一个空字典,以接受关键字实参(键值对)

def occupation(**people):
    """录入人的职业"""
    profile = {}
    for name, career in people:
        profile['name'] = career

# 调用格式
occupation(Amy='programer', david='singer')

8.6 将函数存储在模块中

python可以导入其他存储为.py文件的函数模块。现在假设命名为pizza.py的文件里存储了一个名为make_pizza()的函数

  • 导入整个模块
import pizza # 导入模块

pizza.make_pizza() # 模块中函数的调用格式

然后能够使用as给模块改名字

import pizza as p

p.make_pizza()

同样我们能够只导入模块中的单个或多个函数, 此时调用不需要模块的前缀,如:

from pizza import make_pizza(), eat_pizza()

make_pizza()
eat_pizza()

导入模块的所有函数使用’*’

from pizza import *

make_pizza()
eat_pizza()

注意:

  • 导入的模块和主程序需要在一个文件夹当中
  • 导入大量的函数可能造成函数重名,python将会覆盖已有的函数。最佳做法是导入少量函数或者直接导入整个模块使用前缀。

9 类 Class

实用类创建对象,定义的一大类对象都拥有通用的行为,然后根据需要赋予每个个体独立的特性。类传递了 面向对象编程 的理念。

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!")
  • 规定类的名称首字母大写,Dog()
  • 类中的函数称为方法,所有第8章函数定义方式都适用,区别在于调用的方式
my_dog = Dog('wangcai', 4) # 初始化my_dog

my_dog.sit()
my_dog.roll_over()

9.2 使用类和实例

添加属性的默认值,如下文中odometer_reading = 0

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):
            ...

        def read_odometer(self):
            print("This car has " + str(self.odometer_reading) + " miles on it")
  1. 直接修改属性的值
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())

my_new_car.odometer_reading = 23 # 更新里程表的公里数
my_new_car.read_odometer()
  1. 通过方法修改属性的值
    通过在class创建方法来进行属性的更新
class Car():
    ...

    def update_odometer(self, mileage):
        if mileage >= self.odometer_reading:
            """防止回调"""
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer.")
  1. 通过方法对属性的值进行递增
class Car():
    ...

    def increment_odometer(self, miles):
        self.odometer_reading += miles

9.3 继承

编写类(子类)时,可以从已有的类(父类) 继承 其所有的属性和方法,同时能够定义自己特殊的属性和方法 。

给子类定义属性和方法

class ElectricCar(Car):
    def __init__(self, make, model, year):
        """初始化父类的属性"""
        super().__init__(make, model, year) # 关联父类和子类,注意没有参数self
        self.battery_size = 70 # 添加ElectricCar的独特属性

    def describe_battery(self):
        """属于ElectricCar的方法"""
        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

super()函数能够帮助python把父类和子类关联起来,让ElectricCar包含父类的所有属性。

重写父类的方法

如果父类中的方法不适用于子类,可以创建同名方法来进行覆盖。

将实例作为属性

在扩充类的属性和方法时,可以通过将某些小类将大类进行拆分。

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() # 将电池的属性初始化为一个类Battery()


my_tesla = ElectricCar('tesla', 'model s', 2016)

print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery() # 调用Battery()中的方法

9.4 导入类

我们假设我们将class存储到了名为file_name的模块中

导入类

from file_name import Class_name1, Class_name2

导入整个模块

import file_name

为了防止某一个模块过大,我们可以通过在模块中导入类的方式来避免这个问题,也就是说,我们可以在模块中导入模块。

9.5 Python标准库

python自带的默认库

10 文件和异常

10.1 从文件中读取数据

读取整个文件

假设有一个名为pi_digit.txt的文件存储了圆周率的值,我们通过python程序能够进行以下操作:

  • 打开文件 open()
  • 阅读文件内容 .read()
  • 关闭文件 close() 但可以用with代替
with open('pi_digit.txt') as file_object:
    contents = file_objects.read()
    print(contents.rstrip())

以上代码说的是,打开一个名为pi_digit.txt的文件,将文件赋值给变量file_object。然后通过.read()函数获取文件内容。最后使用print进行输出。
这个过程需要注意以下几点:

  • with的作用是让python自动选择什么时候进行文件的关闭,因此没有必要使用close()
  • .read()会在阅读到最后时返回一个空字符串,因此输出会多一个空行。解决这个问题使用.rstrip(),即删除末端空格。

文件路径

上述方法只适用于文件存储在同一个文件夹的同一级下。方法分为绝对路径和相对路径,这里我认为绝对路径能够解决所有问题,直接把文件路径在文件资源管理器中找到并复制即可。

file_path = 'C:\user\ehmatthes\other_files\text_files\file_name'
with open(file_path) as file_object:

逐行读取

with open(file_name) as file_object:
    for line in file_object:
        print(line.rstrip())

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

文件内容只能够在with代码块中可用,要对于文件进行处理,可以创建一个列表来将文件存储在其中。

with open(file_name) as file_object:
    lines = file_object.readlines()

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

方法readlines()能够将每一行分别作为字符串存储在列表当中。

10.2 写入文件

在open()中存在第二个实参:

  • ‘r’ 只读
  • ‘w’ 写入,会自动创建不存在的文件名,会自动覆盖同名文件
  • ‘a’ 添加, 在已有内容后进行写入
  • ‘r+’ 读取和写入
    其中默认值是只读。

写入空文件

with open(file_name, 'w') as file_object:
    file_object.write("I love programming.\n") # 写入时需要手动换行
    file_object.write("I love creating new games.")

附加到文件

在上述写入空文件的例子中,将实参改为’a’即可。

一些报错的原因

在做练习的时候,遇见了许多问题:
1.

FileNotFoundError: [Errno 2] No such file or directory: 'learning_python'

VScode使用的终端,默认文件位置是python的默认位置,而不是程序文件的位置,所以要使用绝对引用。

UnicodeDecodeError: 'gbk' codec can't decode byte 0x81 in position 89: incomplete multibyte sequence

python读取文件路径时默认使用ASCII,若是保存路径中存在中文会报错,在open时可以添加如下属性:

with open(path, encoding='utf-8') as file_object:
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape

字符串中的’‘会引起转义,可在字符串前面(外面)加上’r’

path = r"C:\Users\linli\Desktop\Python_work\10.文件和异常\learning_python.txt"
file_name = input("Please enter your name: ")
path = r"C:\Users\linli\Desktop\Python_work\10.文件和异常"
path += r"\" + file_name + ".txt"                          # 这一行出错

with open(path, 'w', encoding='utf-8') as file_object:
    file_object.write(file_name)

运行时错误如下:

SyntaxError: EOL while scanning string literal

解决:python不支持将\作为字符串最后一个字符,即使加了r。因此方法应该如下:

path += "\\" + file_name + ".txt"

10.3 异常

为了避免程序在错误时停止,同时出现难以理解的traceback,我们可以通过try-expect-else代码块使程序继续运行,同时显示友好的提示。
例如,在进行除法运算时,可能会出现ZeroDivisionError异常,处理方式如下:

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

while True:
    first_number = input("\nfirst number: ")
    if first_number == 'q':
        break
    second_number = input("\nsecond number: ")
    if second_number == 'q':
        break
    
    try:
        answer = int(first_number) / int(second_number)
    except ZeroDivisionError:
        print("You can't divide by 0!")
    else:
        print(answer)

如果希望在出错时不进行任何操作,可以使用pass语句

    try:
        answer = int(first_number) / int(second_number)
    except ZeroDivisionError:
        pass                              # 跳过错误
    else:
        print(answer)

10.4 存储数据

使用模块json(JavaScript Object Notation)来存储数据:
json能够将简单的python数据结构转存到文件中,并在程序再次运行时加载该文件中的数据。你还可以使用json在Python程序或者其他语言之间分享数据。

使用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()将这个列表读取到内存中(从json文件中提取数据并进行使用)

import json

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

print(numbers)

11 测试代码

使用Python标准库中的模块unitest来测试函数的稳定性和各种可能的使用方式。
如果各位有书的话,书上有详尽的unitest使用方法,这里就不在赘述了。

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