Python基础

本文详细介绍了Python的基础知识,包括Python的解释器、Python2.x与3.x的区别、基础语法如注释、运算符、变量及其类型,以及函数、模块、OOP、异常处理和文件操作等核心概念。此外,还探讨了Python的三大基本结构、内建函数、迭代器、生成器和装饰器等高级特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Python 基础

Python 简介

Python(蟒蛇)由 Guido(仁慈的独裁者)设计开发,是一种解释型语言,简洁但速度慢。Python 拥有丰富的官方库和第三方库,使得 Python 快速快速流行起来。

  • 优点:高级,OOP;解释型语言;丰富的库;跨平台。
  • 缺点:相对于编译型语言(C/C++,Java 等),速度较慢;代码开源。

Python 解释器

  • CPython:Python 官方解释器,用 C 语言编写。
  • Ipython:基于 Cpython 的一种交互式解释器。
  • JPython:使用 Java 编写的解释器。
  • 其他。

使用which python3命令查看 Python 解释器的安装路径,一般 Python 解释器大小为 4M 左右,很小。

Python2.x 与 Python3.x

Python3.x 是现在主流更新的版本,Python2.7 是官方的最后一个 2.x 版本。在设计 Python3 时,为了避免引入过多累赘,官方不对下兼容。故 Python2.x 和 Python3.x 是不通的,随着时间的发展,应当选择 Python3。

  • Python2.x 不支持中文,默认采用的是 ASCII 编码,而 Python3.x 使用的是 Unicode 编码,支持世界各种语言(可以使用中文变量名)。
  • Python3 没有了long类型,int理论没有大小限制。然而在 Python2 中数值大小有限制。

运行 Python 程序

  • 使用解释器运行,python3 xx.py
  • 直接运行
    • py 文件开头使用 shebang:#! /usr/bin/env python3或者#! /usr/bin/python3
    • 增加执行权限。chmod +x xx.py,然后用命令./xx.py执行之

shebang 符号

shebang 通常在类 Unix 系统脚本中的第一行开头使用,用于指明执行该脚本文件的解释程序路径。

#! /usr/bin/env python3
# coding:utf-8

Python 基础语法

注释

  • 单行注释:# 单行注释
  • 多行注释:3 个单引号或者 3 个双引号括起来。

运算符

  • 算术运算符:+, -, *, **, /, //, %
    • +还可用于容器的合并,-还可用于集合求差集,*还可以用于容器重复。
  • 比较运算符:>, <, >=, <=, ==, !=
    • 与 C/C++、Java 等语言不同,多个比较运算符会按照数学方式求解。例如,1<3>2表示1<3 and 3>2,结果为True
  • 逻辑运算符:and, or, not,均为短路运算符。
  • 赋值运算符:=, +=, -=, *=, **=, /=, //=, %=
  • 位运算符:&, |, ~, ^, >>, <<
    • &、|、^还可用于集合求交集、并集、对称差集。
  • 成员运算符:in, not in
  • 身份运算符:is, not is
    • is用于判断两个变量的引用是否相同。
    • ==用于判断两个变量的值是否相同。

变量

int, float, complex, bool, str, bytes, list, tuple, dict, set共 10 种类型。

  • 数值类型:int, float, complex, bool,其余为非数值类型。
  • 可变类型:list, dict, set,其余为不可变类型。
  • type(x), id(x), isinstance(x, 类型或元组), 类型(x), eval(str), chr(x), ord(x), bin(x), oct(x), hex(x),其中,isinstance()会自动向上转型,type()不会。
  • int(非十进制表示的字符串, 该进制),例如int('0b0011', 2), int('0o7777', 8), int('0xffff', 16)

Python2 中还有long类型,Python3 中只有int类型,int理论没有大小限制。

在 Python 中,变量和数据是分开存储的,数据保存在内存中,变量中保存的是数据在内存中的位置,即变量中记录着数据的地址(引用)。

数值型
  • B('0b0101')、O('0o7675')、D、H('0xffff')。数值型变量可以使用二进制、八进制、十进制(默认)和十六进制表示,其中除了十进制其他为字符串。
  • complexa.real, a.imag
  • 数学函数:import math
  • 随机函数:import random
字符串
  • 转义字符:\\, \', \", \n, \r等
  • Python 中单引号和双引号,甚至三引号都是一样的,都可以表示 str 类型。这是因为 Python 中没有单独的 char 类型,只有长度为 1 的 str 类型。
  • 字符串编码:
    • Unicode编码(2 个字节):Python3 默认使用Unicode编码。
    • ASCII编码(1 个字节):Python2 默认使用ASCII编码。故 Python2 不支持中文。
  • 字符串运算符:+, *, [x], [a:b:c]左闭右开原则, in, not in, r'haha'(原始字符串), %(格式字符串), [::-1](字符串逆序)
  • str 的内建方法:capitalize(), splitlines(), index(chr, begin, end), replace(old, new, max), startswith(str), endswith(str), center(len, '*'), isalpha(), istitle(), isalnum(), isdigit(), isupper(), islower(), isdecimal(), find(str, begin, end), strip(), count(str, begin, end), swapcase(), encode("utf-8"), join(list), title(), lower(), upper(), format(), split(str)
  • 'ABC'b'ABC':虽然二者显示一样,但是前者为str,后者为bytesstr可以通过encode方法编码为bytesbytes可以通过decode方法解码为str。在网络传输或者硬盘存储一般以 bytes 的形式。
    • 'abc'.encode('utf-8'),变成bytes
    • b'abc'.decode('utf-8'),变成str
列表
  • 列表运算符:+, *, [x], [a:b:c], in, not in
  • 列表嵌套:列表的元素可以是另一个列表,由此可以构成二维数组。
  • list 的内建方法:append(x), insert(index, x), extend(list), pop(序号,默认为-1), remove(x), clear(), count(x), index(x), reverse(), sort(), copy()
元组
  • 创建只有一个元素的元组必须在元素后面加一个逗号,避免误认为括号。
  • 元组除了无法修改元素以外和 list 功能一样。
  • 元组的自动拆包和封装,a, b = b, a
  • tuple 的内建方法:count(), index()
字典
  • a = {'name':'Bob', 'age':12}
  • dict 的内建方法:a[key], update(), pop(key), clear(), get(), items(), keys(), values()
集合
  • 集合中的元素不重复,利用这个将其他类型强制转换成set()可以排除重复元素。
  • 集合运算符:&, |, -, ^
  • set 的内建方法:add(), update(), remove(), discard(), clear()
容器的公共特性及高级特性
  • 内建函数:len(), del(), max(), min(), sum()
  • 运算符:+, *, in, not in, 比较运算符
  • 迭代:
    • 在 dict 中:for k,v in dict.items()
    • 在 list 中:for i,v in enumerate(l)
  • 切片:list, tuple, str[star:end:step]
  • 列表生成式:
a = [x*x for x in range(1,11)]
b = [m+n for m in 'ABC' for n in 'XYZ']
c = [d for d in os.listdir()]
d = [x+2 for x in range(100) if x%2 == 0]
e = [[1,2], [3,4], [5,6]]
f = [x for i in e for x in i]

输入和输出

  • 输入:input('提示语'),返回值均为str,一般需要进行强制类型转换。
  • 输出:
    • 普通输出:print(a, b, c[, end=' '])
    • 格式化输出:print(格式化字符串%(值)

关键字

import keyword
print(keyword.kwlist)

三大基本结构

顺序结构
条件结构
  • 类型 1
if condition1:
    pass
elif condition2:
    pass
else:
    pass
  • 类型 2
语句1 if condition else 语句2
print('haha') if a>0 else print('hehe')
b = 1 if a>0 else 0

False:0,空字符串,空容器,None。True:非 0, 非空字符串, 非空容器, 非 None。

循环结构
  • 类型 1
while condition:
    pass
else:
    pass
  • 类型 2
for v in seq:
    pass
else:
    pass
  • 类型 3
循环体:
    break
    continue

else 可以省略,else 中的语句只有在循环顺利结束才会执行,如果是 break 造成的跳出循环则不执行。

pass 语句即空语句,一般用来占位符。

内建函数

abs(), bin(), oct(), hex(), dir(), eval(), map(), filter(), sorted(), reversed(), int(), float(), complex(), bool(), str(), bytes(), list(), tuple(), dict(), id(), type(), isinstance(), input(), print(), help(), len(), max(), min(), sum(), pow(), divmod(), round(), range(), open(), zip(), enumerate(), hash(), next(), property(), chr(), ord(), hasattr(), setattr(), delattr(), getattr()

  • 可以使用dir(__builtins__)查看所有的内建函数。
  • dir():输出对象的所有属性和方法。
  • 不要滥用eval()函数。
input_str = input('请输入计算题:')
print(eval(input_str))

__import__('os').system('ls') # 执行终端命令
__import__('os').system('touch aaa.py')
  • map(), filter(), sorted(), 均为高阶函数。
  • isinstance(a, (int, float)), 函数可以判断多个类型其中的一个。
  • range()在 Python3 中返回的是一个迭代器,在 Python2 中返回的是一个元组。返回一个迭代器速度快并且省空间。
  • hash()接受一个不可变参数,返回一个整数。这个整数是该参数的特征码(指纹)。

深拷贝与浅拷贝

  • 直接赋值:传递对象的引而已。二者的 id 相同。
  • copy():浅拷贝。只拷贝父对象,不拷贝子对象,子对象仍然是引用
  • deepcopy():深拷贝。既拷贝父对象,又拷贝子对象
  • 列表的切片d[a:b]是浅拷贝。
  • 列表乘法是浅拷贝。

当单个对象为不可变类型时,copydeepcopy都是引用。
当父对象是不可变的,子对象中有一个可变对象时,deepcopy 是深拷贝,然而 copy 还是引用。

其他

运行时传参数
Python3 haha.py 1 2 3
import sys
print(sys.argv) # ['haha.py', '1', '2', '3']
续行符

当代码一行不足以完全写完时,可以使用’'表示续行。

if (age > 25 and subject == '电子工程') or \
   (college == '重点' and subject == '电子工程')
   print('haha')

函数

函数初步

定义函数
def 函数名(形参)'''功能描述
    :param 参数1:参数描述
    :param 参数2:参数描述
    '''
    pass
函数的参数和返回值
  • 参数:位置参数,默认参数,不定长参数,关键字参数。可以使用listdict的拆包。
def f(a, b, c=0, *args, **kw):
    pss
f(1, 2, 3, *list, **dict)
  • 默认参数只会在定义的时候解释一次,之后会共用同一份。所以默认参数定义为可变类型会产生隐含错误。
  • 实参的赋值顺序:位置参数,不定长参数,默认参数,关键字参数。所以当这些参数混用时要注意参数重复赋值的问题
  • 函数的可变参数和不可变参数:
    • 无论实参是可变参数还是不可变参数,都为引用。这与 C/C++等不同。
    • 在函数内部,针对参数进行赋值语句操作,无论是可变还是不可变参数,都不会影响外部引用的变量。仅仅针对复制修改,相当于重新创建一个同名的局部变量。
    • 若对参数进行方法的修改则会改变外部值。
    • 列表的+=不能视为赋值操作,它的本质是调用extend方法。
  • 返回值:可以用元组的自动封装。
函数的嵌套和递归
  • 函数的嵌套:函数中调用另一个函数
  • 函数的递归:函数中调用自己(一般参数不同且有边界判断)。

局部变量和全局变量

  • 在函数中,可以使用全局变量的值,但是不允许改变它的值。如果企图改变它的值,就会定义一个同名的局部变量。
  • 若非要在函数中改变全局变量的值,则需要用global声明之。
num = 10
def f1():
    num = 99 # 不会改变全局变量的值
    print(num)

def f2():
    global num # 声明num是一个全局变量
    num = 99
    print(num)

f1()
print(num)
f2()
print(num)

匿名函数(lambda 表达式)

f = lambda x:x*x
f = lambda :print('haha')

高阶函数

变量名可以指向函数,所以函数可以作为另一个函数的参数。这种函数叫做高阶函数,内置的高阶函数有map(), filter(), sorted()

def haha(x, y, f):
    return f(x) + f(y)
  • map(func, iterable):func 作用于 iterable 中的每一项,将结果作为一个 iterable 返回。list(map(int, '123'))
  • reduce(func, iterable):func 作用于 iterable 中的相邻元素,将结果继续和后继序列的下一个元素作累积运算。reduce(f, [1,2,3]) == f(f(1,2),3)
  • filter(func, iterable):func 作用于 iterable 中的每一个元素,只有结果为True的元素被保留下来。
  • sorted(iterable, key, reverse=True):根据 key 所指向的函数对序列进行排序。
  • 利用 filter 筛素数
def odd_iter():
    n = 1
    while True:
        n += 2
        yield n

def not_prime(n):
    return lambda x:x%n != 0

def primes():
    yield 2
    it = odd_iter()
    while True:
        n = next(it)
        yield n
        it = filter(not_prime(n), it)

闭包(返回函数)

闭包是指返回值是函数的函数。内部函数可以应用外部函数的参数、局部变量和全局变量,当返回闭包时,相关参数信息被一同保存在返回的函数中,但是这种保存时引用保存。返回的函数并不立即执行,当主动调用时才执行。

  • 在闭包中,如果需要在内部函数中修改外部函数中的变量,需要使用nonlocal x声明(Python3 中才支持,Python2 不行)。
def count():
    fs = []
    for i in range(1,4):
        def f():
            return i*i
        fs.append(f)
    return fs

haha = count()
for i in range(1,4):
    fs[i]()

结果为:9 9 9,而不是1 4 9

在闭包中,返回函数最好不要引用可变的变量。因为闭包保存的是该变量的引用,当该变量后期变化时,闭包的结果将改变。当然,特殊需求除外。

Python 中的三个器

迭代器

可迭代对象和迭代器

迭代是访问序列的一种方式,从序列的一个位置除法,按顺序访问元素。迭代中只可以向前而不可往后。

  • 可迭代对象(iterable):实现__iter__方法的类,例如str, list, tuple, dict, set, 生成器
  • 迭代器(iterator):实现__iter____next__方法的类。
实现迭代器

定义一个类,类中实现__iter____next__方法。__iter__方法要返回一个迭代器(一般为自己),__next__方法要需要打印的值。

class Fab(object):
    def __init__(self, n):
        self.n = n
        self.a = 1
        self.b = 1
        self.current = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < self.n:
            ret = self.a
            self.a, self.b = self.b, self.a+self.b
            self.current += 1
            return ret
        else:
            raise StopIteration

生成器

生成器是特殊的迭代器,它是一种可迭代对象。迭代器和生成器都是保存生成数据的代码,边使用边生成数据,可以有效地节省空间和提高效率。构造迭代器有 2 种方式。

实现生成器
  • 使用列表生成式:a = (i*i for i in range(100))
  • 使用yeild关键字:一般使用在函数中,将需要打印的对象使用yeild输出。yeild会将生成器阻塞,直至下一次调用它。因此可以使用yeild来实现多任务。
def fab(n):
    a, b = 1, 1
    current = 0
    while current < n:
        yeild a
        # 当为send时,ret为给生成器的参数
        # ret = yeild a
        # print(ret)
        a, b = b, a+b
        current += 1

a = fab(100)
ret = next(a)
# 给生成器一个100的参数
# ret = a.send(100)

nextsendnextsend都可以启动生成器,但是send可以传参数给yeild

生成器实现多任务–协程

利用yeild的阻塞特性,可以实现多任务的第三种机制–协程。

def f1():
	while True:
		print("1")
		yield

def f2():
	while True:
		print("2")
		yield

while True:
	next(f1())
	next(f2())

装饰器

装饰器本质是高阶函数的闭包,它的参数中有一个函数func1,它的返回值是另一个函数func2。由此,装饰器可以在不改变源代码的基础上实现增加功能的需求。func2可以看做是fun1功能的升级。

实现装饰器

在需要打补丁的函数前使用@装饰器名来使用装饰器。

def log(func):
    def wrapper(*args, **kw):
        # 新增加功能
        print('hahah')
        ret = func(*args, **kw)
        return ret
    return wrapper

@log
def now():
    print('2019-3-23')

此时,now = log(now)
多个装饰器

当一个函数有多个装饰器时,装饰器会从上到下执行,但是从下到上装饰。

类装饰器
  • 除了函数,类也可以当做装饰器。
  • 输入的参数作为__init__的参数,调用要实现__call__函数。
class Test(object):
    def __init__(self, func):
        self.func  = func

    def __call__(self):
        print('----haha----')
        self.func()

@Test # func = Test(func)
def func():
    print('luelue')

func() # 调用的是Test中的__call__函数
带有参数的装饰器

当装饰器含有参数的时候,装饰器分为了 2 步:

  • 调用装饰器并且将参数当做实参传递
  • 用上一步调用的返回值当做装饰器再对原函数进行装饰
  • 所以原有的装饰器要变成返回装饰器的装饰器。
def set_level(level_num):
    def set_func(func):
        def call_func(*args, **kwargs):
            if level_num == 1:
                print('--验证权限1--')
            elif level_num == 2:
                print('--验证权限2--')
            return func()
        return call_func
    return set_func

@set_level(1)
def test1():
    print('--test1---')

test1()


# def set_func(func):
#     def call_func(*args, **kwargs):
#         level = args[0]
#         if level == 1:
#             print('--验证权限1--')
#         elif level == 2:
#             print('--验证权限2--')
#         return func()
#     return call_func

# @set_func
# def test1():
#     print('--test1--')

# test1(1)

模块

模块与包

  • 模块:一个.py文件就是一个模块。
    • 模块名采用大驼峰命名法。
    • __name__属性:一个模块可能有测试代码,为了在导入该模块时避免执行这些代码,可以使用__name__的属性约束测试代码的执行,它可是保证测试代码只有在测试的时候运行。
    • __name__在当前执行程序中为'__main__',在导入的程序中为模块文件名
def main():
    pass

if __name__ == '__main__':
    main()
  • 包:为了避免模块名冲突和更好的管理多个模块,Python 引入包的概念。包是众多模块的集合。一个包就是一个拥有__init__.py文件的文件夹。
    • 包名采用全小写命名。
    • __init__.py中要指明对外界提供的模块列表。有两种方法指定:from . import send_message 或者 __all__ = ['send_message', 'recv_message']

模块的导入与使用

  • 导入模块
    • import math [as mt]
    • from math import sin [as sn]
    • from math import *
  • 使用模块
    • 当模块中的变量或者函数与本程序中的重复时,程序中的变量会覆盖模块中的变量。
    • 若试图修改模块中的值,会和函数参数一样,相当于定义了一个同名的局部变量。推荐使用模块名.变量的方式使用模块。
  • 重新导入模块:特别是针对于自己写的模块,导入模块之后,又再次修改了模块,由于 Python 中有预解释模块为.pyc的字节码文件的特性,故新修改的模块不会起作用。这时需要使用imp.relaod(模块名)来重新导入模块。

.pyc(python compiled)文件。当导入一个模块(特别是自己写的模块)时,为了提高运行速度,Python 会事先对模块进行预处理,会在导入文件的同一级目录生成一个__pycache__的文件夹。

模块搜索路径

  • 当前目录,内置模块和已安装的第三方模块
  • 搜索路径在sys.path的列表中,可以人为修改该列表中的值来改变模块的搜索路径,例如sys.path.append('/users/hzg/my_py_scripts')

发布包和安装包

可以将自己创作好的模块发布出去,供别人安装使用。

发布包
  • 创建 setup.py 文件,该文件与包同一级
from distutils.core import setup
setup(name = 'xx', version = 'xx') # 用于指明包的相关信息
  • 构建模块:python3 setup.py build
  • 生成发布的压缩包:python3 setup.py sdist
  • 安装包
tar -zxvf haha.tar.gz
sudo python3 setup.py install
  • 卸载模块
cd /usr/local/lib/python3.6/dist-package/
sudo rm haha -r
安装包

利用 pip3 工具可以下载官方的第三方模块。

OOP

OOP 初步

定义一个类
class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score

    def print_score(self):
        print('%s:%s'%(self.name, self.score))

stu1 = Student('Bob', 75)
  • 类名采用大驼峰命名法。
  • self是当前实例的一个引用,根据数据的调用者的不同而不同。
  • 创建一个类实例时stu1 = Student('Bob', 75),会自动执行以下操作:
    • 为对象在内存分配空间。__new__()方法。
    • 为对象的属性进行初始化。__str__()方法。
  • 获取对象的信息:type(), isinstance(), dir(), hasattr(obj, 'x'), getattr(obj, 'x'), setattr(obj, 'x', 19), delattr(obj, 'x')
特殊的属性和方法
  • xx:public。
  • _xx:外部可以访问,但是要视为 private。
  • __xx:private。
  • __xx__:内置属性和方法。__new__, __init__, __str__, __del__, __iter__, __next__, __enter__, __exit__, __len__, __call__

Python 中 private 不一定就真正不能访问,因为 Python 将__xx解释为_类名__xx,但是不建议这么去访问 private 属性。Python 没有任何机制限制你做任何事,一切全靠编程自觉。

继承和多态
  • Python 支持多继承。
  • object是所有类的基类。以object为基类的类称之为新式类,否则为旧式类。Python3 默认为新式类,Python2 默认是旧式类。
  • 子类将继承父类的所有属性和方法,同时子类也可以重载方法。
  • 子类不可以直接访问父类的私有属性和方法,需要借助父类的共有方法去间接访问之。
  • super().xx,手动调用父类的方法。
  • 向上类型转换:子类可以看成父类,但是父类不可以看成子类。在定义函数的参数时可以设为父类,该函数可以根据传入的参数的具体类型去执行特定的代码
class Animal(object):
    def run(self):
        print('Animal runs')

class Dog(Animal):
    def run(self):
        print('Dog runs')

class Cat(Animal):
    def run(self):
        print('Cat runs')

def haha(animal):
    animal.run()

haha(Dog())
haha(Cat())
  • 多继承中的问题:由于 Python 支持多继承,故不同父类中的同名方法和属性将互相混淆。在 Python 类中,__mro__(method resolution order)内置属性指明了属性和方法的搜索顺序。
class C(A, B)
    pass

print(C.__mro__),结果为(C, A, B, object)

class C(B, A)
    pass

print(C.__mro__),结果为(C, B, A, object)
  • 在继承中不是拷贝,而是共用同一份代码
class Parent(object):
    x = 1

class Child1(Parent):
    pass

class Child2(Parent):
    pass

print(Parent.x, Child1.x, Child2.x),结果为1 1 1
Child1.x = 2
print(Parent.x, Child1.x, Child2.x),结果为1 2 1
Parent.x = 3
print(Parent.x, Child1.x, Child2.x),结果为3 2 3

属性和方法

实例和类的属性和方法
  • 实例属性和类属性
    • 实例属性:通过实例对象或self设置。
    • 类属性:直接在类中定义。类属性虽然归类所有,但是所有实例对象均可以访问。当类属性和实例属性同名时,实例属性会屏蔽掉类属性。例如tool.count = 4,会给 tool 增加一个实例属性 count,同时屏蔽该实例对象的 count 类属性,故不推荐实例直接使用类属性。
  • 实例方法、类方法和静态方法
    • 实例方法:在类中定义的方法默认为实例方法。
    • 类方法:用@classmethod装饰器装饰的方法为类方法,类方法的第一个参数为cls。在类方法中只能调用其他类属性及类方法。
    • 静态方法:用@staticmethod装饰器装饰的方法为静态方法。静态方法与类无本质联系,但功能与类有关。静态方法不可使用类的任何资源。
动态增加属性和方法
  • Python 支持为实例动态绑定属性和方法,给实例动态绑定的属性和方法不对其他实例起作用。
  • __slots__属性:该元组限制实例的能添加的属性名。该限制对子类不再使用。
class A(object):
    # __slots__ = ('name', 'age')
    pass

def haha():
    print('haha')

a = A()
a.name = 'Bob'
print(a.name)
a.haha = haha
a.haha()
property 属性

Property 是一个装饰器,装饰的函数必须返回一个值,调用时相当于获取一个属性一样。将方法变成属性

  • 装饰的函数只有一个self参数,且必须有一个返回值。调用时无需括号。
  • @property, @变量名.setter, @变量名.deleter
  • property 函数。price = property(getter, setter)
class Milk(object):
    def __init__(self, price):
        self.__price = price

    @property
    def price(self):
        return self.__price

    @price.setter
    def price(self, price):
        self.__price = price

    # price = property(price_getter, price_setter, price_deleter),不好用。

单例模式

  • 每次创建对象时,总是返回同一个对象的引用。例如系统的回收站, 打印机等资源无论何时总保证只有一个。当使用类名()欲创建一个新对象时,系统自动做了以下 2 件事:
    • 为对象在内存分配空间。__new__()方法。
    • 为对象的属性进行初始化。__str__()方法。
  • 重写__new__方法保证每次只创建一个对象。
  • 重写__init__方法保证每次只初始化一次该对象。
class A(object):
    instance = None
    is_init = False

    def __new__(cls, *args, **kw):
        if cls.instance is None:
            cls.instance = super().__new__(cls)
        return cls.instance

    def __init__(self, name):
        if not A.is_init:
            self.name = name
            A.is_init = True

异常处理

抛出异常

  • 自动抛出异常:当程序运行发生错误时,会自动抛出相应异常。
  • raise手动抛出异常:在需要的时候可以手动抛出异常:
if len(pwd) < 8:
    ex = Exception('密码长度不足8位')
    raise ex

捕获异常

  • 格式
try:
    pass
except 异常1:
    pass
except (异常2, 异常3):
    pass
except Exception as result:
    print(result)
else:
    pass
finally:
    pass
  • 异常类型:dir(__builtins__)

异常传递

  • 当函数/方法发生异常,会将异常传递给调用方。
  • 若异常传递到主程序仍未捕获,则程序会异常退出。
  • 一般在主程序中捕获异常,以便代码整洁。

调试

  • print():利用print()函数打印中间变量,观察变量值对程序的影响。
  • assert:利用断言。若断言正确则不会发生什么;若断言错误则会抛出异常。在运行时python3 -0 err.py可以忽略所有断言。
def f(s):
    n = int(s)
    asset n != 0
    print(10/n)
  • logging:Python 自带的模块可以记录和打印程序运行中的错误。
  • pdb:命令行单步调试,很麻烦。
  • IDE:利用 IDE 集成开发环境进行调试支持:断电、单步调试等多种调试功能。

单元测试和文档测试

单元测试
  • 单元测试是针对单一模块、函数、类等进行正确性检验,如对函数abs()就可以做如下的单元测试:正数、负数、0、其他。单元测试的好处是能确保单一模块是正确的,减少项目整体出错的可能性。单元测试的样例要包括常用的输入组合、边界条件和异常。
  • Python 中利用unittest模块可以进行单元测试。继承unittest.TestCase类,其中定义以test_xxx为方法名的方法用于不同的测试。常用的断言有assertEqual, assertRaises
import unittest

def f(n):
    sum = 0
    for i in range(n):
        sum += i
    return sum

class MyTest(unittest.TestCase):
    def test_haha(self):
        self.assertEqual(f(10), 45)
        self.assertEqual(f(100), 4950)

    def test_hehe(self):
        with self.assertRaises(TypeError):
            f('100')

if __name__ == '__main__':
    unittest.main()
文档测试

在编写类注释或者函数注释时,可以添加交互式命令的测试语句,Python 内置的doctest模块可以自动提取注释代码中的样例进行文档测试。也就是将 Python 交互界面的测试内容拷贝过来,并且只有输出调用栈错误时可以用...表示。

class Dict(dict):
    '''
    Simple dict but also support access as x.y style.

    >>> d1 = Dict()
    >>> d1['x'] = 100
    >>> d1.x
    100
    >>> d1.y = 200
    >>> d1['y']
    200
    >>> d2 = Dict(a=1, b=2, c='3')
    >>> d2.c
    '3'
    >>> d2['empty']
    Traceback (most recent call last):
        ...
    KeyError: 'empty'
    >>> d2.empty
    Traceback (most recent call last):
        ...
    AttributeError: 'Dict' object has no attribute 'empty'
    '''
    def __init__(self, **kw):
        super(Dict, self).__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Dict' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value

if __name__=='__main__':
    import doctest
    doctest.testmod()

with 与上下文管理器

with 的用法
# 初级
f = open('haha.txt', 'w')
f.write('hehe')
f.close()

# 进阶
f = open('haha.txt', 'w')
try:
    f.write('hehe')
except Exception as ret:
    print(ret)
finally:
    f.close()

# 高级
with open('haha.txt', 'w') as f:
    f.write('hehe')
上下文管理器

实现了__enter____exit__方法的类均可称为上下文管理器。上下文管理器对象可以使用with关键字,显然,文件类型实现了。__enter____exit__方法是一对原子操作,有进入就有退出。

class File(object):
    def __init__(self, name, mode):
        self.name = name
        self.mode = mode

    def __enter__(self):
        print('进入上下文......')
        self.f = open(self.name, self.mode)
        return self.f

    def __exit__(self):
        print('退出上下文......')
        self.close()

with File('haha.txt', 'w') as f:
    f.write('hehe')

文件操作

文件概述

  • 文件的存储方式(内部均为二进制存储)
    • 文本文件:可以用编辑器打开的。
    • 二进制文件:图片、视频、音频等。

文件相关函数

  • 1 个函数 3 个方法
    • open(name, mode):打开文件并返回文件对象。
    • f.read()或f.read(字节数)或f.readline():读取文件内容到内存。
    • f.write():将指定内容写入文件。
    • f.close():关闭文件。
  • 文件打开方式
    • r:只读。默认方式,文件不存在会报错。
    • w:只写。文件存在会覆盖,文件不存在会创建。
    • a:追写。文件存在则在末尾追加,文件不存在会创建。
    • r+, w+, a+:全部拥有读写权限。
    • rb, rb+, wb, wb+, ab, ab+:对二进制文件操作。
  • 文件/目录操作:import os
    • 文件操作:rename, remove
    • 目录操作:listdir, mkdir, rmdir, chdir

A.py去调用B.py时,B.py里面有打开文件操作,其路径是以A.py为准,而不是B.py

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值