Python 用_getattr___和相关

Python 用_getattr___和相关,python,Python,我试图封装一个对象而不改变它的默认行为,问题是当我访问该对象时,它已经被构造好了。因此,我的想法是使用继承并使用\uuuu getattr\uuuuuu、\uuuu setattr\uuuuuu、\uuuu getitem\uuuuuu和\uuuu setitem\uuuuuuuuuuuu并委托给封装对象,但我自己定义的字段除外 class Request(HttpRequest): def __init__(self, request, *args, **kwargs):

我试图封装一个对象而不改变它的默认行为,问题是当我访问该对象时,它已经被构造好了。因此,我的想法是使用继承并使用
\uuuu getattr\uuuuuu
\uuuu setattr\uuuuuu
\uuuu getitem\uuuuuu
\uuuu setitem\uuuuuuuuuuuu
并委托给封装对象,但我自己定义的字段除外

class Request(HttpRequest):

    def __init__(self, request, *args, **kwargs):
        self._original_request = request
        super(Request, self).__init__(*args, **kwargs)

    def __getattr__(self, name):
        return getattr(self._original_request, name)

    def __setattr__(self, name, value):
        if name == '_original_request':
            super(Request, self).__setattr__(name, value)
        else:
            self._original_request.__setattr__(name, value)

    def __getitem__(self, key):
        return self._original_request[key]

    def __setitem__(self, key, value):
        self._original_request[key] = value
如果我沿着原始对象传递,一切都很好。如果我不这样做,我就会

host = self.META['SERVER_NAME']
KeyError: u'SERVER_NAME'
我错过什么了吗?我的类不应该和它封装的类完全一样吗

Internal Server Error: /
Traceback (most recent call last):
  File "c:\Python27\lib\site-packages\django\core\handlers\base.py", line 115, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "c:\Python27\lib\site-packages\django\views\generic\base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\www\lookwanted\djutils\views.py", line 35, in dispatch
    return super(View, self).dispatch(Request(request), *args, **kwargs)
  File "C:\www\lookwanted\djutils\views.py", line 12, in __init__
    super(Request, self).__init__(*args, **kwargs)
  File "c:\Python27\lib\site-packages\django\http\request.py", line 43, in __init__
    self.GET, self.POST, self.COOKIES, self.META, self.FILES = {}, {}, {}, {}, {}
  File "C:\www\lookwanted\djutils\views.py", line 21, in __setattr__
    self._original_request.__setattr__(name, value)
AttributeError: can't set attribute
Traceback (most recent call last):
  File "c:\Python27\lib\wsgiref\handlers.py", line 85, in run
    self.result = application(self.environ, self.start_response)
  File "c:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", line 72, in __call__
    return self.application(environ, start_response)
  File "c:\Python27\lib\site-packages\django\core\handlers\wsgi.py", line 255, in __call__
    response = self.get_response(request)
  File "c:\Python27\lib\site-packages\django\core\handlers\base.py", line 178, in get_response
    response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
  File "c:\Python27\lib\site-packages\django\core\handlers\base.py", line 217, in handle_uncaught_exception
    return debug.technical_500_response(request, *exc_info)
  File "c:\Python27\lib\site-packages\django\views\debug.py", line 69, in technical_500_response
    html = reporter.get_traceback_html()
  File "c:\Python27\lib\site-packages\django\views\debug.py", line 298, in get_traceback_html
    return t.render(c)
  File "c:\Python27\lib\site-packages\django\template\base.py", line 140, in render
    return self._render(context)
  File "c:\Python27\lib\site-packages\django\template\base.py", line 134, in _render
    return self.nodelist.render(context)
  File "c:\Python27\lib\site-packages\django\template\base.py", line 830, in render
    bit = self.render_node(node, context)
  File "c:\Python27\lib\site-packages\django\template\debug.py", line 74, in render_node
    return node.render(context)
  File "c:\Python27\lib\site-packages\django\template\defaulttags.py", line 284, in render
    return nodelist.render(context)
  File "c:\Python27\lib\site-packages\django\template\base.py", line 830, in render
    bit = self.render_node(node, context)
  File "c:\Python27\lib\site-packages\django\template\debug.py", line 74, in render_node
    return node.render(context)
  File "c:\Python27\lib\site-packages\django\template\debug.py", line 84, in render
    output = self.filter_expression.resolve(context)
  File "c:\Python27\lib\site-packages\django\template\base.py", line 578, in resolve
    obj = self.var.resolve(context)
  File "c:\Python27\lib\site-packages\django\template\base.py", line 728, in resolve
    value = self._resolve_lookup(context)
  File "c:\Python27\lib\site-packages\django\template\base.py", line 779, in _resolve_lookup
    current = current()
  File "c:\Python27\lib\site-packages\django\http\request.py", line 112, in build_absolute_uri
    self.get_host(), self.path)
  File "c:\Python27\lib\site-packages\django\http\request.py", line 62, in get_host
    host = self.META['SERVER_NAME']
KeyError: u'SERVER_NAME'

堆栈跟踪显示了问题:代码试图在
self.\u原始\u请求
上设置属性,而不是
self.\uuuu dict\uuuu


请阅读Python文档。

问题在于行:

    super(Request, self).__init__(*args, **kwargs)
这将导致对您的
请求
实例调用
HttpRequest
类的
\uuuuuu init\uuuu
方法,这是没有意义的。因此,只要摆脱这一行

另外,我不明白你为什么要在第一时间子类化。既然python有duck类型,并且您完全包装了内部对象,为什么不使用:

class Request(object):
    def __init__(self, request, *args, **kwargs):
        self._original_request = request

    def __getattr__(self, name):
        return getattr(self._original_request, name)

    def __setattr__(self, name, value):
        if name == '_original_request':
            super(Request, self).__setattr__(name, value)
        else:
            self._original_request.__setattr__(name, value)

    def __getitem__(self, key):
        return self._original_request[key]

    def __setitem__(self, key, value):
        self._original_request[key] = value

你能发布完整的回溯吗?另外,为什么要继承
HttpRequest
?这样做时,我注意到还有一个我没有注意到的异常。。。我将super(Request,self)改为setattr(name,value),但现在我得到了无限递归。不过,我想这是另一个问题。当然不是你的问题,但我真的不明白这句话的意思是什么。你为什么不直接写一句话呢!由于
META
HttpRequest
的一个属性,通过对其进行子分类,您的“拦截器”将获得其自己的
META
属性,因此,
\uuu getattr\uuuu
不会被触发。。。因此没有访问原始对象的
META
属性。我明白了!接得好!关于遗产,它会造成伤害吗?我正在考虑让它保持原样,如果没有其他原因,它记录了这两个类是相关的。事实上,这是一个有趣的评论。因为这是python,所以不需要使用子类型来获得可替换性——这需要Java等语言的接口。所以这里有某种继承感。另一方面,请求对象“不是”传统Java继承意义上的HttpRequest对象,在这种继承中,构造子类型需要通过构造函数调用构造超类型。就我个人而言,我会避免这样做,但我不认为有一个最好的方法来做这件事。