python基础学习总结

python基础学习总结

总结Python基础,修改简化,一方面是作为未来遗忘时的参考;另一方面给看到的人一个学习的参考。

Github记录

零、编程与生活

首先,我们将生活中所有的问题称之为数据,那么理工科的研究在我看来便是研究不同数据的流通——数据本身或者数据之外。

而编程之于解决现实问题,便是对数据的高级操作,将外界的数据以“规范”的形式输入计算机进行处理。

在学习庞杂的知识时,数据线便是我把握知识主干的脉络,在此基础上不断丰富知识库,锻炼逻辑思维能力。

回到Python语言本身,将基础知识打碎重组,有了下面内容。

一、Python中数据是如何组织起来的

数值、字符串

数值

1、+ - * / 常规用法

2、括号用来分组

3、除法运算/返回浮点数类型。要返回整数类型用两个//

4、计算余数用%

5、使用**计算乘方

6、等号相当于给一个变量赋值

7、包含多种类型运算数结果以浮点数形式显示

8、交互模式下,上一次的表达时赋值给变量_

9、使用复数,后缀j 或者J表示虚数部分

字符串

1、使用'...' "..."表达字符串

2、反斜杠\用来转义

3、不转义在字符串前面加r :

r"..."

4、三重引号不像让回车包含到字符串中,在行尾加一个\

def doc_test():
    a = """\
    123 \
    456
    789
    """
    print(a)

5、字符串用+连接到一起,用*重复

6、相邻两个或多个字符串自动连在一起

a= 'p''c'
a
Out[3]: 'pc'

用在把很长的字符串分开输入的场合

7、字符串可以被索引和切片,访问第一个索引的位置是0,以此类推。:索引是获取单个字符串,切片是获取子字符串。

8、切片开始被包括在结果中,结束不被包括。

9、切片中越界索引会被自动处理

a = 'a123'
a[3:5]
Out[5]: '3'

10、字符串不能被修改,想要一个不同的字符串,方法是新建一个

11、使用内建函数len()返回一个字符串的长度

列表

基本

1、通过方括号括起、逗号隔开的一组元素得到;

2、列表支持索引、切片、拼接

3、列表的切片返回一个新的列表

4、列表的内容可以改变

  • 可以使用append方法添加新元素
  • 赋值不同切片的[]可以改变元素大小或者清空列表

5、内置函数len()可以作用到列表上

6、列表内可以嵌套列表

lst=[['a','b','c'], 3, 4]
lst[0][1]
Out[8]: 'b'
方法
list.append(x) 列表末尾添加一个元素
list.extend(iterable) 使用可迭代对象拓展列表
list.insert(i, x) 给定的位置插入一个元素
list.remove(x) 移除列表中第一个值为x的元素
list.pop([i]) 删除列表中指定位置的值并返回它,没有给位置默认是最后一个
list.clear() 移除列表中所有元素
list.index(x[,start[,end]]) 返回列表中值为x的索引,可选切片范围
list.count(x) 返回列表中x出现的次数
list.sort(*, key=None, reverse=False) 对列表元素进行排序,可自定义
list.reverse() 翻转列表中的元素
list.copy() 浅拷贝(关于深浅拷贝区别,浅拷贝是引用,当对于引用的值需要修改时,单独深拷贝。出现这种区别的原因在于资源的利用。举个例子,游戏开发中某一材质会被多个内容使用,但可能只有某一处需要修改材质参数值,这时候材质先都用浅拷贝,然后需要做出修改的部分用深拷贝。)

列表——>栈

添加用append(),取出用pop()

列表——>队列

使用collections.deque

列表推导

一种创建列表更简单的方法

1、创建一个新的列表,例如平方

2、使用条件过滤一些元素,例如取出大于等于0的

3、对所有元素使用一个函数处理

vec = [-4, -2, 0, 2, 4]
[x*2 for x in vec]
Out[3]: [-8, -4, 0, 4, 8]
[x for x in vec if x >= 0]
Out[4]: [0, 2, 4]
[abs(x) for x in vec]
Out[5]: [4, 2, 0, 2, 4]

4、 对每个元素使用方法

5、创建元组

6、改变数组的维度

freshfruit = [' banana', ' loganberry ', 'passion fruit ']
[weapon.strip() for weapon in freshfruit]
Out[7]: ['banana', 'loganberry', 'passion fruit']

[(x, x**2) for x in range(6)]
Out[8]: [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
    
vec = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[num for elem in vec for num in elem]
Out[10]: [1, 2, 3, 4, 5, 6, 7, 8, 9]

列表推导式可以使用复杂的表达式和嵌套函数

matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
# 将列表交换其行和列
[[row[i] for row in matrix] for i in range(4)]
Out[14]: [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
list(zip(*matrix))
Out[15]: [(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]

del语句

可以按照给定的索引移除一个元素,也可以删除整个变量。

元组

1、0个元素的元组直接()

2、1个元素的元组加,

3、元组可以打包和解包

t = 1, 2, 3
x, y, z = t
t
Out[18]: (1, 2, 3)
x
Out[19]: 1
y
Out[20]: 2
z
Out[21]: 3

4、元组与生成器表达式

# 生成器表达式
print("使用生成器表达式:", sum(i*i for i in range(10)))

字典

1、字典是键:值对的集合

2、字典的主要操作是使用关键字储存和解析值

3、对字典使用list()可以返回包含该字典中所有键的列表

4、循环中对字典使用items()方法可以将关键字和对应的值同时取出

函数

定义

1、用关键字def引入函数定义

2、第一个语句是文档字符串是一个很好的做法

3、函数的执行:引入一个用于函数局部变量的新符号表;变量引用首先在局部符号中寻找,然后在外层函数的局部符号表,再然后是全局符号表,最后是内置名称的符号表。

4、使用return从函数内部返回一个值。不指定返回值默认返回None

定义函数

def fib(n):
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a + b
    print()  # 空行

调用函数

if __name__ == '__main__':
    fib(100)
位置参数

定义时的值叫做形式参数,调用时的值叫做实际参数。

定义:

# 对一个或多个参数指定默认值
def ask_ok(prompt, retries=4, reminder='Please try again!'):
    while True:
        ok = input(prompt)
        if ok in ('y', 'ye', 'yes'):
            return True
        if ok in ('n', 'no', 'nop', 'nope'):
            return False
        retries = retries - 1
        if retries < 0:
            raise ValueError('invalid user response')
        print(reminder)

调用:

if __name__ == '__main__':
    # ask_ok函数的调用方法
    # ask_ok('Do you really want to quit?')  # 只给出必需的参数
    # ask_ok('OK to overwrite the file?', 2)  # 给出一个可选的参数
    ask_ok('OK to overwrite the file?', 2, reminder='Come on, only yes or no!')  # 给出所有的参数

1、函数的默认值是在函数定义处计算的

i = 5

def f(arg=i):
    print(arg)
    
i = 6
f()
会打印5

2、默认定义的形参值被调用时只执行一次,如果想要执行多次,定义在函数内部。

def f2(a, one=[]):
    # one被执行了一次
    one.append(a)
    return one


def f3(a, eli_one=None):
    # 想要执行多次的做法
    if eli_one is None:
        eli_one = []
    eli_one.append(a)
    return eli_one


if __name__ == '__main__': 
   # 测试默认值参数调用次数
    print(f2(1))
    print(f2(2))
    print(f2(3))

    print(f3(1))
    print(f3(2))
    print(f3(3))
    
运行结果:    
[1]
[1, 2]
[1, 2, 3]
[1]
[2]
[3]
关键字参数

1、在调用中,关键字参数必须跟随在位置参数的后面。

def parrot(voltage, state='a stiff', action='vcom', type='Norwegian Blue'):
    print("-- This parrot wouldn't", action, end=' ')
    print("if you put", voltage, "volts through it.")
    print("-- Lovely plumage, the", type)
    print("-- It's", state, "!")
    
    
if __name__ == '__main__':     
    # 关键字参数的学习
    parrot(1000)  # 1 positional argument
    print()
    parrot(voltage=2000)  # 1 keyword argument
    print()
    parrot(voltage=1000, action='VOOOOOM')  # 2 keyword arguments
    print()
    parrot(action='VOOOOOM', voltage=1000) # 2 keyword arguments
    print()
    parrot('a million', 'bereft of life', 'jump')  # 3 positional arguments
    print()
    parrot('a thousand', state='pushing up the daisies')  # 1 positional, 1 keyword
    
结果:
-- This parrot wouldn't vcom if you put 1000 volts through it.
-- Lovely plumage, the Norwegian Blue
-- It's a stiff !

-- This parrot wouldn't vcom if you put 2000 volts through it.
-- Lovely plumage, the Norwegian Blue
-- It's a stiff !

-- This parrot wouldn't VOOOOOM if you put 1000 volts through it.
-- Lovely plumage, the Norwegian Blue
-- It's a stiff !

-- This parrot wouldn't VOOOOOM if you put 1000 volts through it.
-- Lovely plumage, the Norwegian Blue
-- It's a stiff !

-- This parrot wouldn't jump if you put a million volts through it.
-- Lovely plumage, the Norwegian Blue
-- It's bereft of life !

-- This parrot wouldn't vcom if you put a thousand volts through it.
-- Lovely plumage, the Norwegian Blue
-- It's pushing up the daisies !


2、剩余的形参中,位置参数用*收集,关键字参数用**收集。

def cheese_shop(kind, *arguments, **keywords):
    print("-- Do you have any", kind, "?")
    print("-- I'm sorry, we're all out of", kind)
    for arg in arguments:
        print(arg)
    print("-" * 40)
    for kw in keywords:
        print(kw, ":", keywords[kw])
        
if __name__ == '__main__':
    # 剩余参数的收集
    cheese_shop("Limburger", "It's very runny, sir.",
                "It's really very, VERY runny, sir.",
                shopkeep="Michael Pallin",
                client="John Cleese",
                sketch="Cheese Shop Sketch")
结果:
-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
shopkeep : Michael Pallin
client : John Cleese
sketch : Cheese Shop Sketch
如何限制参数调用

1、/之前的参数调用仅限位置参数,*之后的调用仅限关键字参数,二者之间随意

def standard_arg(arg):
    print(arg)


def pos_only_arg(arg, /):
    print(arg)


def kwd_only_arg(*, arg):
    print(arg)


def combined_example(pos_only, /, standard, *, kwd_only):
    print(pos_only, standard, kwd_only)


if __name__ == '__main__':
    # 不同调用方式比对
    standard_arg(2)
    pos_only_arg(1)  # 希望形参名称对用户不可用时使用、对API,防止形参名称修改时造成破坏性的API变动
    kwd_only_arg(arg=2)  # 形参有实际意义、防止过度依赖传入参数的位置时
    combined_example(1, 2, kwd_only=3)

2、使用仅限位置参数,对API,可以防止形参名称被修改时造成的破坏性的API变动

3、当然,若形参有实际意义、防止过度依赖传入参数的位置时,使用仅限关键字参数

打包与解包参数

定义函数时,我们使用***打包剩余的位置参数或关键字参数供函数执行使用。

调用函数时,使用它们来解包参数传递给函数调用。

def unpack_para():
    args = [3, 6]
    show = list(range(*args))
    print(show)
    
if __name__ == '__main__':
    # 将元组里的参数**解包**分别传递给调用的函数
    unpack_para()
lambda表达式

创建一个匿名函数,在需要函数对象的任何地方使用。

可以用来返回一个函数或者传递一个小函数作为参数

def lambda_test(n):
    return lambda x: x + n
    
if __name__ == '__main__':    
    f = lambda_test(42)
    print(f(8))
def transport():
    pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
    pairs.sort(key=lambda pair: pair[1])
    print(pairs)
  
if __name__ == '__main__':
    # 传递小函数作为参数
    transport()

理解命名空间和作用域
  • 命名空间:名字到对象的映射
  • 作用域:一个命名空间可直接访问的python程序的文本区域

global:将变量关联到全局作用域

def scope_test():
    def do_local():
        spam = "local spam"

    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"

    def do_global():
        global spam
        spam = "global spam"

    spam = "test spam"
    do_local()
    print("after local: ", spam)
    do_nonlocal()
    print("after nonlocal: ", spam)
    do_global()
    print("after global: ", spam)


if __name__ == '__main__':
    # 理解作用域与命名空间,一个命名空间下的多个作用域
    scope_test()
    print("In global scope: ", spam)
类和实例:属性引用

(1)类的属性引用

  • 属性引用:返回内容或者函数对象
class MyClass:
    """A simple class"""
    i = 12345

    def f(self):
        return 'hello world'


if __name__ == '__main__':
    # 属性引用
    # MyClass.i = 'changed' 类的属性可以被赋值,可以通过赋值来更改值
    print(MyClass.i)  # 返回一个整数
    print(MyClass.__doc__)
    print(MyClass.f)  # 返回一个函数对象

(2)实例的属性引用

可以视之为不带参数的函数,常常包含一个名为__init__()的特殊方法

self即是类本身,初始化方法的使用:

class Complex:
    def __init__(self, realpart, imagpart):
        self.r = realpart
        self.i = imagpart


if __name__ == '__main__':
    # 实例化2
    x2 = Complex(3.0, -4.5)
    print('实数部分:%.1f;虚数部分:%.1f' % (x2.r, x2.i))
  • 数据属性

    赋值时产生,实例化时的专有名词,对应类时的变量

    # 实例化的属性引用: 数据属性
    x.counter = 1
    while x < 10:
        x.counter = x.counter * 2
    print(x.counter)

    del x.counter
  • 方法

类的属性引用叫做函数对象>>>实例化之后的引用叫做方法

方法可以在绑定后被立即调用,也可以被保存起来以后再调用

    # 方法 类的属性引用叫做函数对象 实例化之后的引用叫做方法
    xf = x.f # 注意这里!!! x.f:绑定,不立即调用; x.f():绑定后立即调用
    print(xf())

方法:实例对象会作为函数的第一个参数被传入,调用x.f()相当于MyClass.f(x)

类和实例中的“变量”

实例中的实例变量是每个实例的唯一数据,类中的变量是所有实例共享的属性和方法

class Dog:
    kind = 'canine'  # class variable shared by all instance

    def __init__(self, name):
        self.name = name  # instance variable unique to each variable


if __name__ == '__main__':
    # 类和实例变量
    d = Dog('Fido')
    e = Dog('Buddy')
    print("=== shared by all variable ===")
    print(d.kind)
    print(e.kind)
    print("=== unique by each variable ===")
    print(d.name)
    print(e.name)

!注意:类中的变量会共享给所有实例,要想使得某个变量被独享,应该放在初始化方法中

**反例: **

属性引用被映射到了公共区域,若是想要独享,只要映射在实例特有区域便可

class Dog:
    kind = 'canine'  # class variable shared by all instance

    tricks = []

    def __init__(self, name):
        self.name = name  # instance variable unique to each variable

    def add_tricks(self, trick):
        self.tricks.append(trick)


class Dog2:

    def __init__(self, name):
        self.name = name  # instance variable unique to each variable
        self.tricks = []

    def add_tricks(self, trick):
        self.tricks.append(trick)


if __name__ == '__main__':
    # 共享范围对比
    print("=== 这是放在类的共享区域里: ===")
    d = Dog('Fido')
    e = Dog('Buddy')
    d.add_tricks('roll over')  
    e.add_tricks('play dead')
    print(d.tricks)

    print("=== 这是利用初始化,为每个实例创建的空间: ===")
    d2 = Dog2('Fido')
    e2 = Dog2('Buddy')
    d2.add_tricks('roll over')  # 换言之,实例将属性引用映射到了不同的位置:查找时一般时先映射到共享的类的位置,再是映射到每个实例下。
    e2.add_tricks('play dead')
    print(d2.tricks)
    print(e2.tricks)
属性查找优先级

同样的属性名称同时出现在类和实例中,则属性查找会优先选择实例

class Warehouse:
    purpose = 'storage'
    region = 'west'


if __name__ == '__main__':
    w1 = Warehouse()
    print(w1.purpose, w1.region)
    print("=====前后对比=====")
    w2 = Warehouse()
    w2.region = 'east'
    print(w2.purpose, w2.region)

方法可以引用全局名称,比如模块、函数。

继承

派生类:DerivedClassName(BaseName):

当构造类对象时,基类会被记住,用来解析属性引用:

请求的属性在当前类中找不到,上一级去基类中找。再找不到,如果有基类的基类,就继续递归式地查找。

  • 派生类可能重载基类的方法
  • 两个内置函数可以被用于继承机制:
isinstance() 检查一个实例的类型
issubclass() 检查类的继承关系
私有变量、一些说明

下划线的名称改写

迭代器

__next__方法

生成器

用于创建迭代器的工具,使用yield语句

模块和包

模块就是一个.py文件,模块之间可以互相引用,在实际编程,以主模块为核心,编写各种功能模块。

通过.__name__获得当前模块名称

制作模块
# 学习模块的使用,构建更大项目
# 函数放在主函数之外的其他地方

def fib(n):
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a + b
    print()


def fib2(n):
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result
使用模块
import fibo


if __name__ == '__main__':
    # 访问做好的模块
    fibo.fib(1000)
    print(fibo.fib2(100))
    # 当前模块的名称
    print(fibo.__name__)
  • 技巧:如果经常使用某一函数,可以赋值到一个变量上。
# 导入模块,赋值简化方便后续使用
    fib = fibo.fib
    fib(500)
更多关于模块

(1)函数定义和可执行语句在第一次导入时被执行,用来初始化模块。

(2)每个模块都有一个私有符号表:

  • 主模块的全局变量不会和其他模块发生冲突

  • 可以用访问函数的方法去访问一个模块的全局变量

  • 同样,可以指定导入模块的对应私有符号变量而不去导入模块本身

  • 使用*符号导入除了以下划线开头的名称之外的所有名称(通常情况不要这样做,因为可能会导入一些未知的函数覆盖调自己定义的东西)

  • 可以用as指定别名

    from fibo import fib, fib2
    fib(500)
    

(3)每个模块在解释器中执行一次,更改了模块的内容得重启。

在交互测试中可以这样做:

import importlib
importlib.reload(modulename)
执行模块

使用脚本传入参数执行模块

python module.py <arguments>


# =======
if __name__ == '__main__':
    # 脚本方式执行模块
    import sys

    fib(int(sys.argv[1]))
  • 技巧:添加main,只有在主模块执行时下面的内容才被调用,经常用于提供一个很方便的用户接口或者用于测试
模块搜索路径

当一个模块被导入,解释器寻找次序为:

(1)具有该名称的内置模块;

(2)从sys.path变量给出的目录里面找module.py的文件

sys.path的初始路径:输入脚本的目录(未指定文件时为当前目录)、PYTHONPATH(一个包含目录名称的列表)、取决于安装的默认位置

!在初始化之后可以更改sys.path,包含正在运行的脚本的文件目录将被放在搜索路径的开头,在标准库路径之前。所以,不要让文件和标准库重名了。

关于编译过的python文件

__pycache__缓存.pyc文件,会让载入速度变快但并不对执行起作用。

两种情况不检查缓存:(1)命令行载入的;(2)没有源模块。

  • - O 编译时去除断言,- OO编译时去除断言和__doc__字符串
  • compileall模块可以为一个目录下的所有模块创建.pyc文件
dir()函数

(1)查看模块定义的名称,返回字符串列表

默认返回当前定义的名称,会列出所有类型的名称

(2)要查看内置函数和变量名称:

import builtins
dir(builtins)

(1)模块的集合,分层的文件系统,__init.py是标志。

导入方法类似上述的模块(第2点)

(2)关于__init.py文件:

可以只是一个空文件,也可以是执行包的初始化代码或设置__all__变量:

包中导入*时,可能会产生不必要的副作用,所以此时可以提供一个包的显式索引,即:

from package import *
设置:
__all__ = ['moduleA','moduleB']
如果没有设置__all__:
不会导入包中的任何子模块,只确保 导入当前的模块和运行任何在__init.py__中的代码,然后导入包中定义的任何名称

总结:
建议使用from package import specific_submodule

(3)包除了绝对导入外,还可以相对导入:“子包参考”

二、将数据引入处理

文件打开

三、数据的流通

while语句

只要条件为真就一直执行,非零整数为真,零为假。

标准比较操作符有:<(小于) >(大于) ==(等于) <=(小于等于) >=(大于等于) !=(不等于)

def whl_t():
    a, b = 0, 1
    while a < 10:
        print(a, end=',')
        a, b = b, a + b


if __name__ == '__main__':
    whl_t()

if语句

可以有零个或多个elif部分以及一个可选的else部分

def if_t():
    x = int(input("Please input an integer: "))
    if x < 0:
        x = 0
        print('Negative changed to zero')
    elif x == 0:
        print('Zero')
    elif x == 1:
        print('Single')
    else:
        print('More')

关键字elif适合用于避免过多的缩进

for语句

对任意序列进行迭代,条目的迭代顺序与它们在序列中出现的顺序一致。

def for_t():
    words = ['cat', 'window', 'defenestrate']
    for w in words:
        print(w, len(w))

遍历集合时如果要做修改,做法是循环该集合的副本或者创建新集合

直接修改: # RuntimeError: dictionary changed size during iteration

def for_change_error():
    users = {'a': 'active', 'window': 'inactive', 'defenestrate': 'active'}
    for user, status in users.items():  # RuntimeError: dictionary changed size during iteration
        if status == 'inactive':
            del users[user]

做法:

def for_change():
    users = {'a': 'active', 'window': 'inactive', 'defenestrate': 'active'}
    for user, status in users.copy().items():  # RuntimeError: dictionary changed size during iteration
        if status == 'inactive':
            del users[user]
    print(users.keys())
def for_change2():
    active_users = {}
    users = {'a': 'active', 'window': 'inactive', 'defenestrate': 'active'}
    for user, status in users.items():  # RuntimeError: dictionary changed size during iteration
        if status == 'active':
            active_users[user] = status
    print(active_users.keys())

range和enumerate函数

返回的都是可迭代对象:

range可以用来迭代由算术级数组成的序列;

enumerate()可以用来迭代序列的索引位置和其对应的值

zip函数

将序列之间的元素一一匹配

def zip_t():
    a = [1, 2, 3]
    b = ['one', 'two', 'three']
    for m, n in zip(a, b):
        print('{0}的英文是{1}'.format(m, n))
     
1的英文是one
2的英文是two
3的英文是three

break/continue/for…else…/while…else…

1、break可以跳出最近的forwhile循环

2、forwhile循环带有else子句时,在for耗尽可迭代对象、while变为假值时执行,break终止时不执行else

3、continue表示继续循环中下一次迭代

def break_t():
    for n in range(2, 10):
        for x in range(2, n):
            if n % x == 0:
                print(n, 'equals', x, '*', n//x)
                break
        else:
            # loop fell through without finding a factor
            print(n, 'is a prime number')
          
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3       
def continue_t():
    for num in range(2, 10):
        if num % 2 == 0:
            print("Found an even number", num)
            continue
        print("Found an odd number", num)

pass语句

什么也不做,语法上需要这么一个东西,但不需要执行什么的时候用。

def pass_t():
    while True:
        pass  # Busy-wait for keyboard interrupt


class MyEmptyClass:
    pass


def initlog(*args):
    pass  # Remember to implement this!

错误分为语法错误和异常

语法错误

Syntax Error:解析时发现的错误

异常

程序执行时检测到的错误:

错误的最后一行,遇到了什么类型的错误;

错误的前一部分,以堆栈回溯的形式显示发生异常时的上下文

处理异常
  • 异常测试:执行try语句,正常情况跳过except;出现异常去检测except中匹配的部分并执行,(没有时报错),执行完继续try语句。
def except_test():
    while True:
        try:
            x = int(input("please input a number: "))
            break
        except ValueError:
            print("Oops! That was no valid number. Try again...")


if __name__ == '__main__':
    # 异常测试:执行try语句,正常情况跳过except;出现异常去检测except中匹配的部分并执行,(没有时报错),执行完继续try语句
    except_test()
多个异常

一个except语句可以用元组包含多个异常

...
except (RuntimeError, TypeError, NameError):
    pass
执行顺序

异常执行时,基类可以起到派生类的作用,假如将基类放在前面,则出发基类。

异常类的兼容问题: 基类兼容派生类。但是派生类不兼容基类

class B(Exception):
    pass


class C(B):
    pass


class D(C):
    pass


if __name__ == '__main__':
    # 异常类的兼容问题: 基类兼容派生类。但是派生类不兼容基类
    for cls in [B, C, D]:
        try:
            raise cls()
        except D:
            print("D")
        except C:
            print("C")
        except B:
            print("B")

反例:

...
# 异常覆盖
for cls in [B, C, D]:
    try:
        raise cls()
    except B:
        print("B")
    except D:
        print("D")
    except C:
        print("C")
通配符

except后没有任何东西时,作通配符

这种方式可能会掩盖真正的编程错误

def no_except():
    try:
        f = open('myfile.txt')
        s = f.readline()
        i = int(s.strip())
    except OSError as err:
        print("OS error: {0}".format(err))
    except ValueError:
        print("Could not convert data to an integer.")
    except:
        print("Unexpected error:", sys.exc_info()[0])
        raise


if __name__ == '__main__':
    # 省略异常以用作通配符
    no_except()
else子句(可选)

try…except…既是捕获异常,也是对一段代码的保护。而使用else语句可以避免意外捕获try-except语句保护的代码引发的异常。——>就是把try执行代码分开了,针对性地处理

def else_test():
    for arg in sys.argv[1:]:
        try:
            f = open(arg, 'r')
            print('here...')
        except OSError:
            print('cannot open', arg)
        else:
            print(arg, 'has', len(f.readlines()), 'lines')
            f.close()
            
# else子句测试
 else_test()
except关联到实例

except可以在异常后面指定一个变量关联到实例

def connect_except():
    try:
        raise Exception('spam', 'eggs')
    except Exception as inst:
        print(type(inst))
        print(inst.args)
        print(inst)

        x, y = inst.args  # unpack args
        print('x = ', x)
        print('y = ', y)

# except可以在异常后面指定一个变量关联到实例
# connect_except()
函数内部

处理try子句中函数内部发生的异常

def inner_test():
    try:
        this_fails()
    except ZeroDivisionError as err:
        print('Handing run-time error:', err)


if __name__ == '__main__':
    # 程序可以处理try子句中函数内部发生的异常
    inner_test()
抛出异常

raise语句:强制发生指定的异常

唯一的参数就是指定的异常

raise NameError

Traceback (most recent call last):
  File "D:/coding/python/python_learn/basic/error_expectation06.py", line 78, in <module>
    raise NameError
NameError

重新出发异常:确定异常是否被引发但不处理

def raise_again():
    try:
        raise NameError('HiThere')
    except NameError:
        print('An exception flew by!')
        raise  # 这个raise重新触发了Name Error 打印出来后面的内容


if __name__ == '__main__':
    # 重新引发异常
    raise_again()

用户可以从Exception派生类自定义自己的异常

定义清理操作

finally子句:定义必须在所有的情况下执行的清理操作

def finally_test():
    try:
        raise KeyboardInterrupt
    finally:
        print('Goodbye, world!')
        
        
if __name__ == '__main__':
    # 定义必须在所有的情况下执行的清理操作
    finally_test()

finally子句的优先级是最高的,比except、try都高:

  • except的异常(try中、except中、else中)在finally执行完毕后才被触发
  • try中的break、continue或return在finally之后被执行
  • try和finally中都有return时,以finally中的为准
def bool_return():
    try:
        return True
    finally:
        return False


if __name__ == '__main__':
    # finally拥有最高的优先级
    x = bool_return()
    print(x)

实际应用程序中,finally子句对于是否释放外部资源(例如文件或者网络连接)非常有用,无论是否成功使用资源。

预定义清理子句

在代码执行完毕后及时地清理

def with_test():
    with open("myfile.txt", encoding='utf-8') as f:
        for line in f:
            print(line, end="")


if __name__ == '__main__':
    # with子句预定义清理操作
    with_test()

四、数据的呈现

文档字符串

1、文档字符串的书写:缩进是根据第一个非引号行确定的;

2、第一部分:对象目的的简述。

3、第二部分:空白,在视觉上与其余描述分开。

4、第三部分:对象的调用约定、它的副作用等。

函数标注的使用方法

形参的标注是后面加上:,返回值的标注是括号后面、冒号前面加上->

def annotations_test(ham: str, eggs: str = 'eggs') -> str:
    """
    函数标注的使用例子:其中分别有对位置参数、关键字参数、返回值的标注
    """
    print("Annotations:", annotations_test.__annotations__)
    print("Arguments:", ham, eggs)
    return ham + ' and ' + eggs
    
if __name__ == '__main__':
    # 函数标注(和文档字符串一起学习的)
    result = annotations_test('spam')
    print(fibonacci.__annotations__)
    print(result)

表达式语句

格式化输出法:一是格式化字符串面值;

def format_one():
    year = 2021
    event = 'Referendum'
    print(f'Results of the {year} {event}')


if __name__ == '__main__':
    format_one()

format方法

print('格式化是这样使唤的:{a}。。。{b}'.format(a='没错,你使唤对了',b='对了2'))
格式化是这样使唤的:没错,你使唤对了。。。对了2

五、数据使用

文件

1、处理文件对象使用with关键字

2、文件中读取行使用循环遍历文件对象

JSON说明

序列化和反序列化治之间对数据或文件高效地利用,JSON格式通常被现代应用程序用于允许数据交换

Reference

[1]python 3.8 官方文档:https://docs.python.org/3.8/

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值