predicting function calls?

R

Roy Smith

I think I know the answer to this, but I'll ask it just in case
there's something I hadn't considered...

I'm working on a python interface to a OODB. Communication with the
DB is over a TCP connection, using a model vaguely based on CORBA.
I'll be creating object handles in Python which are proxies for the
real objects in the database by doing something like:

handle = connection.getObjectHandle (className, instanceName)

Objects can have attributes (data) and operations associated with
them. It would be very convenient to use the "." syntax to access
both of these, i.e. be able to say:

print handle.someAttribute
print handle.someOperation (arg1, arg2)

I'm using __getattr__() to process both of these constructs, and
herein lies the rub; I need to do different things depending on
whether the name is an attribute or an operation. I can ask the DB
for a list of the names of all the operations supported by a given
object, but that's a fairly expensive thing to do, so I'd rather avoid
it if possible. It would be really nice if I had some way to find
out, from inside __getattr__(), if the value I'm about to return will
get called as a function (i.e., the name is followed by an open
paren). I can't see any way to do that, but maybe I'm missing
something?

One possibility would be to use different syntaxes for attributes and
operations, i.e:

print handle["someAttribute"]
print handle.someOperation (arg1, arg2)

but I really want to avoid having to do that for a variety of reasons,
not the least of which is syntax similarity with a legacy system.

The best I've come up with so far is doing the expensive "get a list
of operations for this class" call the first time I see an object of a
given class and caching the list. The problem there is that this is a
very dynamic system. It may be possible to add new operations on the
fly and I don't have any good way to invalidate the cache.

Any ideas?
 
M

Mike Meyer

Objects can have attributes (data) and operations associated with
them. It would be very convenient to use the "." syntax to access
both of these, i.e. be able to say:

print handle.someAttribute
print handle.someOperation (arg1, arg2)

I'm using __getattr__() to process both of these constructs, and
herein lies the rub; I need to do different things depending on
whether the name is an attribute or an operation. I can ask the DB
for a list of the names of all the operations supported by a given
object, but that's a fairly expensive thing to do, so I'd rather avoid
it if possible. It would be really nice if I had some way to find
out, from inside __getattr__(), if the value I'm about to return will
get called as a function (i.e., the name is followed by an open
paren). I can't see any way to do that, but maybe I'm missing
something?

Any ideas?

Fnorb (a pure-Python CORBA orb) dealt with this by not allowing
attributes per se. Instead, it provided _get_AttributeName and
_set_AttributeName as appropriate for each attribute in the IDL. Doing
this means that *everything* you hand back from __getattr__ is going
to be a callable, and presumably called at some point.

Properties postdate Fnorb, so weren't considered in it's design. You
might be able to do something with them as well.

<mike
 
S

Steven D'Aprano

I think I know the answer to this, but I'll ask it just in case
there's something I hadn't considered...

I'm working on a python interface to a OODB. Communication with the
DB is over a TCP connection, using a model vaguely based on CORBA.
I'll be creating object handles in Python which are proxies for the
real objects in the database by doing something like:

handle = connection.getObjectHandle (className, instanceName)

Objects can have attributes (data) and operations associated with
them. It would be very convenient to use the "." syntax to access
both of these, i.e. be able to say:

print handle.someAttribute
print handle.someOperation (arg1, arg2)

I'm using __getattr__() to process both of these constructs, and
herein lies the rub; I need to do different things depending on
whether the name is an attribute or an operation.
[snip]

It would be really nice if I had some way to find
out, from inside __getattr__(), if the value I'm about to return will
get called as a function (i.e., the name is followed by an open
paren).

How do you decide whether handle.foo should be treated as an attribute or
an operation?

If your object has an attribute foo, then what should you do when somebody
calls handle.foo()? That is, they treat an attribute as if it were an
operation? And vice versa.

In other words, it is not sufficient to know whether handle.foo is being
used as a operation or an attribute, but you need to know whether it
*should* be called as an operation or an attribute.
 
R

Roy Smith

Steven D'Aprano said:
How do you decide whether handle.foo should be treated as an attribute or
an operation?

That's exactly what I'm trying to figure out. In the legacy system I'm
trying to emulate, the interpreter knows the from syntax (i.e. whether
handle.foo is followed by an open paren or not). I'm looking for some way
I can emulate that behavior in Python.
If your object has an attribute foo, then what should you do when somebody
calls handle.foo()? That is, they treat an attribute as if it were an
operation? And vice versa.

That's easy. In such a case, the database will generate an error, which I
can then pass on to the user, probably by raising some subclass of
TypeError.
 
R

Roy Smith

Mike Meyer <[email protected]> said:
Fnorb (a pure-Python CORBA orb) dealt with this by not allowing
attributes per se. Instead, it provided _get_AttributeName and
_set_AttributeName as appropriate for each attribute in the IDL. Doing
this means that *everything* you hand back from __getattr__ is going
to be a callable, and presumably called at some point.

That's exactly what the low-level C/C++ API does in the system I'm working
with. It is, unfortunately, not the interface that's exposed by the serial
protocol.
 
O

OKB (not okblacke)

Roy said:
print handle.someAttribute
print handle.someOperation (arg1, arg2)

I'm using __getattr__() to process both of these constructs, and
herein lies the rub; I need to do different things depending on
whether the name is an attribute or an operation. I can ask the DB
for a list of the names of all the operations supported by a given
object, but that's a fairly expensive thing to do, so I'd rather avoid
it if possible. It would be really nice if I had some way to find
out, from inside __getattr__(), if the value I'm about to return will
get called as a function (i.e., the name is followed by an open
paren).

What do you do if the person does:

x = handle.someOperation
x(arg1, arg2)

--
--OKB (not okblacke)
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
 
E

Ernst Noch

Roy said:
I think I know the answer to this, but I'll ask it just in case
there's something I hadn't considered...

I'm working on a python interface to a OODB. Communication with the
DB is over a TCP connection, using a model vaguely based on CORBA.
I'll be creating object handles in Python which are proxies for the
real objects in the database by doing something like:

handle = connection.getObjectHandle (className, instanceName)

Objects can have attributes (data) and operations associated with
them. It would be very convenient to use the "." syntax to access
both of these, i.e. be able to say:

print handle.someAttribute
print handle.someOperation (arg1, arg2)

I'm using __getattr__() to process both of these constructs, and
herein lies the rub; I need to do different things depending on
whether the name is an attribute or an operation. I can ask the DB
for a list of the names of all the operations supported by a given
object, but that's a fairly expensive thing to do, so I'd rather avoid
it if possible. It would be really nice if I had some way to find
out, from inside __getattr__(), if the value I'm about to return will
get called as a function (i.e., the name is followed by an open
paren). I can't see any way to do that, but maybe I'm missing
something?

For various reasons also mentioned by other posters it's also not clear
to me how relying on user input should work. Esp. for the

x=obj.meth
print x(args)

case.

Couldn't you just, for every access to a member of your object, first
try to treat is as an access to an operation? If this fails (you
mentioned the db will throw an error if this is an attribute instead of
an operation), fall back to ask the db for an attribute of that name.

Or maybe just ask the db to look up this attribute in the list of
operations, depending which is faster.

Btw. if the system is very dynamic, you might have to think about also
implementing the attributes as proxies.
 
R

Roy Smith

Ernst Noch <[email protected]> said:
Couldn't you just, for every access to a member of your object, first
try to treat is as an access to an operation? If this fails (you
mentioned the db will throw an error if this is an attribute instead of
an operation), fall back to ask the db for an attribute of that name.

Or maybe just ask the db to look up this attribute in the list of
operations, depending which is faster.

Btw. if the system is very dynamic, you might have to think about also
implementing the attributes as proxies.

Well, what I ended up doing is having a proxy for each object. The first
time I access any instance of a given class, I get from the DB a list of
operations for that class and cache it (keyed by class).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,274
Messages
2,571,372
Members
48,064
Latest member
alibsskemoSeAve

Latest Threads

Top