一、魔术方法(内置方法)
'''
魔术方法(内置方法):
类里面内置的双下划线开头的一些方法,它们具有特殊的功能,称之为魔术方法,简称魔法
比如:__init__
魔术方法的学习需要掌握每个方法什么时候触发或者执行
__str__,__repr__方法
__del__方法
isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
issubclass(sub, super)检查sub类是否是 super 类的派生类
__doc__
__enter__和__exit__
__setattr__,__delattr__,__getattr__
__setitem__,__getitem,__delitem__
__call__
'''
1. __str__和__repr__方法
'''
"""
1. 打印对象的时候会自动触发这两个方法
2. 如果有返回值,类型必须是字符串形式的
3. 如果有返回值,那么,打印的结果就是它的返回值
4. 如果这两个方法同时存在,优先使用__str__方法,__str__的优先级高
5. print打印会执行这两个任意一个,str()会执行__str__, repr()会执行__repr__
"""
__str__方法会在对象被打印时自动触发,print功能打印的就是它的返回值,
我们通常基于方法来定制对象的打印信息,该方法必须返回字符串类型
'''
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return '<Name:%s Age:%s>' % (self.name, self.age)
p = People('lili', 18)
print(p)
class School:
def __init__(self, name, addr, type):
self.name = name
self.addr = addr
self.type = type
def __repr__(self):
return 'School(%s,%s)' % (self.name, self.addr)
def __str__(self):
return '(%s,%s)' % (self.name, self.addr)
s1 = School('oldboy1', '北京', '私立')
print('from repr: ', repr(s1))
print('from str: ', str(s1))
print(s1)
'''
str函数或者print函数--->obj.__str__()
repr或者交互式解释器--->obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
注意:这俩方法的返回值必须是字符串,否则抛出异常
'''
2. __del__方法
'''
"""
1. 当删除对象的时候,会自动触发
2. 当程序执行结束的时候也会触发方法的执行
3. 它的作用一般用来清理数据
"""
__del__会在对象被删除时自动触发。由于Python自带的垃圾回收机制会自动清理Python程序的资源,
所以当一个对象只占用应用程序级资源时,完全没必要为对象定制__del__方法,
但在产生一个对象的同时涉及到申请系统资源(比如系统打开的文件、网络连接等)的情况下,
关于系统资源的回收,Python的垃圾回收机制便派不上用场了,需要我们为对象定制该方法,
用来在对象被删除时自动触发回收系统资源的操作
'''
from sqlite3 import connect
class MySQL:
def __init__(self, ip, port):
self.conn = connect(ip, port)
def __del__(self):
self.conn.close()
obj = MySQL('127.0.0.1', 3306)
3. isinstance(obj,cls)和issubclass(sub,super)
'''
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
'''
class Foo(object):
pass
obj = Foo()
print(isinstance(obj, Foo))
'''
issubclass(sub, super)检查sub类是否是 super 类的派生类
'''
class Foo(object):
pass
class Bar(Foo):
pass
print(issubclass(Bar, Foo))
4. doc
它是查看类内部的详细信息,类内部的注释内容
class Foo:
'我是描述信息'
pass
print(Foo.__doc__)
---------------------继承-----------------------------
class Foo:
'我是描述信息'
pass
class Bar(Foo):
pass
print(Bar.__doc__)
5. enter__和__exit
"""
1. 当出现with语句的时候,会触发__enter__方法
2. 如果__enter__方法中有返回值,则就赋值给as后面的变量名
3. 开始执行with代码块,当with代码块执行完毕之后,在执行__exit__方法
4. with代码块中出现了异常,则在__exit__方法中会拿到异常的信息(异常类型、异常值、追溯信息)
5. 如果在__exit__方法中return True,忽略异常,相当于什么都没发生
举例: with打开文件
"""
'''在操作文件对象的时候可以这么写'''
with open('a.txt') as f:
'代码块'
'''
上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,
必须在这个对象的类中声明__enter__和__exit__方法
'''
class Open:
def __init__(self, name):
self.name = name
def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
with Open('a.txt') as f:
print('=====>执行代码块')
'''
__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,
with语句中代码块出现异常,则with后的代码都无法执行
'''
class Open:
def __init__(self, name):
self.name = name
def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
print(exc_type)
print(exc_val)
print(exc_tb)
with Open('a.txt') as f:
print('=====>执行代码块')
raise AttributeError('***着火啦,救火啊***')
print('0' * 100)
'''
如果__exit()返回值为True,那么异常会被清空,
就好像啥都没发生一样,with后的语句正常执行
'''
class Open:
def __init__(self, name):
self.name = name
def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
print(exc_type)
print(exc_val)
print(exc_tb)
return True
with Open('a.txt') as f:
print('=====>执行代码块')
raise AttributeError('***着火啦,救火啊***')
print('0' * 100)
6. setattr,delattr,getattr
"""
前提:必须是使用点语法(.) obj.x
__getattr__: 获取一个不存在的属性名的时候,会自动触发__getattr__的执行,并且有个参数:属性名
__setattr__:设置一个不存在的属性的时候,会自动触发__setattr__的执行,并且有两个参数:key,value, self.__dict__[key] = value =====> self.key = value=====> 无限递归
__delattr__:删除一个属性的时候,触发的函数
"""
class Foo:
x = 1
def __init__(self, y):
self.y = y
def __getattr__(self, item):
print('----> from getattr:你找的属性不存在')
def __setattr__(self, key, value):
print('----> from setattr')
def __delattr__(self, item):
print('----> from delattr')
self.__dict__.pop(item)
''' __setattr__添加/修改属性会触发它的执行'''
f1 = Foo(10)
print(f1.__dict__)
'''这句打印是因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,
就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值'''
f1.z = 3
print(f1.__dict__)
'''__delattr__删除属性的时候会触发'''
f1.__dict__['a'] = 3
'''这句赋值是因为我们可以直接修改属性字典,来完成添加/修改属性的操作'''
del f1.a
print(f1.__dict__)
'''__getattr__只有在使用点调用属性且属性不存在的时候才会触发'''
f1.xxxxxx
7. setitem 和 getitem 和 delitem
"""
前提:必须是使用中括号([]) obj['x']
__getitem__: 获取一个不存在的属性名的时候,会自动触发__getitem__的执行,并且有个参数:属性名
__setitem__:设置一个不存在的属性的时候,会自动触发__setitem__的执行,并且有两个参数:key,value, self.__dict__[key] = value =====> self.key = value=====> 无限递归
__delitem__:删除一个属性的时候,触发的函数
"""
给你一个字典,字典通过key取值,中括号的形式,不支持句点符,所以,现在想让字典支持点取值
d = {"a":1}
d['a']
d.a
class C(dict):
def __getattr__(self, item):
return self.__dict__[item]
obj = C()
obj.a
class Foo:
def __init__(self, name):
self.name = name
def __getitem__(self, item):
print(self.__dict__[item])
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, key):
print('del obj[key]时,我执行')
self.__dict__.pop(key)
def __delattr__(self, item):
print('del obj.key时,我执行')
self.__dict__.pop(item)
f1 = Foo('sb')
f1['age'] = 18
f1['age1'] = 19
del f1.age1
del f1['age']
f1['name'] = 'alex'
print(f1.__dict__)
8.call
"""
对象加括号会自动触发__call__的执行,如果有返回值,就给到了对象加括号的位置
"""
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo()
obj()
Foo()()
二、反射
'''
反射其实就是通过字符串的形式来操作对象的属性
'''
class Student:
school = 'SH'
def __init__(self, name, age):
self.name = name
self.age = age
def index(self):
print('Student.index')
stu = Student('jason', 20)
"""getattr() setattr() delattr() hasattr()"""
1.getattr()
res = getattr(stu, 'name')
res1 = getattr(stu, 'age1', '没有age1')
res2 = getattr(stu, 'index')
2.setattr()
setattr(stu, 'x', 1)
setattr(stu, 'name', '666')
print(stu.__dict__)
3.delattr()
delattr(stu, 'name')
4.hasattr()
print(hasattr(stu, 'index'))
案例
class FtpServer:
def serve_forever(self):
while True:
inp = input('input your cmd>>: ').strip()
cmd, file = inp.split()
if hasattr(self, cmd):
func = getattr(self, cmd)
func(file)
def get(self, file):
print('Downloading %s...' % file)
def put(self, file):
print('Uploading %s...' % file)
server = FtpServer()
server.serve_forever()
三、异常补充
'''
1.异常就是错误发生的信息,必须要做处理,否则,后续代码无法正常运行
2.如何捕获异常
try:
# 被监测代码
pass
except 异常类型:
pass
else:
pass
finally:
pass
3.如何抛出异常
import abc
class Animal:
@abc.abstractmethod
def speak(self):
raise Exception('请先实现Animal中的speak方法')
class People(Animal):
def speak(self):
pass
"""主动抛出异常"""
stu = People()
stu.speak()
4.自定义异常
class MyException(BaseException):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
raise MyException('这是异常信息')
'''