先甩个题:
class B(object):
def __init__(self,name.age):
self.name=name
self.age = age
self.foo()
def foo() :
print("B foo")
class A(B):
name = 'xxxxx'
def foo():
print("A foo")
X = A('GWJ','23')
输出X会得到什么。
之前学习的django都基于fbv的开发模式,既视图函数基于方法的开发。
然而这并不能体现python面向对象的优点,所以引入了cbv的开发模式,既视图函数基于类的开发。在fbv开发中,无法基于路由判断请求方法是get还是post,在cbv中可以声明,既:
可以定义两个方法分别对应两种请求。类LoginView继承父类View,drf的开发是完全面向对象的,所以在开始学习前不得不重新熟悉一下python中类的使用。首先是实例化对象,例:
定义一个动物类,写入初始化方法。在外部拿一个A去接收,传入规定的两个参数name和age,这就是一个实例化的过程。我们去深究他的原理,其实类是会单独开辟一个存储空间的,叫做类空间,其中会包含类的属性,类的方法等等。我们实例化的过程实际就是在开辟一个实例空间,如图,类空间其实是实例空间的创建环境,当实例空间找不到一个变量的时候(既上文中的name age)就会去类空间里面找,如果类空间里面也没有,此时就会去类空间的父类对象里面去找,如果父类里面也没有的话程序这个时候就该报错了。
很多人以为类在实例化的时候是初始化方法先被执行既__init__,其实在初始化方法之前还有一个__new__方法,而这个方法的作用实际上就是帮助我们开辟实例空间的,name,age等变量都存储在这里。new魔术方法是开辟了一个内存空间之后,将这个内存空间作为返回值附给了init方法的self。此时self其实就相当于这块开辟出来的实例空间了,后面的操作无非就是对里面的属性进行赋值。
我们拿出来接收的A,A = Animal("daishu",'22')此时A就指向这块实例化的空间的地址,A.name或者A.age的时候就会去这块实例化空间找,如果在实例化的空间找不到,就会去他的上一级,既类空间去找。
所以类属性是适用于类中所有方法的,因为类中的方法在自己的实例化空间找不到变量的时候都会去公共的类空间寻找。举个有趣的例子:在类空间里面定义了一个number=1,此时
A = Animal("daishu",'22')
B = Animal("GWJ",'24')
如果我定义B.number=2,这个时候A.number也不会有任何变化还是等于1,因为这是写在类空间的公用属性。那如果我非要改这个类空间里面的属性怎么办呢,那就将眼光放到类对象上,直接Animal.number=2就可以对类属性进行更改了。
还有一个点,既我在类中加上这么一个函数,然后实例化这个类,我能不能调用name这个函数
A.name()答案是不行的,因为name是class这个类的方法,如果写下A.name(),python解释器会先执行A.name,既name这个变量,然后返回一个字符串后面再接一个括号就报错了,因为py中只有函数和类才是可callable的。如果想使用name方法只能Animal.name('xxxx')
现在再来看上面那道题就清晰多了,首先实例化A类,没有init方法,就去他的父类B类中寻找,将name和age传入B类的init方法后,还会执行一个foo方法,那么问题来了,是执行B类中的foo方法还是执行A类中的foo方法呢。根据上面的知识点,x会现在自己的实例化对象中找,如果自己的实例化对象中没有才会去父类中找,所以这个时候会执行A类中的foo方法,既输出A foo。