[2]魔法函数、类和对象

什么是魔法函数

在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('打开文件')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值