0

I'm aware that methods are just objects that can be accessed via getattr(obj, 'method_name'). Is the method does not exist, this will trigger obj.__getattr__(method_name). However, is it possible in the __getattr__ implementation to distinct whether the attribute is called directly by the user or not? It seems to me that descriptors might allow this, but I'm not entirely sure.

My motivation is a proxy class that forwards both attribute access and method calls to a wrapped object to which communication is slow. For attribute access, we necessarily have to block and wait for the result. But for method access, I'd like to inject a _blocking parameter that allows to receive a non-blocking promise object:

proxy = Proxy(Inner())
proxy.value  # Block and wait for inner.value
promise = proxy.method(arg1, args2, _blocking=False)  # Non-blocking
promise()  # Wait for the return value of inner.method(arg1, arg2)
danijar
  • 32,406
  • 45
  • 166
  • 297
  • 3
    You can't detect if the result is going to be called or not; calling is distinct from attribute access. At most you can test for callable objects. – Martijn Pieters Oct 16 '17 at 15:15
  • 2
    How would you handle the `method_to_be_used_later = proxy.method` case for example? I can turn around and later on and apply a call expression to the new reference with `method_to_be_used_later()` – Martijn Pieters Oct 16 '17 at 15:17
  • This would be handled as an attribute access and would be blocking. I was hoping that descriptors allow me to handle the `proxy.method(...)` case though. If that's not possible, I could have another proxy object to wraps result in that behaves different depending on whether the result is a method or not (`inspect.ismethod(...)`). The problem here is that if the result is a primitive type, the result proxy cannot fully behave like that. – danijar Oct 16 '17 at 15:21
  • 2
    Descriptors are invoked for attribute access; that functions are descriptors and produce methods is not really special here; `property` objects are also descriptors. At best you can *wrap* method objects, so you can intercept the call. – Martijn Pieters Oct 16 '17 at 15:30
  • Descriptors handle *binding*, not calling. – Martijn Pieters Oct 16 '17 at 15:31
  • Thanks. Yes, I was thinking about wrapping method objects. But I can't tell whether something is a method object waiting for the response from the inner object. Thus, I'd have to return a non-blocking proxy that blocks on `__call__`. However, the return value might not be a method, and in this case the proxy would have to behave like the return value. Do you know if it's possible for this proxy to fully behave like the return value? – danijar Oct 16 '17 at 16:19
  • so how *would* you know if something is a method that has to wait for a response? – Martijn Pieters Oct 16 '17 at 16:20
  • Sorry, I saw a few typos in my previous comment that made it hard to read. I won't know the type until the return value arrives. But I could still hand back control to the user by returning an empty container object. When the container is called, it sends the args to the inner object and returns a promise of the response. When it's accessed in any other way, it has to block and wait for the return value and then behave like that return value. – danijar Oct 16 '17 at 18:49

0 Answers0