python koans:类代理
我正在解决python koans。 直到34号我才遇到任何真正的问题。
这就是问题所在:
项目:创建代理类
在此作业中,创建一个代理类(已为您启动一个代理类) 以下)。您应该能够使用任何初始化代理对象 目的。任何在代理对象上调用的属性都应该被转发 到目标对象。当发送每个属性调用时,代理 应记录发送的属性的名称。
代理类已为您启动。您需要添加一个方法 缺少处理程序和任何其他支持方法。规格 Proxy 类的定义在 AboutProxyObjectProject 公案中给出。
注意:这比 Ruby Koans 的对应部分有点棘手,但是你 可以做到!
这是我到目前为止的解决方案:
class Proxy(object):
def __init__(self, target_object):
self._count = {}
#initialize '_obj' attribute last. Trust me on this!
self._obj = target_object
def __setattr__(self, name, value):pass
def __getattr__(self, attr):
if attr in self._count:
self._count[attr]+=1
else:
self._count[attr]=1
return getattr(self._obj, attr)
def messages(self):
return self._count.keys()
def was_called(self, attr):
if attr in self._count:
return True
else: False
def number_of_times_called(self, attr):
if attr in self._count:
return self._count[attr]
else: return False
它一直有效,直到这个测试:
def test_proxy_records_messages_sent_to_tv(self):
tv = Proxy(Television())
tv.power()
tv.channel = 10
self.assertEqual(['power', 'channel='], tv.messages())
其中 tv.messages()
是 ['power']
因为 tv.channel=10< /code> 由代理对象而不是电视对象获取。
我尝试操作 __setattr__ 方法,但总是以无限循环结束。
编辑1:
我正在尝试这个:
def __setattr__(self, name, value):
if hasattr(self, name):
object.__setattr__(self,name,value)
else:
object.__setattr__(self._obj, name, value)
但是后来我在最后一个条目的循环中遇到了这个错误:
RuntimeError: maximum recursion depth exceeded while calling a Python object
File "/home/kurojishi/programmi/python_koans/python 2/koans/about_proxy_object_project.py", line 60, in test_proxy_method_returns_wrapped_object
tv = Proxy(Television())
File "/home/kurojishi/programmi/python_koans/python 2/koans/about_proxy_object_project.py", line 25, in __init__
self._count = {}
File "/home/kurojishi/programmi/python_koans/python 2/koans/about_proxy_object_project.py", line 33, in __setattr__
object.__setattr__(self._obj, name, value)
File "/home/kurojishi/programmi/python_koans/python 2/koans/about_proxy_object_project.py", line 36, in __getattr__
if attr in self._count:
循环位于__getattr__
中。
I'm solving the python koans.
I haven't got any real problem until the 34th.
this is the problem:
Project: Create a Proxy Class
In this assignment, create a proxy class (one is started for you
below). You should be able to initialize the proxy object with any
object. Any attributes called on the proxy object should be forwarded
to the target object. As each attribute call is sent, the proxy
should record the name of the attribute sent.The proxy class is started for you. You will need to add a method
missing handler and any other supporting methods. The specification
of the Proxy class is given in the AboutProxyObjectProject koan.Note: This is a bit trickier that it's Ruby Koans counterpart, but you
can do it!
and this is my solution until now:
class Proxy(object):
def __init__(self, target_object):
self._count = {}
#initialize '_obj' attribute last. Trust me on this!
self._obj = target_object
def __setattr__(self, name, value):pass
def __getattr__(self, attr):
if attr in self._count:
self._count[attr]+=1
else:
self._count[attr]=1
return getattr(self._obj, attr)
def messages(self):
return self._count.keys()
def was_called(self, attr):
if attr in self._count:
return True
else: False
def number_of_times_called(self, attr):
if attr in self._count:
return self._count[attr]
else: return False
It works until this test:
def test_proxy_records_messages_sent_to_tv(self):
tv = Proxy(Television())
tv.power()
tv.channel = 10
self.assertEqual(['power', 'channel='], tv.messages())
where tv.messages()
is ['power']
because tv.channel=10
is taken by the proxy object and not the television object.
I've tried to manipulate the __setattr__
method, but I always end in a unlimited loop.
edit 1:
I'm trying this:
def __setattr__(self, name, value):
if hasattr(self, name):
object.__setattr__(self,name,value)
else:
object.__setattr__(self._obj, name, value)
But then I get this error in a loop on the last entry:
RuntimeError: maximum recursion depth exceeded while calling a Python object
File "/home/kurojishi/programmi/python_koans/python 2/koans/about_proxy_object_project.py", line 60, in test_proxy_method_returns_wrapped_object
tv = Proxy(Television())
File "/home/kurojishi/programmi/python_koans/python 2/koans/about_proxy_object_project.py", line 25, in __init__
self._count = {}
File "/home/kurojishi/programmi/python_koans/python 2/koans/about_proxy_object_project.py", line 33, in __setattr__
object.__setattr__(self._obj, name, value)
File "/home/kurojishi/programmi/python_koans/python 2/koans/about_proxy_object_project.py", line 36, in __getattr__
if attr in self._count:
The loop is in __getattr__
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您在
__setattr__
中使用hasattr
来决定是否应该写入本地对象或代理对象。除了一种情况外,这对所有情况都适用。在您的
__init__
中,您有以下行:这会使用
'_count'
调用__setattr__
,此时该值不存在(因此>hasattr
返回False
)被转发到代理对象。如果您想使用您的方法,您必须像这样编写
__init__
:You are using
hasattr
in__setattr__
to decide whether you should write to the local or proxied object. This works well for all but one case.In your
__init__
you have the following line:This calls
__setattr__
with'_count'
which does not exist at that point and therefore (hencehasattr
returnsFalse
) is forwarded to the proxied object.If you want to use your approach you have to write your
__init__
like this:据我了解,您的问题可能与设置属性值时的递归调用有关。 来自文档:
如果
__setattr__()
想要分配给实例属性,它不应该简单地执行“self.name = value
”——这会导致对其自身的递归调用。相反,它应该将值插入实例属性的字典中,例如“self.__dict__[name] = value
”。对于新式类,不应访问实例字典,而应调用基类的同名方法,例如“object.__setattr__(self, name, value)
”。As I understand maybe your problem is related with the recursive call when you set and attribute value. From docs:
If
__setattr__()
wants to assign to an instance attribute, it should not simply execute "self.name = value
" -- this would cause a recursive call to itself. Instead, it should insert the value in the dictionary of instance attributes, e.g., "self.__dict__[name] = value
". For new-style classes, rather than accessing the instance dictionary, it should call the base class method with the same name, for example, "object.__setattr__(self, name, value)
".setattr 在所有分配中都会被调用。它更像是 getattribute 而不是 getattr。这也会影响 __init__ 方法中的代码。
这意味着这段代码的第一个分支几乎总是会失败,只有从对象继承的属性才会通过测试:
相反,我们
可以假设分配是针对代理的,除非它具有 _obj 属性。因此 __init__ 中的注释。我们设置代理的属性,然后添加目标对象,并将所有未来的分配发送给它。
但是通过使用 hasattr,我们还需要更改 __getattr__ 来检查 _obj 以防止递归:
另一种方法是直接在 __setattr__ 方法中检查代理的 __dict__ 属性:
setattr is called on all assignments. It's more like getattribute than getattr. This also affects code in the __init__ method.
This means that the first branch of this code will almost always fail, only attributes inherited from object will pass the test:
Instead we
can assume that assignments are meant for the Proxy unless it has an _obj attribute. Hence the comment in __init__. We set up our proxy's attributes, then add the target object and all future assignments get sent to it.
But by using hasattr we would also need to alter __getattr__ to check for _obj to prevent recursion:
An alternative would be to inspect the proxy's __dict__ attribute directly in the __setattr__ method:
从测试来看,代理需要记录所有通过代理的属性调用。并且代理只有很少的内置方法,这些方法特别用于日志记录,所以我的答案是:
在此之后,很容易实现其他方法('messages','was_known',...)
抱歉,necro'ing老问题。
我发现 getattribute 可以更改:只需检查该属性是否在目标对象中即可。
from the test, it is a requirement for proxy to log all the attribute calls via proxy. And the proxy has only few built-in methods which are exceptionally used for logging, so my answer was:
After this it is quite easy to implement other methods ('messages', 'was_called', ... )
Sorry for necro'ing old question.
and I found out that getattribute can be changed : just check whether the attribute is in the target object.
我所做的是对代理中的属性进行所有调用,并通过 object.__getattribute__ 调用它们以避免递归。
这对方法不起作用,因此我将方法调用包装在 try.. except AttributeError 中,以便首先在代理中尝试它们。然后,如果它们引发错误,请在子对象中尝试它们。
如果有人有更优雅的解决方案,我很乐意看到它。
What I did was take all the calls to attributes in the proxy and call them via
object.__getattribute__
to avoid recursion.That did not work for methods so I wrapped the method calls in a try..except AttributeError to try them first in the proxy. and then if they raise an error try them in the child object.
If anyone has a more elegant solution would love to see it.
为什么不使用method_missing?
我的回答:
why not use method_missing?
my answer: