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)