このブログは廖雪峰python教程の練習問題を記録している(六)


列挙クラスの使用
2つのコードを貼りましょう.
>>> from enum import Enum
>>> Month1=Enum('Month2',('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'))
>>> Month1.Jan   #                Month1(         )    ,       Enum()     Month2    ,,,,
1>
>>> Month2.Feb   #  ,   Month2       
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'Month2' is not defined
>>> Month1.Sep  
9>
>>> for name,member in Month1.__members__.items():  #       for in             
...     print(name,'-->',member,member.value)
...
Jan --> Month2.Jan 1      name(  Enum     ),member(  Month1.name    )      member.value  
Feb --> Month2.Feb 2
Mar --> Month2.Mar 3
Apr --> Month2.Apr 4
May --> Month2.May 5
Jun --> Month2.Jun 6
Jul --> Month2.Jul 7
Aug --> Month2.Aug 8
Sep --> Month2.Sep 9
Oct --> Month2.Oct 10
Nov --> Month2.Nov 11
Dec --> Month2.Dec 12

2つ目の例では、Enumを継承するクラスを定義できます.
>>> from enum import Enum,unique
>>> @unique
... class Weekday(Enum):
...     Sun=0
...     Mon=1
...     Thu=2
...     Wed=3
...     Thr=4
...     Fri=5
...     Sat=6
...
>>> Weekday.Mon
1>
>>> Weekday['Mon']
1>
>>> Weekday(1)
1>

最後に、「Studioのgenderプロパティを列挙タイプに変更すると、文字列の使用を避けることができます.」という宿題を書きます.
>>> from enum import Enum,unique
>>> @unique
... class Gender(Enum):
...     male=0
...     female=1
...
>>> class Student(object):
...     def __init__(self,name,gender):
...         self.name=name
...         self.gender=gender
...
>>> xuan=Student('Zhangxuan',Gender.female)
>>> xuan.gender==Gender.female
True
>>>

メタクラスの使用
まずhelloを書きます.pyファイル(モジュール)は、次のように書かれています.
 class Hello(object):
...     def hello(self,name='Zhangxuan'):
...         print("hello,%s."%name)
...
>>>

次に、右側のコンソールに次のように入力します.
from hello import Hello

h=Hello()   #  h  Hello     

h.hello()    #  h    (  )hello() 
hello,Zhangxuan.

type(Hello)
Out[158]: type  #Hello           

type(h)
Out[159]: hello.Hello

では、type()関数を使用してクラスを動的に作成するにはどうすればいいのでしょうか.type()関数は、class Hello(object)を使用することなく、type()関数を使用してHelloクラスを作成することができます.コードは次のとおりです.
>>> def fn(self,name='World'):
...     print("Hello,%s."%name)
...
>>> Hello=type('Hello',(object,),dict(hello=fn))
>>> h=Hello()
>>> h.hello()
Hello,World.
>>> type(Hello)
'type'>
>>> type(h)
'__main__.Hello'>
>>>
```      class , type()          :
1.    
2.      ,  tuple()           ,
3.class     ,       fn     hello 





这里写代码片
“`

>>> Hello1=type('Hello2',(object,),dict(hello=fn))
>>> h=Hello2()   #               Hello1!!!      type()   ,  Hello2          ,,,
Traceback (most recent call last):
  File "", line 1, in <module>
NameError: name 'Hello2' is not defined
>>> h=Hello1()
>>> h.hello()
hello,Zhangxuan.
>>> type(Hello1)
<class 'type'>
>>> type(h)
<class '__main__.Hello2'>

エラー、デバッグ、テスト
エラー処理
身につける必要があるExcept...の使い方:
def func(n):
    try:
        print("Trying....")
        value=10/n
        #print("the value is{}".format(value))
    except ZeroDivisionError as e:
        print("error",e)
    else:
        print("No error!")
        print("the value is{}".format(value))
    finally:
        print("Finally.....")

def main():

    func(10)

main()

実際には、ValueError、ZeroDivisionErrorなど、さまざまなタイプのエラーをキャプチャするために複数のexceptを返すこともできます.
def func(s):
    try:
        print("Trying!")
        value=10/int(s)
        print("the value is {}".format(value))
    except ValueError as e:
        print("error1:",e)
    except ZeroDivisionError as e:
        print("error2:",e)
    finally:
        print("Finally!")

def main():
    #func('xixi')  #        
    func('0') #        

main()

関数間呼び出しに遭遇した場合は適切な関数でエラーをキャプチャするだけでよい
def func1(s):
        value=10/int(s)
        return value

def func2(s):  #func2   func1
    return func1(s)*2

def main():   #main     func2
    s='xixi'
    #s='0'
    try:
        print("Trying!")
        value=func2(s)+100
        print("the value is {}".format(value))
    except ValueError as e:
        print("Error1:",e)
    except ZeroDivisionError as e:
        print("Error2:",e)
    else:
        print("There is no error!")
    finally:
        print("Finally!")

    print('End!')

main()

複数の関数に呼び出し関係がある場合、ある関数がエラーになる可能性があります.上位で呼び出す関数を一つ一つキャプチャする必要はありません.適切な階層でエラーをキャプチャするだけでいいです.
エラーキャプチャを行わないと、メイン関数でエラーが実行されると、次のように実行されません.
def func(s):
    value=10/int(s)
    return value

def func2(s):
    return func(s)*2

def main():
    s='0'
    value=func2(s)
    print("the value is {}".format(value))
    print('End')  #         ,,,

main()

再main()関数の最初のprint文がvalueの値を印刷するとエラーが発生することを知っています.value自体に問題があるint(‘0’)が0 func 1に戻って10/int(‘0’)を計算するとエラーが発生し、func 2がエラーになります.main()が間違っているので、後のprint(‘End’)も実行されません.
エラーメッセージは次のとおりです.

  File "E:/pyhtonworkspace/py3-pratice/bymyself_practice/python_Liaoxuefeng/20180211/hello.py", line 116, in 
    main()

  File "E:/pyhtonworkspace/py3-pratice/bymyself_practice/python_Liaoxuefeng/20180211/hello.py", line 112, in main
    value=func2(s)

  File "E:/pyhtonworkspace/py3-pratice/bymyself_practice/python_Liaoxuefeng/20180211/hello.py", line 108, in func2
    return func(s)*2

  File "E:/pyhtonworkspace/py3-pratice/bymyself_practice/python_Liaoxuefeng/20180211/hello.py", line 104, in func
    value=10/int(s)

ZeroDivisionError: division by zero

しかし、エラーと同時にエラー情報を投げ出し、プログラムを実行し続けるにはloggingを使用します.

import logging

def func(s):
    value=10/int(s)
    return value

def main():
    try:
        value=func('0')
        print("the value is {}".format(value)) #       ,    try except     try                  except    
    except ZeroDivisionError as e:
        logging.exception(e)

    print('End!!        ')  #   logging                   ,        

main(

コンソールは次のように動作します.
ERROR:root:division by zero
Traceback (most recent call last):
  File "E:/pyhtonworkspace/py3-pratice/bymyself_practice/python_Liaoxuefeng/20180211/hello.py", line 128, in main
    value=func('0')
  File "E:/pyhtonworkspace/py3-pratice/bymyself_practice/python_Liaoxuefeng/20180211/hello.py", line 123, in func
    value=10/int(s)
ZeroDivisionError: division by zero
End!!        

ここではエラー情報を記録するだけで、以前のようにめちゃくちゃなエラー情報を投げ出すことはなく(プログラムを見るとエラーが発生するようなものは、実は自分で上記の2つの関数を実行してコンソール出力の形式を比較することができます)、プログラムの実行を保証することができるので、try except関数以外の最後のprint文を出力します
最後にもう一つの作業を書きます.「次のコードを実行し、異常情報に基づいて分析し、エラーのソースを特定し、修復します.」
#                           ,    ,   

from functools import reduce

def str2num(s):
    return int(s)

def calc(exp):
    ss = exp.split('+')
    ns = map(str2num, ss)
    return reduce(lambda acc, x: acc + x, ns)

def main():
    r = calc('100 + 200 + 345')
    print('100 + 200 + 345 =', r)
    r = calc('99 + 88 + 7.6')
    print('99 + 88 + 7.6 =', r)

main()

このコードの実行後に表示されるエラーは次のとおりです.
  File "E:/pyhtonworkspace/py3-pratice/bymyself_practice/python_Liaoxuefeng/20180211/hello.py", line 157, in 
    main()

  File "E:/pyhtonworkspace/py3-pratice/bymyself_practice/python_Liaoxuefeng/20180211/hello.py", line 154, in main
    r = calc('99 + 88 + 7.6')

  File "E:/pyhtonworkspace/py3-pratice/bymyself_practice/python_Liaoxuefeng/20180211/hello.py", line 149, in calc
    return reduce(lambda acc, x: acc + x, ns)

  File "E:/pyhtonworkspace/py3-pratice/bymyself_practice/python_Liaoxuefeng/20180211/hello.py", line 144, in str2num
    return int(s)

ValueError: invalid literal for int() with base 10: ' 7.6'

コードは次のように変更されます.


from functools import reduce

def str2num(s):
    #return int(s)   #       
    try:
        number=int(s)

    except:   #            except      try except        except!!     if else      if else
        try:
            number=float(s)
        except:
            print("what you input is not a number!!!")

    finally:

        return number



def calc(exp):
    ss = exp.split('+')  #    calc()       +               '100' ,'200' split      list
    ns = map(str2num, ss)#    map          str2num  (              )     ss           !
    return reduce(lambda acc, x: acc + x, ns)  #   reduce                  map        (         )

def main():
    r = calc('100 + 200 + 345')
    print('100 + 200 + 345 =', r)
    r = calc('99 + 88 + 7.6')
    print('99 + 88 + 7.6 =', r)

main()   

それからsplitを復習します.
>>>
>>> s='100+200+300'
>>> L=s.split('+')   #split          
>>> L
['100', '200', '300']
>>>

寮に帰りました.