1.类的定义 class Heap:# def __new__(cls): # 创建实例,传入cls类本身# # 可以改变实例创建的行为,这就是元编程的体现# pa
1.类的定义
class Heap:# def __new__(cls): # 创建实例,传入cls类本身# # 可以改变实例创建的行为,这就是元编程的体现# pass # 通常不写,除非要改变默认的创建实例的行为# 所有类的__class__都是type或其子类的实例 class_var = 1 # 类变量,被实例共享引用,可被类.操作修改,赋值修改后产生个性化 class_list = [] # 类可变变量,赋值改变,修改不变 # 对象创建完成后,立刻执行,self代表实例本身 def __init__(self, *args, **kwargs): # 通常叫做构造函数,在python中更多的叫做初始化函数 self.kwargs = kwargs # 没有显示定义__init__时,会使用默认的__init_ self.x = x # 普通实例变量 self.__y = y # 仅双下划线开始的变量是私有实例变量,理论上,仅可被内部方法访问;实际上._类名__私有变量__ self._z = z # 单下划线开始的变量是共有的 self.__m__ = 1 # 双下划线开始结尾的变量是公有的(特殊) def add(self, x): # 实例方法 pass # “第一个参数”必须是self @classmethod #使用装饰器,定义类方法,用于让实例能调用 def method_of_class(cls): # “第一个参数”是cls,类本身 print('method of class') @staticmethod # 用于让实例能调用 def static_method(): # 静态方法,默认不能被实例调用 print('static method') # 不传入“第一个参数”
2.类的封装
class G: __private_var = 'private' status1 = '...' @property # 使用装饰器,把x方法装饰为属性,通过.操作直接访问 def status1(self): return self.__private_var @status1.setter # 被x.setter装饰的方法,使方法属性可被直接修改 def status11(self, value): if value in ('closed', 'openning'): self.__private_var = value else: raise ValueError(value) @status1.deleter def status1(self): raise NotImplementedError('you can nott')
类变量、方法属性、实例变量,会根据代码的执行顺序进行覆盖:
类变量、方法属性是定义类的时候定义的,所以会根据代码写的顺序进行覆盖
实例变量在类定义后实例化的时候定义
3.类的继承
# 所有类都继承于object类class H(G): # H类继承G类,会创建H类MRO表 def print(self): print('i am H') super().print() # 调用H父类的方法 super(G, self).print() # 调用G父类的方法 #print(super().private) # 无法访问父类的实例变量 #print(super().pub) # 可访问类变量H.mro()[__main__.H, __main__.G, __main__.Base, object]可通过super(type, self),返回type的父类(准确来说是mro表的下一个类)的指代super对象,进行调用type类的方法
4.运算符重载
class Complex: def __init__(self, real, imag=0): # 方法前后双下划线,称为专有方法或魔术方法 self.real = real self.imag = imag # 重载int类方法 def __add__(self, other): # 重载+法,只能__add__跟默认的+方法重载 return Complex(self.real + other.real, self.imag + other.imag) def __sub__(self, other): # 重载-法,只能__sub__跟默认的-方法重载 return Complex(self.real - other.real, self.imag - other.imag) def __mul__(self, other): # 重载*法,只能__mul__ return Complex(self.real * other.real - self.imag * other.imag, self.real * other.imag + self.imag * other.imag)
5.内建方法
class A: def __init__(self): self.length = 1 def __len__(self): return self.length def __bool__(self): return Falsea = A()len(a)bool(a)
6.可调用对象
class Add: def __call__(self, a, b):#有__call__方法的对象,是可调用对象,可以直接调用 return a + b # __init__ 有__call__方法a = Add() # 所有函数都是可调用对象a(1, 2) # 当调用一个可调用对象时,实际上调用的是__call__方法3callable(a) # 内置函数callable用于判断一个对象是否是可调用对象True
7.对象可视化
class Complex: def __init__(self, real, imag=0): self.real = real self.imag = imag def __str__(self): if self.imag > 0: return ' {} + {}i'.format(self.real, self.imag) elif self.imag < 0: return ' {} - {}i'.format(self.real, self.imag * -1) return ' {}'.format(self.real) def __repr__(self): return '<{}.{}({}, {}) at {}>'.format(self.__module__, self.__class__.__name__, self.real, self.imag, hex(id(self)))c = Complex(1, 2)str(c)' 1 + 2i'c<__main__.Complex at 0x7f88f5eb7a58><__main__.Complex(2, 3) at 0x7f88f5ed25f8> # 修改了__repr__方法后
8.context
class Context: def __init__(self): print('init') # 同时具有__enter__和__exit__方法的类 def __enter__(self): print('enter') def __exit__(self, *args, **kwargs): print('exit')with Context()as a: # with后面跟一个实例,as把__enter__方法的返回值赋给a print('block') # 按照__init__,__enter__,block,__exit__顺序执行成对出现操作,并且必须确保两个都执行 资源打开/关闭 枷锁/解锁进入代码块之前要执行一些操作(__enter__) 初始化 权限判断离开代码块时要执行一些操作(__exit__)
# 标准库里的context装饰器import [email protected] test(): print('enter') # __enter__ try: yield 123 # block finally: print('exit') # __exit__
9.反射
#通俗:可以使用代码,获取对象本身的一些属性,例如对象的字段、方法等dir(a) # 获取实例的属性和方法a.__class__ # 获取当前模块类__main__.Aa.__class__.__name__ # 获取当前类名'A'a.__dict__ # 获取属性{'y': 1}a.__doc__ # 文档字符串'''doc'''a.__module__ # 当前所在模块'__main__'
class A: x = 1 def __init__(self): self.y = 1 # getattr 内建函数,调用 __getattribute__,通过字符串的方式访问类的属性 # 如果类定义了__getattr__ 方法,当输出不存在时,将会访问__getattr__方法 def __getattr__(self, name, default=None): return 'missing proptery' # 当定义__getattribute__方法的时候,访问实例的属性的时候,总是调用__getattrbute__ def __getattribute__(self, *args, **kwargs): return '1111' a = A()setattr(a, 'x', 3) # setattr设置object属性(实际调用__setattr__),存在即修改,不存在即创建delattr(a, 'num') # 删除属性
10.描述器
class Int: def __init__(self, name): print('init') self.name = name # __get__和__set__方法成对出现 def __get__(self, instance, cls): # 访问属性时 print('access') if instance is None: return self return instance.__dict__[self.name] def __set__(self, instance, value): # 修改属性时 print('set') instance.__dict__[self.name] = value def __delete__(self, instance): # 删除属性时 raise TypeError('not allowed')# 用于控制对属性的访问、赋值和删除class A: x = Int('x') # 实例化描述器,传入任意值填补Int.__init__的参数 def __init__(self, x): self.x = x
11.描述器的应用
# property装饰器,把类方法改为类属性class Property: def __init__(self, fget=None, fset=None, fdel=None): self.fget = fget self.fset = fset self.fdel = fdel print('initP') def __get__(self, instance, cls): print('get') if instance is None: # instance是调用Property实例方法的实例a return self if not callable(self.fget): raise AttributeError() return self.fget(instance) # self.fget即A.x def __set__(self, instance, value): print('set') if not callable(self.fset): raise AttributeError() self.fset(instance, value) def __delete__(self, instance): print('delete') if not callable(self.fdel): raise AttributeError() self.fdel(instance) def setter(self, fset): print('setter') #self.fset = fset return Property(self.fget, fset, self.fdel) def delete(self, fdel): print('delete') #self.fdel = fdel return Property(self.fget, self.fset, fdel) def print(self): print(self.fget)class A: def __init__(self, x): print('init2') self.__x = x @Property # 传入x方法作为fget,实例化了类装饰器 def x(self): print('x') return self.__x # x = Property(A.x) @x.setter def x(self, value): print('set_x') self.__x = value # x = x.setter(A.x) = Property(x.fget, A.x, x.del)
# classmethod装饰器from functools import wraps, partialclass Classmethod: def __init__(self, method): wraps(method)(self) def __get__(self, instance, cls): return partial(self.__wrapped__, cls)class C: @Classmethod def method(cls): print(cls) @Classmethod def method2(cls, x): print(cls) print(x)
# 对类变量做类型检查class Typed: def __init__(self, name, required_type): self.name = name self.required_type = required_type def __get__(self, instance, cls): if instance is None: return self return instance.__dict__[self.name] def __set__(self, instance, value): if not isinstance(value, self.required_type): raise TypeError(' {} required type {}'.format(self.name, self.required_type)) instance.__dict__[self.name] = value class A: x = Typed('x', int) y = Typed('y', str) def __init__(self, x, y): self.x = x self.y = y