小白学Python之第十五天

使用枚举类

当我们在定义常量时,一个方法就是用大写变量通过整数来定义,这种方法简单,但是缺点是类型是int,并且仍然是变量,更好的方法时为这样的枚举类型定义一个class类型,然后,每个常量都是class的唯一的一个实例。

枚举的实现:

1.首先要导入enum模块

2.枚举定义要用class关键字,继承Enum类

3.用于定义枚举的class和定义类的class是有区别的。

示例:

fromenumimport Enum

classColor(Enum):

red

=1

orange =2

yellow =3

green =4

blue =5

indigo =6

purple =7

代码分析:

1.我们定义了颜色的枚举Color

2.有7个成员,每个成员都有自己的名字。例如:Colour.red成员的名称就是:red。值是1.

3.每个成员的数据类型就是它属的枚举。

注意:

1.定义枚举时,成员名称不能重复,不然会出现TypeError错误。

2.默认情况下,不同的成员值允许相同,但是两个相同值得成员,第二个成员名称视作是第一个成员名称的别名。在通过值获取枚举成员时,只能获取到第一个成员。

3.如果要限制枚举的成员不能有相同的值,可以使用装饰器@unique

fromenumimportEnum,unique

@unique

classColour(Enum):

red =1

yellow =1

执行就会出现:ValueError: duplicate values found in : yellow -> red

访问枚举:

1.通过成员名称获取成员

Color['red']

2.通过成员值获取

Color(5)

2.通过成员,来获取它的名称和值

yanse = Color.blue

yanse.name

'blue'

yanse.value

5

迭代枚举成员

1.遍历

forcolorinColor:

print(color)

输出为:Color.redColor.orangeColor.yellowColor.greenColor.blueColor.indigoColor.purple

2.如果成员值相同,就会遍历第一个成员

fromenumimport Enum

classColor(Enum):

red

=1

orange =2

yellow =3

green =4

blue =5

indigo =6

purple =7

red_wai =1

forcolorinColor:

print(color)

Color.redColor.orangeColor.yellowColor.greenColor.blueColor.indigoColor.purple

3.如果想把重复值也遍历出来,就要在枚举时加一个特殊属性__member__

fromenumimport Enum

classColor(Enum):

red

=1

orange =2

yellow =3

green =4

blue =5

indigo =6

purple =7

red_wai =1

forcolor in Color.__members__.items():

print(color)

输出为:('red', )('orange', )('yellow', )('green', )('blue', )('indigo', )('purple', )('red_wai', )

比较:

1.同一性比较

Color.redisColor.red

True

Color.redisnotColor.blue

True

2.等值比较

Color.blue == Color.red 

False

3.不能进行大小比较

Color.red>Color.blue

TypeError: '>' not supported between instances of 'Color' and 'Color'

参考资料:

廖雪峰博客:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143191235886950998592cd3e426e91687cdae696e64b000

航行博客:https://www.cnblogs.com/ucos/p/5896861.html

使用元类

type()

在定义类型时,我们通常用class 类名称(object).......来定义,但在Python解释器中,遇到class定义,仅仅只是扫描一下,然后就调用type()函数创建出class。也就是说我们通过定义type()也可以创建出类来,

type()函数创建类要依次传入三个参数:

1.class的名称

2.继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法

3.class的方法名称与函数绑定

示例:

deffn(self,name ='world'):#先定义函数

print('Hello,%s.'%name)

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

调用:

h = Hello()

h.hello()

Hello,world.

print(type(Hello))

print(type(h))

type()函数可以查看一个类型或变量的类型,Hello是一个class,它的类型就是type。而h是一个实例,它的类型就是class Hello。

type()函数既可以返回函数类型,又可以创建新的函数。

但正常情况下,我们都用class Xxx.....来定义类,type()函数也允许我们动态创建出类来,也就是说,动态语言本身支持运行期动态创建类,这和静态语言非常不同。

metaclass

metaclass直译就是元类,我们可以通过其创建出类:

先定义metaclass,就可以创建类,最后创建实例。

metaclass是Python面向对象里最难理解的,也是最难使用的魔术代码。正常情况下,不会碰到需要使用metaclass的情况。

所以暂且不看了。下面是SQL语句,没看懂。

错误、调试和测试

错误处理

在程序运行时,我们通常会遇到错误,如果返回错误码的话,我们在查看错误时非常不方便,因为函数本身应该返回的正常结果和错误码混在一起,造成调用者必须用大量的代码来判断是否出错。所以在python中内置了一套语句:try.........except..........finally........

try

如果我们认为某些代码可能会出错时,就可以用try来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳至错误处理代码,即except后,如果有finally语句块,则执行此语句块,至此,执行完毕。

举例:

try:

print('try......')

r =10/ int('a')

print('result:',r)

exceptValueErrorase:

print('ValueError:',e)

exceptZeroDivisionErrorase:

print('ZeroDivisonError:', e)

finally:

print('finally....')

print('END')

int()函数可能会抛出ValueError,还有ZeroDivisionError错误,所以用except来排除。也可以在except语句块后加一个else语句,当没有错误发生时,就会自动执行else语句块。

try:

print('try......')

r =10/ int('a')

print('result:',r)

exceptValueErrorase:

print('ValueError:',e)

exceptZeroDivisionErrorase:

print('ZeroDivisonError:', e)

else:

print('NoError')

finally:

print('finally....')

print('END')

注意:在Python中,错误也是一个class,也有父类和子类。所有的BaseException,在使用except时需要注意的是,它不光捕获该类型的错误,还将其子类‘一网打尽’。

使用try......except还有一个好处,可以跨越多层调用比如说main()函数调用foo()函数,foo()调用bar(),结果bar()出错了,这时只要我们捕获到main()函数就可以处理错误了,也就是说我们不需要再每一个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了。大大减小了写try......except.......finally的麻烦了。

调用栈

如果错误没有被捕获,那么错误就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。来解读下错误信息。举例:

#err.py:

deffoo(s):

return10/int(s)

defbar(s):

returnfoo(s)*2

defmain():

bar('0')

main()

因为int(s)返回的是0,在计算10/0时出错了。这是错误的源头。

在出错的时候,一定要分析错误的调用栈的信息,才能定位错误的位置。

记录错误

我们不捕获错误可以让解释器来打印出错误堆栈,但同时程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,同时让程序继续执行下去。然后分析错误信息。

Python内置的logging模块可以非常容易地记录错误信息:

importlogging

deffoo(s):

return10/int(s)

defbar(s):

returnfoo(s)*2

defmain():

try:

bar('0')

exceptExceptionase:

logging.exception(e)

main()

print('END')

通过配置,logging还可以把错误记录到日志文件里,方便日后排查。

抛出错误

错误不是凭空出现的,而是有意创建的,Python内置函数会抛出很多类型的错误,我们自己编写的函数也可以抛出错误。

如果要抛出一个错误。根据需要,可以定义一个错误的class,选择好继承关系,然后。用raise语句抛出一个错误的实例:

#err_raise.py

classFooError(ValueError):

pass

deffoo(s):

n = int(s)

ifn ==0:

raiseFooError('invalid value: %s'%s)

return10/n

foo('0')

错误中就出现了我们自己定义的错误。

只有在必要的时候我们才自己定义错误类型,尽量使用python内置的错误类型。

有时候我们不知道错误如何处理,在捕获到错误时我们会继续往上抛,让顶层调用者去处理,

raise语句如果不带参数,就会把当前的错误原样抛出。

deffoo(s):

n = int(s)

ifn==0:

raiseValueError('invalid value: %s'%s)

return10/n

defbar():

try:

foo('0')

exceptValueErrorase:

print('ValueError')

raise

bar()

此外,在except中raise一个Error,还可以把一种错误转化成另一个错误:

try:

10/0

exceptZeroDivisonError:

raiseValueError('input error!')

但前提是转换逻辑要合理,不能转化成毫不相关的错误类型。

调试

程序写完能正常运行的概率很小,基本不会超过1%,总会出现或简单或复杂的bug,所以我们需要一整套的调试方法去修复这些bug。

print()语句:简单的方法就是把它打印出来,用print()语句把可能出现问题的变量打印出来看看。但这种办法是在修正后还要在删除掉print(),所以有了下面的方法:

断言(assert

凡是print()语句来辅助查看的地方,都可以用断言(assert)来替代。

deffoo(s):

n = int(s)

assertn !=0,'n is zero!'

return10/n

defmain():

foo('0')

例子中的assert意思是,表达式 n != 0应该是True,否则根据程序运行的逻辑,后面的代码肯定会出错的。如果断言失败,assert语句本身会抛出AssertionError

AssertionError: n is zero!

但如果程序中充满着assert,和print()语句相比也好不哪去,不过,我们可以启动python解释器时可以用-0参数来关闭assert。关闭后,可以把所有的assert语句当成pass来看。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容