1. isinstance和type:
is和==符号,is指的是内存地址,是不是一个对象,ID知否相同
集成链
class A: pass class B(A): pass b = B() print(isinstance(b,B)) print(isinstance(b,A)) print(type(b) is B) print(id(type(b)),id(B)) # 2943616512536 2943616512536
2. 类变量和对象变量:
类中的self == 实例,其实就等于a = A()的a,等于传递进去,这就是为什么类中有self的原因。
class A: aa = 1 def __init__(self,x,y): self.x = x self.y = y a = A(2,3) A.aa = 11 a.aa = 100 print(a.x,a.y,a.aa) # 2 3 1 print(A.aa) # print(A.x,A.y) # 抛异常 # 2 3 100 # 11
记住:查找的顺序是由下而上进行查找
记住:类变量只能通过类来更改,如果通过实例去更改,只会开辟一块儿新的变量,类的变量其实不能更改,但是看起来是一个变量。类的变量是所有成员共享的。
3. 类属性和实例属性的查找顺序:
定义在内部的实例或者方法。
查找分深度查找和广度查找,其实前面有类名.__init__这样继承父类的方式就是深度查找,我们Py3用的是MRO算法,用的是C3,super()就是一种C3的查找方法。
class A: name = "A" def __init__(self): self.name = "obj" a = A() print(a.name) # 会打印obj回不到name变量
class D: pass class C(D): pass class B(D): pass class A(B,C): pass print(A.__mro__) # (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
记住:可以用__MRO__查看继承链的关系。
记住:py2,必须要写object才有object,py3.不用写也会继承object,是一种新式类
4. 静态方法、类方法、对象方法(实例方法):
class Date: # 构造函数 def __init__(self,year,month,day): self.year = year self.month = month self.day = day def tomoroow(self): self.day += 1 @staticmethod def parse_from_string(date_str): year, month, day = tuple(date_str.split("-")) return Date(int(year),int(month),int(day)) @staticmethod def valid_str(date_str): year, month, day = tuple(date_str.split("-")) if int(year)>0 and (int(month)>0 and int(month)<12) and (int(day)>0 and int(day)<=31): return True else: return False @classmethod def from_string(cls,date_str): year, month, day = tuple(date_str.split("-")) return cls(int(year),int(month),int(day)) def __str__(self): return "{year}/{month}/{day}".format(year=self.year,month=self.month,day=self.day) if __name__ == '__main__': new_day = Date(2019,6,7) new_day.tomoroow() print(new_day) #2019-6-7 # date_str = "2019-6-7" # year,month,day = date_str.split("-") # print(year,month,day) #用staticmethod完成初始化 date_str = "2019-6-7" new_day = Date.parse_from_string(date_str) print(new_day) # 用staticmethod完成初始化 date_str = "2019-6-7" new_day = Date.from_string(date_str) print(new_day) print(Date.valid_str(date_str))
记住:类中有属性和方法,前面我们说了属性分:类属性,对象属性(实例属性),还有一种静态属性。在方法这个层面也分:类方法、静态方法和对象方法(实例方法)。
记住:对象方法平时用的很多,记住在类中的self就是用于传回实例的那个标签的。
记住:静态方法和类方法相同点就是可以直接通过类来进行访问,不用再实例化。 不同点是:如果返回值是类名的话,静态方法每次都要更改return 类名,而类方法不用。
记住:静态方法@staticmethod,中的是self。类方法@staticclass,中的是cls。这两种其实就是和什么关联。
5. 数据封装和私有属性:
class User: def __init__(self,birthday): self.__birthday = birthday def get_age(self): return 2019 - self.__birthday class Student(User): def __init__(self,birthday): self.__birthday = birthday if __name__ == '__main__': user = User(1981) print(user.get_age()) # print(user.__birthday) # 不能访问 print(dir(user)) # ['_User__birthday', print(user._User__birthday) print(user._Student__birthday)
记住:私有属性在Py中突破的比较简单一些,不用通过反射机制。
记住:私有属性其实就是在类中创建了一个_类名.__私有属性的变量而已。我们可以通过dir看到这个变量。而且可以直接拿到那个私有属性。
6. Py的自省:
通过一定的机制查询到对象的内部结构。
class Person: """ 人 """ name = "user" class Student(Person): def __init__(self,school_name): self.school_name = school_name if __name__ == '__main__': user = Student("Oxford") # 通过__dict__查询属性。 print(user.__dict__) # {'school_name': 'Oxford'} print(user.name) # user print(Person.__dict__) user.__dict__["schoole_addr"] = "北京" print(user.__dict__) # {'school_name': 'Oxford', 'schoole_addr': '北京'} print(dir(user))
记住:查看类中的属性的两个魔法函数是__dict__和dir,其中dict是一种高效的数据存储方式。用dir可以查看全部的。
记住:__doc__是查看类中的文档注释内容的。
7. super函数:
实际上就是调用我们的父类。
class A: def __init__(self): print("A") class B(A): def __init__(self): print("B") # super(B,self).__init__() #这是Py2的用法 super().__init__() # 这是Py3的用法。 # 既然重写了B的构造函数,为什么还要去调用super # super到底执行顺序是什么样的? if __name__ == '__main__': b = B()
记住:查找顺序就是MRO
记住:Py2的调用方法和Py3的调用方法不同,但是Py3也可以用Py2的格式。
8. 类的调用关系:
mixin模式(属于Python几大设计模式中的一个,后面说)
minin类功能单一
不和基类管理啊,可以和任意基类组合,基类可以不和mixin关联就能初始化成功
在mixin中不要使用super之中用法。
9. 上下文管理器with和contextlib
def exe_try(): try: # f_read = open("bobby.txt") print("code started") # f_read.close() raise KeyError return 1 except KeyError as e: print("key error") return 2 else: print("other error") return 3 finally: print("finally") return 4 if __name__ == '__main__': result = exe_try() print(result) # 如果有finally语句会return 4,如果没有finally的话,执行try和Except语句,返回2
上下文管理器协议(是协议就要和魔法函数挂钩)
因此涉及到了__enter__和__exit__
# 上下文管理器协议 class Sample: def __enter__(self): print("enter") return self def __exit__(self, exc_type, exc_val, exc_tb): print("exit") def __str__(self): return "this is finally?" def do_something(self): print("do something") with Sample() as sample: sample.do_something() print(sample)
记住:上下文管理器,其实就是规定类的进和出的关系。比如我们用with open as f:这样的管理方式,就是在open当中规定了__enter__和__exit__两个魔法函数。进出关系,所以不用关闭了。
记住:__exit__指的是最后的退出,因此里面要打印字符串打印的__str__是在这个之前的。
import contextlib
import contextlib @contextlib.contextmanager def file_open(filename): print("file open") # __enter__ yield {} print("file close") # __exit__ with file_open("bobby.txt") as f_opened: print("file processing") # file open # file processing # file close
记住:上下文管理器函是一个用装饰器的方式生成一个上下文管理器,巧妙的运行了生成器的特性。yield的方式。