python day 11: 类的补充,元类,魔法方法,异常处理

python day 11

2019/10/14

学习资料来自老男孩与尚学堂

1. 类的补充

1.1 通过反射来查找类,创建对象,设置对象的属性与方法

#通过__import__输入字符串文件名的方式导入模块
m = __import__('getattr_setattr', fromlist=True)
if hasattr(m, 'Foo'):
    # 去模块中找类
    Foo = getattr(m, 'Foo')
    # 根据类创建对象
    obj1 = Foo()
    # 通过对象找到对象的属性
    n1 = getattr(obj1, 'n1')
    # 通过反射找到对象的方法
    show = getattr(obj1, 'show')
    obj1.show()
    print(obj1.n1)
    # 通过反射设置对象的属性
    setattr(obj1, 'name', 'lanxing')
    print(obj1.name)

    # 通过反射设置对象的方法
    setattr(obj1, 'func1', lambda x: x + 1)
    # def func1(x):
    #     return x + 1

    # setattr(obj1, 'func1', func1)
    print(obj1.func1(2))

1.2 类的魔法方法:getitem,setitem

class Foo(object):
    def __init__(self, key):
        self.key = key

    def __call__(self, *args, **kwargs):  # __call__定义类的对象可以当作函数来调用

        return 1

    def __getitem__(self, key):  # obj['item'],obj[1:3]也是用的这种方法
        if self.key:
            return self.key
        else:
            return None

    def __setitem__(self, key, value):  # obj[key] = value
        self.key = value

    def __delitem__(self, key):  # del obj[key]
        pass

    def __iter__(self):  # for循环本质是调用了__itre_方法
        yield 1
        yield 2


# 本质上使用关键字class创建类时,就是调用了type函数来创建一个名为Foo的类。元组里面是父类,字典里面是类属性。
# r = Foo('item')  # 执行__init__方法
# # print(r())  # 执行__call__方法
# r['item'] = 'lanxing'  # r.__setitem__('item','lanxing')
# print(r['item'])  # r.__getitem__('item')
# del r['item']  #
# print(r[1:3])  #
# r[1:3] = [11, 22, 33]
# del r[1]
print(Foo, type(Foo))
# print(r.__dict__)  # 获取对象的所有属性与值,以字典形式返回
# {'key': [11, 22, 33]}
# print(Foo.__dict__)  # 获取类的所有属性与值,以字典形式返回
'''
{'__module__': '__main__', 
'__init__': <function Foo.__init__ at 0x0000020458CC08C8>, 
'__call__': <function Foo.__call__ at 0x0000020458CC0950>, 
'__getitem__': <function Foo.__getitem__ at 0x0000020458CC09D8>, 
'__setitem__': <function Foo.__setitem__ at 0x0000020458CC0A60>, 
'__delitem__': <function Foo.__delitem__ at 0x0000020458CC0AE8>, 
'__iter__': <function Foo.__iter__ at 0x0000020458CC0B70>, 
'__dict__': <attribute '__dict__' of 'Foo' objects>, 
'__weakref__': <attribute '__weakref__' of 'Foo' objects>, 
'__doc__': None}
'''
# for i in r:  # 本质是调用了__iter__方法
#     print(i)
# dic = dict(k1=11, k2=22)
# print(dic['k1'])
# del dic['k2']
# print(dic)

1.3 元类__metaclass__

元类的理解,这篇文章有助于理解元类。
使用元类
就是函数,方法调过来调过去,得使用几次才能理解元类。

class MyType(type):
    def __init__(self, what, base=None, dict=None, *args, **kwargs):
        super().__init__(what, base=None, dict=None, *args, **kwargs)

    def __call__(self, *args, **kwargs):
        obj = self.__new__(self, *args, **kwargs)
        self.__init__(obj)


class classname(metaclass=MyType):
    __metaclass__ = MyType  # 声明其元类是MyType

    def __init__(self, name, *args, **kwargs):
        self.name = name
        super().__init__(*args, **kwargs)

    def __new__(cls, *args, **kwargs):
        return object.__new__(cls, *args, **kwargs)


# 第一阶段,解释器从上到下执行代码创建Foo类
# 第二阶段,通过Foo类创建obj对象

# Foo2 = type('Foo2', (object, ), {'func': lambda x: x + 2, 'name': 'lanxing'}) #关键字class本质是执行了type(class,base,dict=None)方法

23. exception异常的处理

23.1 引入异常

异常的写法,把子类往前放,把父类往后放。可以存在多个except分支,一个except分支执行后,其他的就不会再次执行了。

'''
异常处理:
    需求:
        从键盘输入被除数与除数,求商并打印结果
1,输入的数据类型问题:valueError
2,ZeroDivisionError:division by zero
try-except-finally

'''
# 这种写法太耗费程序员精力了,语法也不简洁。
# if a.isdigit() and b.isdigit():
#     a1 = int(a)
#     b1 = int(b)
#     if b != 0:
#         c = a/b
#         print('商为:{0}'.format(c))
#     else:
#         print('ZeroDivisionError:division by zero')
#         print('除数不能为0')
a = input('请输入被除数:》》》')
b = input('请输入除数:》》》')
try:
    a1 = int(a)
    b1 = int(b)
    c = a/b
    print('mod = {0}'.format(c))
# 一旦捕获到异常,try里面异常后面的语句就不会被执行了。
# 异常只会执行一次。

# 捕获异常方式用法一:
# except:
#     print('输入类型有误或者除数为0')

# 捕获异常方式用法二:
# except Exception as e:#捕获异常并存储到e上
#     print(type(e))
#     print('输入类型有误或者除数为0')

# 捕获异常方式用法三(提倡这种写法):
# except ValueError:
#     print('输入类型有误')
# except ZeroDivisionError:
#     print('除数为0错误')
# except Exception:
#     print('遇到异常')

# 捕获异常方式用法四,这种写法与用法三会有区别:
# except (ValueError,ValueError) as e:
#     print('输入类型有误或除数为0')

# 捕获异常方式用法五:
except ValueError as e :
    print(e)
except Exception:
    print('遇到异常')

23.2 try-except-else-finally

'''
try:将有可能出异常的代码纳入try语句
except:捕获异常,有多种写法
else:可有可无,没有except就执行else
finally:最后执行,不管前面什么情况,都最终执行。
'''

try:
    file = open('123.txt','r',encoding='utf-8')
    content = file.read()
    print(content)
except Exception as e:
    print(e.args)
else:
    print('没有异常')
finally:
    file.close()

23.3 异常的传递过程

def test1():
    print('---'*10+'test1开始'+'---'*10)
    try:
        print(aa)
    except:
        pass
    print('---' * 10 + 'test1结束' + '---' * 10)

def test2():
    print('---'*10+'test2开始'+'---'*10)
    # try:
    #     test1()
    # except:
    #     pass

    print('---' * 10 + 'test2结束' + '---' * 10)

def test3():
    print('---'*10+'test3开始'+'---'*10)
    # try:
    #     test2()
    # except:
    #     pass
    print('---' * 10 + 'test3结束' + '---' * 10)

test3()

23.4 自定义异常

先定义一个Exception的子类,然后再在调用处使用raise语句。

'''
自定义异常:
    自己创建异常类,一定要继承自Exception.
    抛出异常 raise 异常对象
'''

class GenderError(Exception):
    def __init__(self):
        self.errMsg = '性别异常,只能设置为男或女'


class Student():
    def __init__(self,name,gender):
        self.name = name
        self.setGender(gender)

    def setGender(self,gender):
        if gender in ('男','女'):
            self.__gender = gender
        else:
            raise GenderError()

    def getGender(self):
        return  self.__gender

stu1 = Student('刘忙','男')
try:
    stu1.setGender('未知')
except Exception as e:
    print(type(e))
    print(e.args)
    print(e.errMsg)

原文地址:https://www.cnblogs.com/lanxing0422/p/pythonday11.html