什么是魔法函数
在python的类中,以 __ 开头和 __ 结尾的的实例方法,称为魔法函数。魔法函数能够改变对象的特性。
//定义一个类,实现__getitem__方法,使其对象能够直接在for循环中遍历
class Zoo:
def __init__(self, l):
self.animal = l
def __getitem__(self, i):
return self.animal[i]
zoo = Zoo(['cat', 'pig', 'dog', 'fish'])
for item in zoo:
print(item)
常用魔法函数
分组 | 方法名 | 含义 |
---|---|---|
字符串 | __str__ | 当对象被当成字符串使用,使用str()时,被调用 |
序列 | __len__ | 使用len()时被调用 |
__getitem__ | 使用for迭代时被调用 |
鸭子类型和多态
- 如果一只鸟能叫、游泳、喝水,那么我们就认为这只鸟是鸭子。
- 多态指的是,相同的接口,不同的子类,有不同的具体实现方法。
- 在Java中,是通过定义一个接口类,然后通过子类继承接口,并且实现具体的接口,实现多态的效果。
- 在python中,只需要在不同的类中,定义相同的实例方法。使用变量接收其中类创建实例,通过该变量调用该实例方法,实现多态。
- 在java中通过继承实现 IS-A的概念,但是python中只要类实现了某个魔法函数就能实现IS-A的概念。
比如,在java中,类需要继承迭代器接口,这个类才是迭代器,能进行迭代器的操作。在python中,类实现__len__\ __getitem__ 魔法行数,他就是一个迭代器,能通过for循环进行迭代。
class Cat:
def run(self):
print("CAT 能跑")
class Pig:
def run(self):
print("PIG 能慢跑")
# 通过Cat类实例化cat实例,赋值给某个变量
animal = Cat()
# 通过变量调用方法
animal.run()
# 通过Pig类实例化cat实例,赋值给某个变量
animal = Pig()
# 通过变量调用方法,调用相同的实例方法,Pig和Cat都实现了相同的方法,但具体的实现不一致。
animal.run()
class Cat:
def run(self):
print("CAT 能跑")
class Pig:
def run(self):
print("PIG 能慢跑")
# 通过Cat类实例化cat实例,赋值给某个变量
animal = Cat()
# 通过变量调用方法
animal.run()
# 通过Pig类实例化cat实例,赋值给某个变量
animal = Pig()
# 通过变量调用方法,调用相同的实例方法,Pig和Cat都实现了相同的方法,但具体的实现不一致。
animal.run()
抽象基类
python能够通过使用鸭子变量的范式实现多态。但是通过这种方式存在两个问题。
- 无法判断类具有某一种功能,只能判断类是否有某个功能。
- 无法约束实例方法必须存在,实例方法方法的方法名、参数一致。
python提供了另外一种方法,抽象基类来解决这些问题。抽象基类其实就类似java的接口,无法实例化,继承了抽象基类的类,必须提供接口的具体实现,否则无法实例化
#鸭子变量
class Cat:
def running(self):
print("cat 能跑")
def eat(self):
print("cat 能吃")
#需要一个一个的判断是否具有某个实例方法
print(hasattr(Cat, 'running'))
print(hasattr(Cat, 'eat'))
#抽象基类
class Animals:
def running(self):
raise NotImplementedError
def eat(self):
raise NotImplementedError
class Cat(Animals):
def running(self):
print("cat 能跑")
def eat(self):
print("cat 能吃")
cat = Cat()
//通过抽象基类,一次能判断实例是否具有Animals这组方法
print(isinstance(cat, Animals))
#通过父类抛出异常实现抽象基类,在实例方式调用时报错
class Animals:
def running(self):
raise NotImplementedError
def eat(self):
raise NotImplementedError
class Cat(Animals):
def running(self):
print("cat 能跑")
#cat类必须需要实现Animals的所有接口,否则调用时出错
cat = Cat()
cat.eat()
#定义抽象基类的另一种方式,继承abc类,在创建子类时会报错
import abc
class Animals(metaclass=abc.ABCMeta):
@abc.abstractmethod
def running(self):
pass
@abc.abstractmethod
def eat(self):
pass
class Cat(Animals):
def running(self):
print("cat 能跑")
cat = Cat()
isintance和type
- isintance:判断实例是否是某个类或其父类创建的
- type:返回实例的类对象
- ==:判断两个变量的数值是否相等
- is:判断两个变量指向的地址是否相等
class A:
pass
class B(A):
pass
b = B()
print('isinstance(a, A)', isinstance(b, A))
print('isinstance(a, A)', isinstance(b, B))
print('type(b) is B', type(b) is B)
print('type(b) == B', type(b) == B)
print('type(b) is B', type(b) is A)
print('type(b) is B', type(b) == A)
类的反射
通过类的反射,能够查看类的内部结构。
python 通过 <object>.__dist__和 dir()函数实现类的反射
异常
def f1():
try:
#raise IndexError
return 1
except IndexError as e:
print("捕获异常IndexError")
return 2
except IsADirectoryError as e:
print('捕获异常')
return 3
else:
print('没有异常')
return 4
finally:
print('finally')
return 5
print(f1())
- 通过raise 抛出异常
- 通过多个except 能够捕获多个异常
- 当try中的代码没有异常产生时,会执行else
- 在finally中,主要是写资源回收的代码,例如关闭数据库链接、关闭文件等
- finally的代码无论如何都会执行,而已写在finally中的retrun 语句会覆盖写在try/except中的return语句
上下文管理器、with语句
上下文管理器,主要是为某操作提供前置初始化和后续资源回收。
- 通过魔法函数实现上下文管理器
class A:
def __init__(self):
print("构造函数")
def __enter__(self):
print('enter')
return self
def __exit__(self,p1,p2,p3):
print('exit')
def method(self):
print("逻辑处理")
with A() as a:
a.method()
只要类实现了这两个魔法方法,这个类就支持上下文协议,能使用with语法,先执行__enter__,让后是method,最后__exit__
- 通过装饰器实现
import contextlib
@contextlib.contextmanager
def open_file(file_name):
print("open")
yield{}
print("end")
with open_file("/path/to/somefile") as f :
print('打开文件')