Python高级编程(17):python中的with语句
要使用 with 语句,首先要明白上下文管理器这一概念。有了上下文管理器,with 语句才能工作。
上下文管理协议(Context Management Protocol):包含方法 __enter__() 和__exit__(),支持该协议的对象要实现这两个方法。
上下文管理器(Context Manager):支持上下文管理协议的对象,这种对象实现了__enter__() 和__exit__()方法。上下文管理器定义执行 with 语句时要建立的运行时上下文,负责执行 with 语句块上下文中的进入与退出操作。通常使用 with 语句调用上下文管理器,也可以通过直接调用其方法来使用。说白了就是你只要是包含了__enter__() 和__exit__()这两个魔法函数,我就可以把你当做一个上下文管理器(鸭子类型)来操作。
我们先来看一段代码,给这个函数实现上下文管理协议:
12345678910111213141516171819class Sample: def __enter__(self): # 获取资源 print("enter&q ...
Python高级编程(16):mixin继承
mixin混合模式的特点:1、mixin类功能单一;2、不和基类关联,可以和任意基类进行组合,基类可以不和mixin关联就能初始化成功;3、在mixin中,不要使用super这种用法;最后尽量以mixin结尾
参考文章:Python mixin模式
Python中的Mixin模式
Python高级编程(15):super真的是调用父类吗?
这一部分非常重要,我相信很多人心中一直觉得super函数就是调用父类,但是结果是这样吗,我们来好好聊一下这个super。我们先来看一段代码:
1234567891011121314class A: def __init__(self): print("A")class B(A): def __init__(self): print("B")if __name__ == '__main__': b = B()# 输出结果:B
这个是没有问题的,很好理解,我们接着来看下一段代码:
12345678910111213class A: def __init__(self): print("A")class B(A): def __init__(self): print("B") super().__init__()# 输出结果:BA
有人说这不就是调用了父类的方法么,我暂且不说话。并向你扔了2个问 ...
Python高级编程(14):python对象的自省机制
自省是通过一定的机制查询到对象的内部结构 ,Python中提供了很多的方法来查询对象的内部结构,比如: hasattr:查询对象是否有一个特性的属性 ;getattr:获取对象的属性 ;setattr:设置对象的属性 ;delattr:从一个对象中删除属性,这些都是比较常规的方法,我们今天主要来讲一下__dict__和dir()这两个方法,我们先来看一段代码:
1234567891011121314151617181920# 自省是通过一定的机制查询到对象的内部结构class Person: name = "user"class Student(Person): def __init__(self, school_name): self.school_name = school_nameif __name__ == '__main__': user = Student("家里蹲大学") # 通过__dict__来查询属性 print(user.__dict__) print(u ...
Python高级编程(13):数据封装和私有属性
在java或者c++里面,我们都有private,protected等来修饰类,从而达到数据封装和私有属性的目的,但是在Python里面,这些都是没有的,那么它是如何达到相同目的的呢?我们继续看段代码:
123456789101112131415161718from .class_method import Dateclass User: def __init__(self, birthday): self.birthday = birthday def get_age(self): return 2018-self.birthday.yearuser = User(Date(1990, 9, 12))print(user.get_age()) # 通过调用这个get_age方法来获取对象的年龄print(user.birthday) # 通过调用这个birthday属性来获取对象的出生信息# 输出结果:281990/9/12
现在我们不希望直接获取到自己的出生信息,需要对其进行隐藏,我们可以使用__birthday(前面有2个下划线)就能实现 ...
Python高级编程(12):类方法、静态方法和实例(对象)方法
定义在类中的代码块叫方法,Python的方法分为『实例方法』、『类方法』、『静态方法』,按照从前到后的顺序它们和实例对象的依赖程度依次降低。
我们先来看一段代码:
12345678910111213141516171819202122class Date: # 构造函数 def __init__(self, year, month, day): self.year = year self.month = month self.day = day def tomorrow(self): self.day += 1 def __str__(self): return "{year}/{month}/{day}".format(year=self.year, month=self.month, day=self.day)if __name__ == '__main__': new_day = ...
Python高级编程(11):类和实例属性的查找顺序—mro查找
我们先来看一段代码:
12345678910111213class A: name = "envse" def __init__(self): self.name = "job"a = A()print(a.name)# 输出结果:job
上面的运行结果是没有任何疑问的,那么我们为啥要专门说明一下这个类和实例的查找顺序呢?那是因为在多继承的条件之下,我们的继承关系就比较复杂了,一眼直接看出来就比较难了。
MRO算法MRO就是method resolution order,主要用于在多继承时判断所调用属性的路径(来自于哪个类)
经典类在Python2.2之前,我们Python里面的类称为经典类,经典类是一种没有继承的类,实例类型都是type类型,如果经典类被作为父类,子类调用父类的构造函数时会出错。这时MRO的方法为DFS(深度优先搜索(子节点顺序:从左到右))
在上面的图里面就是:A–>B–>D–>C–>E。也就是说会先往一条路深了查找,如果找不到就走另一条路。按照这种情况其实是非常合理的,B里 ...
Python高级编程(10):类变量和实例(对象)变量
关于类变量和实例变量,我相信很多小白刚开始学习Python的时候,一直没有搞懂里面初始化代码的意思,也没有哪本书介绍过这里面各个参数的意思,这里看完你就会有一个清醒的认识了。
我们先来看一段代码:
12345678910111213class A: aa =1 # 类变量 def __init__(self, x, y): # 这里的self是指这个类的一个实例化对象,不是类本身 self.x = x # 类实例化后的对象的x等于我们传进来的x (self.x属于我们实例化后的对象,不再属于类本身) self.y = y # 类实例化后的对象的y等于我们传进来的y (self.y属于我们实例化后的对象,不再属于类本身)a = A(2, 4)print(a.x, a.y, a.aa)# 输出结果:2 4 1
这里的a.x 其实就是self.x,a.y其实就是self.y,而这里的a.aa则是类的aa,为什么会这样呢,那是因为这关系到python变量的查找顺序,后面会说。它会首先查找这个实例化对象是否存在aa这个属性,如果不存在就往 ...
Python高级编程(9):isinstance和type的区别
老规矩,还是先看一段代码:
12345678910111213141516class A: passclass B(A): passb = B()print(isinstance(b, B))print(isinstance(b, A)) # 运行结果:TrueTrue
很容易理解因为isinstance判断的是继承关系,我们再来看一下type,不过我需要说明一下这个is 和==的区别:is用来判断这两个对象是不是同一个对象,就是判断id是否相同;而== 是用来判断这两个对象的value是不是相等。我们看一段代码,加深一下印象:
1234567891011121314151617class A: passclass B(A): passb = B()print(id(b), id(B), id(A))print(b is B) # 判断这两个对象是不是同一个对象,就是判断id是否相同print(b is A)# 输出结果:10722864 16500152 16499680FalseFalse
因此:is同一性运算符:比较判断两个对象是否相同,id做为判断 ...
Python高级编程(8):抽象基类(Abstract Base Classes模块)
在java里面,继承都是单继承的,只有接口才支持多继承,而且接口是不支持实例化的,同样在Python里面的抽象基类也是不支持实例化的,这一点要非常明确。
其次,在动态语言(Python,JavaScript等)里面,是没有变量的类型的,它只是一个符号,可以指向任何类型的变量,所以它就不支持多态了,从语言上来说就是多态语言了。动态语言在声明变量的时候,是不用声明变量的类型的,但是也就少了编译时检查错误的环节,这样我们写的代码出了错如果不运行,我们是很难知道的。这也就是动态语言与静态语言相比的一个劣势,无法做错误检查(没有编译,无法检查)。
在Python设计的理念里,鸭子类型是很重要的,我们要把它放在第一位。在java里面,某个类具有某个功能是看它继承了某个函数,但是在Python里面则是具有了某些魔法函数,就具有了某个功能。(鸭子类型和魔法函数构成了我们Python里面的协议)
回过来,我们谈抽象基类,抽象基类的意思是在这个基类里面,我们设定一些方法,然后所有继承这个基类的类都必须覆盖这个基类的方法;抽象基类是无法进行实例化的。可能还是不是很明白,我们通过两种情况来加深对它的理解。
第 ...