前言
介绍django的重要知识点
1、__getattr__
方法、__getattribute__
方法及其应用
1.1 __getattr__
方法
概述:对象中有成员时,不会触发;对象中没有成员时,会触发;
class Foo(object):
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
return 123
def __getattr__(self, item):
print("---->", item)
return 999
obj = Foo("任刚", 19)
# 不触发 __getattr__
print(obj.name) # 任刚
print(obj.age) # 19
print(obj.show()) # 123
# 触发 __getattr__(不存在成员)
print(obj.xxxxx) # ----> xxxx 999
v2 = getattr(obj,"xxxxx")
print(v2) # ----> xxxx 999
1.2 __getattribute__
方法
- 只要执行
对象.xxxx
都会执行__getattribute__
方法; - object中的
__getattribute__
内部处理机制:- 对象中有值,返回
- 对象中无值,报错
1.3 两种方法结合使用
class HttpRequest(object):
def __init__(self):
pass
def v1(self):
print("我是HttpRequest中的v1")
def v2(self):
print("我是HttpRequest中的v2")
class Request(object):
def __init__(self, req, xx):
self._request = req
self.xx = xx
def __getattr__(self, attr):
try:
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
# ------------------------------------------------------
req = HttpRequest()
req.v1() # 输出结果为:我是HttpRequest中的v1
req.v2() # 输出结果为:我是HttpRequest中的v2
# ------------------------------------------------------
request = Request(req, 111)
print(request.xx) # 输出结果为‘111’,request对象中有xx成员,不执行`__getattr__(self, attr)`方法
request.v1()
# 输出结果为:我是HttpRequest中的v1;因为request对象中没有v1,执行`__getattr__(self, attr)`方法(即req对象),`getattr(self._request, attr)`中有v1,返回v1,如果也没有的成员,则会报错。
request.v2() # 输出结果为:我是HttpRequest中的v2
request.v3() # 报错,执行父类object中的`__getattribute__(attr)`方法
通过关键的第17号至21行代码,将__getattr__
方法与__getattribute__
方法结合使用,可以将reqeust._request.v1()简写为reqeust.v1()。
1.4 drf中request对django的request进行封装,用的就是上述方式
1.4.1 总体流程
1.4.2 主要源码
class HttpRequest:
"""A basic HTTP request."""
# The encoding used in GET/POST dicts. None means use default setting.
_encoding = None
_upload_handlers = []
def __init__(self):
# WARNING: The `WSGIRequest` subclass doesn't call `super`.
# Any variable assignment made here should also happen in
# `WSGIRequest.__init__()`.
self.GET = QueryDict(mutable=True)
self.POST = QueryDict(mutable=True)
self.COOKIES = {}
self.META = {}
self.FILES = MultiValueDict()
self.path = ''
self.path_info = ''
self.method = None
self.resolver_match = None
self.content_type = None
self.content_params = None
class Request:
"""
Wrapper allowing to enhance a standard `HttpRequest` instance.
Kwargs:
- request(HttpRequest). The original request instance.
- parsers(list/tuple). The parsers to use for parsing the
request content.
- authenticators(list/tuple). The authenticators used to try
authenticating the request's user.
"""
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
# isinstance(object, classinfo),判断一个对象的变量类型,返回值为True或False
# assert 断言,在表达式条件为 false 的时候触发异常
# request 为django中的基本request【drf封装前】
assert isinstance(request, HttpRequest), (
'The `request` argument must be an instance of '
'`django.http.HttpRequest`, not `{}.{}`.'
.format(request.__class__.__module__, request.__class__.__name__)
)
# 核心代码
self._request = request
self.parsers = parsers or ()
self.authenticators = authenticators or ()
self.negotiator = negotiator or self._default_negotiator()
self.parser_context = parser_context
self._data = Empty
# ……
def __getattr__(self, attr):
"""
If an attribute does not exist on this instance, then we also attempt
to proxy it to the underlying HttpRequest object.
"""
try:
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
2、__init__
方法、super()
方法
2.1 __init__
方法
2.1.1 介绍
__init__
方法是 Python 中面向对象编程中类的特殊方法,也称为构造方法,当创建一个类的实例时,__init__
方法会自动调用。- self参数是必须的,它代表创建的对象本身,在方法内部可以通过self来引用对象的属性和方法。除了self以外的其他参数是可选的,根据实际需求定义。
2.1.2 示例代码
class HttpRequest(object):
#
def __init__(self, name, age):
self.name = name
self.age = age
request = HttpRequest('小杨', 19)
request.city = "北京"
print(request.name) # 输出结果为:小杨
print(request.age) # 输出结果为:
print(request.city) # 输出结果为:北京
2.1.3 注意事项
__init__
方法在对象创建时自动调用,无需手动调用。__init__
方法可以接收任意数量的参数,但必须遵循特定的参数签名。- 在
__init__
方法中,必须给对象的每一个属性赋值,否则该对象将不完整,不能正常工作。 - 可以在
__init__
方法中调用其他方法,但请注意不要在初始化的过程中产生太多的计算,因为这可能会影响程序的性能。 - 一个类可以没有
__init__
方法,在这种情况下,程序将以默认方式创建该类的对象。
2.2 super()方法
2.2.1 介绍
- 根据类的【继承关系】,逐步往上找,并不是单纯找父类中的方法;
2.2.2 示例代码一
class Base:
def f1(self):
print("Base")
class Foo(Base):
pass
class Bar(Foo):
def f1(self):
print("Bar")
super().f1()
obj = Bar()
obj.f1() # 执行结果为:[Bar,Base]
2.2.3 示例代码二
class Base:
def f1(self):
print("Base")
class Foo:
def f1(self):
print("Foo")
class Bar(Foo,Base):
def f1(self):
print("Bar")
super().f1()
obj = Bar()
obj.f1() # 执行结果为[Bar,Foo]
2.2.4 示例代码三
class Base:
def f1(self):
print("Base")
class Foo:
def f1(self):
print("Foo")
super().f1()
class Bar(Foo,Base):
def f1(self):
print("Bar")
super().f1()
obj = Bar()
obj.f1() #执行结果为: [Bar,Foo,Base]
2.2.5 示例代码四
class Base:
def f1(self):
print("Base")
class Foo:
def f1(self):
print("Foo")
super().f1()
class Bar(Foo,Base):
def f1(self):
print("Bar")
super().f1()
obj = Foo()
obj.f1() # 代码报错,因为Foo父类为object,没有f1方法
2.3 __init__
和super
用法
2.3.1 示例代码
class Parent:
def __init__(self, value1, value2):
self.value1 = value1
self.value2 = value2
class Child(Parent):
def __init__(self, value1, value2, value3):
super().__init__(value1, value2)
self.value3 = value3
obj = Child('v1', 'v2', 'v3')
print(obj.value1) # 输出结果为v1
print(obj.value2) # 输出结果为v2
print(obj.value3) # 输出结果为v3
2.3.2 总结
- 在上述示例中,Child继承了Parent的所有属性,并且在其中添加了额外的value3 属性。调用 super().init(value1, value2) 可以访问父类的__init__方法,并将其初始化为value1 和value2。