__getattr__ and __setattr__ from custom python objects.

40 views
Skip to first unread message

mcot

unread,
Dec 7, 2010, 7:08:02 PM12/7/10
to PyV8
I want to be able to use __getattr__ and __setattr__ from my Python
code for dynamic property access. I am noticing some strange behavior
with PyV8.

import PyV8

class Global(PyV8.JSClass):

def __init__(self):
self.x = 10
self.y = self

def write(self, val):
print val

def __setattr__(self, name, value):

print "Set Attribute: %s %s" % (name, value)
object.__setattr__(self, name, value)

def __getattr__(self, name):

print "Get Attribute: %s" % name

with PyV8.JSContext(Global()) as ctx:
ctx.eval("""

write(x);
y.z = 10;
write(z);
""")

With the above code sample I get an output of:


Set Attribute: x 10
Set Attribute: y <__main__.Global object at 0x7faf8f597d50>
10
Get Attribute: z
Set Attribute: z 10
10

I am wondering why __getattr__ gets called when I am setting a
property. Standard python would usually yield this:

class Global(object):

def __init__(self):
self.x = 10
self.y = self

def write(self, val):
print val

def __setattr__(self, name, value):

print "Set Attribute: %s %s" % (name, value)
object.__setattr__(self, name, value)

def __getattr__(self, name):

print "Get Attribute: %s" % name

#return PyV8.JSClass.__getattr__(self, name)

x = Global()
x.y.z = 10


Output:


Set Attribute: x 10
Set Attribute: y <__main__.Global object at 0x7f5f134da790>
Set Attribute: z 10



I am also wondering about __getattr__ in PyV8.py

def __getattr__(self, name):
if name == 'constructor':
return JSClassConstructor(self.__class__)

raise AttributeError(name)

I used the code from the first example but added "return
PyV8.JSClass.__getattr__(self, name)" to my own __getattr__. An
AttributeError exception from the "Get Attribute: z" is being raised
as I would expect, but then it is being caught somewhere. I am trying
to figure out where and why and how the exception gets handled.

Thanks in advance.

Flier Lu

unread,
Dec 8, 2010, 12:10:41 PM12/8/10
to PyV8
The first question was caused by a design problem. Because PyV8
support to use a Python map object as a Javascript object. It means,
if you pass a map object to Javascript, and get/set its property, if
the property doesn't exists, the value will be read from or add to the
map. To implement it, pyv8 must use PyObject_HasAttrString to check
whether the property exists, which will call the __getattr__. So, if
the behavior real broke your code, I think we could remove the check
code, and force to get/set value when the object is a python map
object.

The second question was caused by the Javascript standard. When you
try to get a property that doesn't exists, Javascript should return
undefined. It means, even you raise a exception from Python part, pyv8
will catch the exception and just return a undefined to Javascript
code. You could try to comment the "y.z=10" line

def __getattr__(self, name):
print "Get Attribute: %s" % name

if name == 'constructor':
return JSClassConstructor(self.__class__)

print "here"
raise AttributeError(name)

with PyV8.JSContext(Global()) as ctx:
ctx.eval("""
write(x);
//y.z = 10;
write("z="+z);
""")

Output:

Get Attribute: z
z=undefined


http://www.ecma-international.org/publications/standards/Ecma-262.htm

8.6.2.1 [[Get]] (P)
When the [[Get]] method of O is called with property name P, the
following steps are taken:
1. If O doesn’t have a property with name P, go to step 4.
2. Get the value of the property.
3. Return Result(2).
4. If the [[Prototype]] of O is null, return undefined.
5. Call the [[Get]] method of [[Prototype]] with property name P.
6. Return Result(5).

mcot

unread,
Dec 10, 2010, 4:54:21 PM12/10/10
to PyV8
I am having a little trouble understanding the output of this:

import PyV8

class Global(PyV8.JSClass):
def __init__(self):
pass

with PyV8.JSContext(Global()) as ctx:
ctx.eval("""var x = z""")


with PyV8.JSContext() as ctx:
ctx.eval("""var x = z""")

Only the second one produces a reference error. Shouldn't they both
produce a reference error?

Flier Lu

unread,
Dec 10, 2010, 8:56:48 PM12/10/10
to PyV8
I think it is a bug, the global object should throw a reference error
when access a nonexists field.

I have submitted a bug to trace it, and it should be fixed soon,
thanks :)

http://code.google.com/p/pyv8/issues/detail?id=61

Flier Lu

unread,
Dec 11, 2010, 3:42:07 AM12/11/10
to PyV8
done, now pyv8 will throw ReferenceError when access nonexists
property of the global object

please verify the issue with SVN trunk r304 or later, thanks
Reply all
Reply to author
Forward
0 new messages