类方法与静态方法
类方法
首先需要明确的类方法是用装饰器进行装饰的,那么装饰器的原理就在于在进行被装饰函数执行之前先进行装饰函数的运行.这就非常有意思的将被装饰函数包装起来
可以更加形象的理解装饰器就是在被装饰函数执行前先进行审查,只有通过审查的参数才能被传到被装饰函数中,甚至是可以选择对所有传入的参数都选择忽略,一个都不给被装饰函数
class New(object):
def __init__(self, num1, num2):
self.num1 = num1
self.num2 = num2
@classmethod
def class_fun(cls):
print(f'+++++++++{cls}')
@staticmethod
def static_fun(args):
print(f"========={args}")
New.class_fun()
New.static_fun(10000)
装饰器@classmethod实质就是装饰器,注意到cls这个函数接收的参数cls,当然可以随便写,形参不管取什么名字都可以,但是这里不能没有,类方法会自动的将类传入进去,这里必须用一个参数进行接收
谁完成的这个事情
@classmethod这个装饰器完成的,实际上外面用类名进行调用的时候是没有办法对类进行传参数的,而class_fun方法确又定义了一个参数cls,没有报错则表明这个参数已经传进去了,外面没有给那么只能是装饰器里面自动给的,所以这个装饰器在这里的作用就是不管从外面怎么传参数,装饰器统统接受,但是装饰内部给class_fun的参数只有一个,就是类本身
注意到初始化函数,实际要求的是需要给类传递两个参数作为对象属性,显然这里在进行类方法调用的时候没有给,这就说明实际上调用类方法的时候根本就没有实例化
以上说明所谓的类方法,其实就是一个方法被装饰器装饰后筛掉所有的参数只给被装饰函数传递一个类的方法,这个cls你可以写成a b c d 任意符合命名规范的变量名,只是通常我们习惯写cls
静态方法
静态方法更像是一个定义在类外面的方法,因为这个方法可以不接受任何参数,甚至连类都不接受,注意到其实这个写在类里面的方法实际上也是通过装饰器进行修饰的,那么这个装饰器就像是一个保安大哥一样,拒绝所有的类和对象传入被装饰函数.其核心在于过滤掉一切外部对象和类的传入,当然你被装饰函数需要的参数还是照常传,只是不再像对象方法和类方法一样,默认的给对象本身和类本身
静态方法通过类名进行调用,但是又不接受这个类,感觉还不如定义在外面,实际上并不是这样的,虽然方法的执行与类并没有任何关系,但是其被封装到类里面,这个方法可以跟随对象走,也可以继承,更像是一种打包给这个类的东西,就像你买东西一样,商家还送你一些小玩意
class New(object):
def __init__(self, num1, num2):
self.num1 = num1
self.num2 = num2
@classmethod
def class_fun(cls):
print(f'+++++++++{cls}')
@staticmethod
def static_fun(args):
print(f"========={args}")
class Son(New):
pass
New.class_fun()
New.static_fun(10000)
Son.static_fun('继承的方法')
类实例化的过程
魔术方法里面有两个需要区分
__init__
__new__
init用来初始化对象
new用来创建对象,那么初始化过程一定是发生在创建过程之后的
当进行对象实例化的时候,实际上会存在两个空间,类空间和对象空间,如果是对象方法和对象属性则存放在对象空间中,如果是类方法和类属性则存放在类空间中
class Other(object):
other_attr = '其他类'
class New(object):
def __init__(self):
if self.class_attr == '类属性':
print(self.class_attr)
print('初始化前已经存在类空间')
self.class_attr = '对象属性'
print(self.class_attr)
print('=====================')
print(self.new_attr)
print('**********************')
print(self.new_attr.other_attr)
self.new_attr.other_attr = '修改属性'
print('--------------------------')
print(self.new_attr.other_attr)
print('故意写错')
self.new_attr.other_attr_ = '不会报错,这里直接调用'
print(self.new_attr.other_attr_)
class_attr = '类属性'
new_attr = Other()
test = New()
以上的结果可以说明类实际在实例化的时候先加载的是类里面类方法和类属性,之后再实例化对象,实例化对象成功之后再进行初始化,在初始化过程中调用了类属性,这个new_attr属性实际上又是一个实例化对象,所以这个属性实际上是一个对象,那么在使用self.new_attr.other_attr的时候本身就已经从这个对象上去找对象属性了,而Other这个类中没有对象属性,所以搜寻空间继续上找,在类空间找到了类属性,因此这里的链式查找就返回了’其他类’
这种类属性是另外一个类实例化对象的这种方式在很多框架的源码中用的比较多
核心思想就是链式查找
故意写错的的地方如果不是采用的赋值操作的话就会报错,其实道理很简单,对象.类属性 = 值 这种写法就好像是在类外面进行对象的对象属性赋值