初学Python的学习笔记11----使用元类、错误处理和调试

栏目: 编程语言 · Python · 发布时间: 7年前

内容简介:使用元类,太难......

1.使用元类

(1)type()

# 使用type()创建一个class对象
type(className,fatherClassObj,classFuc)
# className:class的名称
# fatherClassObj:继承的父类集合,Python支持多重继承,如果只有一个父类,用tuple的单元素写法
# classFuc:class的方法名称与函数绑定,然后调用type()函数创建出class

1)可以查看一个类或者变量的类型

class Hello(object):
    def hello(self, name = 'world'):
        print('Hello, %s.' % name)

from hello import Hello
hello = Hello()
print hello.hello()
print type(Hello)

2)type()既可以返回一个对象的类型,又可以创建出新的类型

# 通过type()创建出Hello类
def fn(self, name = 'world'):
    print('Hello, %s.' % name)

Hello = type('Hello', (object), dict(hello=fn))   #创建class

hello = Hello()
print hello.hello()
print type(Hello)
print type(hello)

(2)metaclass:元类,可以用来创建类

控制类放入创建行为 定义metaclass ——> 创建类 ——>创建实例 可以把类看成是metaclass创建出来的"实例"

PS:这个可以不用看,因为看不懂也没事,对我最好的鼓励

例子:

# 定义ListMetaclass
class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value:self.append(value)
        return type.__new__(cls, name, bases, attrs)

# 定义类,要传入关键字metaclass
# 指示 Python 解释器在创建MyList的时候,要通过ListMetaclass.__new__()来创建
# __new__(当前准备创建的类的对象,类的名字,类继承的父类集合,类的方法集合)
class MyList(list, metaclass=ListMetaclass):
    pass

L = MyList()
L.add(1)
print L
# PS:普通的list没有add()
L2 = list()
L2.add()        # 报错

PS:可以用metaclass来实现ORM,对象-关系映射,这个对目前的我的水平来说太难了,我直接跳过了。

2.错误处理

(1)用错误码来表示是否出错

不方便,返回的正常结果和错误码混在一起需要调用者用大量的来判断是否出错

def foo():
    r = some_function()
    if r == (-1):
        return (-1)
    return r

def bar():
    r = foo():
    if r == (-1):
        print('Error')
    else:
        pass

(2)try

1)一种错误----一个expect

try:                                # 正常的代码执行
    print('try......')
    r = 10/0
    print('result', r)
expect ZeroDivisionError as e:      # 代码出错执行
    print('except:', e)
finally:                            # 这个语句可以没有
    print('finally.....')
print('END')

2)多种错误----多个except

try:                                # 正常的代码执行
    print('try......')
    r = 10 / int('a')
    print('result', r)
except ValueError as e:             # 代码出错执行 1
    print ('ValueError:', e)
expect ZeroDivisionError as e:      # 代码出错执行 2
    print('ZeroDivisionError:', e)
finally:                            # 这个语句可以没有
    print('finally.....')
print('END')

3)如果没有发生错误,可以在expect语句后面添加一个else

try:                                # 正常的代码执行
    print('try......')
    r = 10 / int('a')
    print('result', r)
except ValueError as e:             # 代码出错执行 1
    print ('ValueError:', e)
expect ZeroDivisionError as e:      # 代码出错执行 2
    print('ZeroDivisionError:', e)
else:
    print('No Error')
finally:                            # 这个语句可以没有
    print('finally.....')
print('END')

4)Python的所有错误类型都继承自BaseException,所以在使用expect时,不但捕获该类型的错误,还捕获其子类

try:
    foo()
expect ValueError as e:
    print ('ValueError')
expect UnicodeError as e:
    print ('Unicode Error')

PS:因为UnicodeError是ValueError的子类,所以第二个except永远也捕获不到错误

5)跨越多层调用 如果bar()出错了,这时候只要main()捕获到了,就可以处理

def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    try:
        bar('0')
    except Exception as e:
        print('Error:', e)
    finally:
        print('finally......')

main()

(3)调用栈

根据打印的错误一步步去找错误的源头

def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    bar('0')

main()

(4)记录错误

Python内置的logging模块可以非常容易地记录错误信息。 通过配置,logging可以把错误记录到日志文件里。

# 这样就算是错误,程序会打印完错误以后继续执行,并且正常退出
import logging
def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    try:
        bar('0')
    except Exception as e:
        logging.exception(e)

main()
print('END')

(5)抛出错误

1)根据需要,定义一个错误的class,选择好继承关系,然后,用raise语句抛出一个错误的实例

class FooError(ValueError):
    pass

def foo(s):
    n  = int(s)
    if n == 0:
        raise FooError('invalid value: %s' % s)
    return 10 / n

foo('0')


2)另一种错误处理的方法:使用Python内置的错误类型

def foo(s):
    n = int(s)
    if n == 0:
        raise ValueError('invalid value: %s' % s)
    return 10 / n

def bar():
    try:
        foo('0')
    except ValueError as e:
        print('ValueError')
        raise               # raise语句不带参数的话,会把当前错误原样抛出

bar()

3)在except中raise一个Error,可以把一种类型的错误转化为另一种类型

try:
    10 / 0
except ZeroDivisionError:
    raise ValueError('input error!')

PS:绝不能够把一个IOError转换成毫不相干的ValueError——————我没理解

3.调试

(1)print()

用print()把可能有问题的变量打印出来看看,执行后在输出中查找打印的变量值。 坏处是:调试成功以后要把多余的print()都要删除,比较麻烦。

def foo(s):
    n = int(s)
    print('>>> n = %d' % n)
    return 10 / n

def main():
    foo('0')

main()

(2)断言

凡是用print()的地方都可以替换成断言(assert)。 启动Python解释器可以用-0参数来关闭assert,关闭后可以把所有的assert语句当做pass。

def foo(s):
    n = int(s)
    assert n != 0, 'n is zero'      # 如果n != 0,则表示是True,如果断言失败,则assert语句会自动抛出AssertionError
    return 10 / n

def main():
    foo('0')

main()

(3)logging

1)通过简单的配置,一条语句可以同时输出到不同的地方,比如console和文件。 2)允许指定记录信息的级别,有debug, info, warning,error几个等级。 等级高的会覆盖等级低的。

import logging
logging.basicConfig(level=logging.INFO)

s = '0'
n = int(s)
logging.info('n = %d' % n)      # 输出一段文本
print(10 / n)

(4)pdb

启动Python的调试器pdb,让程序以简单方式运行,可以随时查看运行状态

# 准备好程序err.py
s = '0'
n = int(s)
print(10 / n)
# 启动pdb
python -m pdb err.py
# 输入命令1来查看代码
(Pdb) 1
# 输入命令n可以单步执行代码
(Pdb) n
# 输入命令 p 变量名 来查看变量
(Pdb) p s
# 输入命令q结束调试,退出程序
(Pdb) q

(5)pdb.set_trace()

import pdb
s = '0'
n = int(s)
pdb.set_trace()     # 运行到这里会自动暂停,现在就可以用命令p查看变量/或者用命令c继续执行
print(10 / n)

(6)IDE

支持调试功能的IDE: Visual Studio Code 、 PyCharm


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

创新者的窘境

创新者的窘境

克莱顿•克里斯坦森( Clayton M. Christensen ) / 胡建桥 / 中信出版社 / 2010-6 / 38.00元

管理类经典图书 o 被《福布斯》评为20世纪最具影响的20本商业图书之一 o “全球商业书籍奖”获奖图书 “颠覆大师”克莱顿•克里斯坦森经典力作。 《金融时报》/布兹•亚兰及汉密顿全球商务书刊颁发“1997年最佳商务书”奖 “1997年最佳商务‘实用’书”奖 一本书, 让志在必得者战战兢兢, 让犹豫不前者胸有成竹, 掀起激荡决策者的脑力风暴, ......一起来看看 《创新者的窘境》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具