Hi, I need a product with custom attribute getting code and so looked to the BTreeFolder product for inspiration. It implements both __getattr__ and _getOb which appear to do roughly the same thing. What's the difference? Shane hints that __getattr__ is slower but allows acquisiton. Why is that? TIA, Chris
On 2/27/01 10:59 AM, in article 3A9BCED9.A94826E@nipltd.com, "Chris Withers" <chrisw@nipltd.com> wrote:
Hi,
I need a product with custom attribute getting code and so looked to the BTreeFolder product for inspiration.
It implements both __getattr__ and _getOb which appear to do roughly the same thing.
What's the difference?
Shane hints that __getattr__ is slower but allows acquisiton. Why is that?
_getOb and _setOb are for placing subobjects somewhere besides attributes (which is the default implementation). _getOb and friends are the default protocol that *SHOULD* be used by systems that change subobjects (ie - copy and paste). Jeffrey P Shell, jeffrey@Digicool.com http://www.digicool.com/ | http://www.zope.org
"Chris Withers" <chrisw@nipltd.com> wrote:
Jeffrey P Shell wrote:
_getOb and _setOb are for placing subobjects somewhere besides attributes (which is the default implementation).
When would __getattr__ be used then?
In what context? You could wire __getattr__ to call into _getOb (and probably __getitem__ too, since that's also used in traversal and as a way of getting non-Pythonic ID'd objects). def __getattr__(self, attr): return self._getOb(attr) Until very recently, __getattr__ on persistent objects was like playing with nuclear fire. But now, I *believe* it behaves properly, which means __getattr__ gets called when it receives an unknown name. How that affects Acquisition, I don't know.
Jeffrey P Shell wrote:
_getOb and _setOb are for placing subobjects somewhere besides attributes (which is the default implementation).
_getOb and friends are the default protocol that *SHOULD* be used by systems that change subobjects (ie - copy and paste).
Sorry, just thought of another coupla questions: If x is an instance of my class, then: If I do x.a = 1, is _setOb called? If I do print x.a, is _getOb called? cheers, Chris
Sorry, just thought of another coupla questions:
If x is an instance of my class, then: If I do x.a = 1, is _setOb called? If I do print x.a, is _getOb called?
No in either case. _setOb shouldn't be used directly in the current ObjectManger implementation. It doesn't populate the _objects list of the object manager on which it was called (your object won't show up). Instead, _setObject should be called.
Chris McDonough wrote:
Sorry, just thought of another coupla questions:
If x is an instance of my class, then: If I do x.a = 1, is _setOb called? If I do print x.a, is _getOb called?
No in either case.
_setOb shouldn't be used directly in the current ObjectManger implementation. It doesn't populate the _objects list of the object manager on which it was called (your object won't show up). Instead, _setObject should be called.
well, thankfully, I'm not going near __setattr__, _setOb or _setObject :-) On the setting side, only __setitem__ is getting meddled with, and I'm guessing there's not gotachas there? Anyway, using these methods: # attribute - based traversal stuff def _getOb(self, name, default=_marker): print '_getOb:',name try: return higher_getOb(self,name) except: import sys print 'type:',sys.exc_type print 'value:',sys.exc_value raise AttributeError,name def __getattr__(self,name,higher_getattr=higher_getattr): #print '__getattr__:',name try: return higher_getattr(self,name) except AttributeError: import sys #print 'type:',sys.exc_type #print 'value:',sys.exc_value raise AttributeError,name def __getitem__(self,name,higher_getitem=higher_getitem): print '__getitem__:',name try: return higher_getitem(self,name) except KeyError: import sys #print 'type:',sys.exc_type #print 'value:',sys.exc_value raise KeyError,name ...it would appear that unrestrictedTraverse first tries to use getattr and then tries to use getitem to get a name. That much I can veryify from the code ;-) However, it would appear that somewhere in a __getitem__ as implemented by ZCatalog, _getOb ends up getting called. Which is a little confusing :-S I think I know when the __get methods get called; same as normal python right? But when, why, how and what by does _getOb and/org _getObject and/or anything else I might be interested about in this space get called? ;-) Thanks loads for the help so far, Chris
Chris Withers wrote:
Hi,
I need a product with custom attribute getting code and so looked to the BTreeFolder product for inspiration.
It implements both __getattr__ and _getOb which appear to do roughly the same thing.
What's the difference?
_getOb() is part of the ObjectManager interface. If you want to store objects in your special ObjectManager in a special way, you override _getOb(), _setOb(), and _delOb(). (I didn't check the spelling--see ObjectManager.py) However, if you store objects in your ObjectManager in a different way than using setattr(self, name, value), acquisition won't find your subobjects because acquisition only looks at object attributes. It doesn't know anything about _getOb(). (And it's not a good idea to teach it to use _getOb(); think what it would be like if a Xeon ran like a 386...) Overriding __getattr__() lets you make acquisition work again. However, as Jeffrey said, until a few months ago it was forbidden. Then Jim fixed it. Now it's used extensively by BTreeFolders, Transparent Folders, and even the CMF. However, every time the acquisition machinery calls a __getattr__() you get a performance hit in the range of a few microseconds. But the products I listed try hard to minimize that impact, so it's not enough of an issue to warrant a C implementation. BTreeFolder.py provides a base class that doesn't have __getattr__(). You can use that if you think __getattr__() is slowing down your site. The derived class is what most people use because it provides the full functionality. Shane
subobjects because acquisition only looks at object attributes. It doesn't know anything about _getOb(). (And it's not a good idea to teach it to use _getOb(); think what it would be like if a Xeon ran like a 386...)
I remember the days when... ;-) Seriously though, why would that make it so slow? Is _getOb() often an expensive operation? thanks for all the info, Chris
Chris Withers wrote:
subobjects because acquisition only looks at object attributes. It doesn't know anything about _getOb(). (And it's not a good idea to teach it to use _getOb(); think what it would be like if a Xeon ran like a 386...)
I remember the days when... ;-)
Seriously though, why would that make it so slow? Is _getOb() often an expensive operation?
No. The expensive part is invoking Python code from C. It's the same problem described by the documentation for the Python sort() method: it's much faster to sort() then reverse() than it is to sort() with a comparison function that reverses the elements. Invoking C from Python is fast, but invoking Python from C apparently requires a lot of work. Shane
Shane Hathaway wrote:
No. The expensive part is invoking Python code from C. It's the same problem described by the documentation for the Python sort() method: it's much faster to sort() then reverse() than it is to sort() with a comparison function that reverses the elements. Invoking C from Python is fast, but invoking Python from C apparently requires a lot of work.
Thanks, that actually explains (completely unrelated to __getattr__ ;-) why one of our Zope products is so dog slow right now :-) cheers, Chris
On Wed, 07 Mar 2001 09:49:09 -0500, Shane Hathaway <shane@digicool.com> wrote:
Invoking C from Python is fast, but invoking Python from C apparently requires a lot of work.
Invoking a python function from anywhere (even from another python function) requires alot of work. Toby Dickenson tdickenson@geminidataloggers.com
participants (5)
-
Chris McDonough -
Chris Withers -
Jeffrey P Shell -
Shane Hathaway -
Toby Dickenson