[Pythonmac-SIG] parameterize dot notation
TattooMabonzoK.
TattooMabonzoK.
Wed, 20 Sep 2000 11:53:43 +0200
--Apple-Mail-794195924-1
content-transfer-encoding: quoted-printable
content-type: text/plain;
charset=us-ascii
Hello Steven,
Thanks a lot for your quite comprehensive and didactic answer. Also many =
thanks to those who emailed me privately (essentially suggesting to use =
'eval')
The third form root[foo][bar][fubar] is IMHO the most elegant (ie most =
pythonic) although still slightly not as elegant as root.foo.bar.fubar =
which clearly indicates attribute access vs. mapping element access =
(although with the current Python implementation that's quite similar). =
But it will serve my purpose perfectly.
For some context here's how I want to use it.=20
In a Web Application I'm currently developing I'm using a Template class =
to implement templates (HTML, email or whatever kind of text templates).=20=
Templates can have attributes which are Templates themselves, hence my =
question.=20
Template instances are basically in-memory version of a files on disk =
with the added bonus that the accessor method __getattr__ takes care of =
refreshing the in-memory version of file if the file on disk has changed =
since last stored in memory. This provide a simple form of automatic =
update and caching at the cost of having an explicit accessor method. A =
trade-in between that an re-reading the files from disk everytime, or on =
request but then the templates wouldn't be automatically updated.=20
Since I'm lazy :-) I'd rather have the computer do the work and handle =
the automatic update thing whenever a template on disk is changed (I may =
change this design if checking the file moddate for each request is too =
much of a performance hit, but it doesn't seem to be).
Again thanks for your input. I'm going to go the __getitem__ route.
=3D tmk =3D
PS: If I were more knowledgeable about Python I'd probably file a PEP =
for the 'parameterize dot notation' :-). Or would that be a bad idea?
On Wednesday, September 20, 2000, at 12:00 AM, Steven D. Majewski wrote:
> =20
> On Tue, 19 Sep 2000, Tattoo Mabonzo K. wrote:=20
> =20
> > =20
> > In UserLand's Frontier, paths to 'objects' are denoted using a =20
> > syntax such as the following:=20
> > =20
> > root.foo.bar.fubar (1)=20
> > =20
> > Now suppose that v1, v2, v3 are variables holding the values =20
> > 'foo', 'bar', 'fubar' respectively, the following notation is =20
> > equivalent to (1): > =20
> > root.[v1].[v2].[v3] (2)=20
> > =20
> > I was wondering if there's a way in Python to achieve the same=20
> > ie 'parameterize'(is that a correct word anyway?) the path to an =
object =20
> > an object path. After all, Python seems to support syntax such as > =20=
> > root.foo().bar().fubar =20
> > (meaning that the intermediate steps in the previous path are not =
taken =20
> > 'literally' if you see what I mean). > =20
> =20
> =20
> There are several ways to dynamically access object attributes in =
Python,=20
> but you don't get anything like the Frontier syntax without some extra =
=20
> work. =20
> =20
> =20
> I. Classes and instances in Python have a __dict__ attribute which is =
the =20
> objects attribute dictionary, so you could say something like:=20
> =20
> root.__dict__[v1].__dict__[v2].__dict__[v3]=20
> =20
> =20
> II. There is a getattr function, which will:=20
> [1] work for things that don't have __dict__'s but do have =20
> attributes, like functions for example. =20
> [2] for objects and classes, it will search back thru the=20
> inheritance tree, if necessary, for an ancestor that defines=20=
> the attribute. ( For example, using the definitions below: =20
> root.__dict__['__getitem__'] would fail, while =20
> getattr( root, '__getitem__' ) would return:=20
> <method Fubar.__getitem__ of Root instance at ...> ) =20
> =20
> But the syntax would be nested rather than chained:=20
> getattr( getattr( getattr(root,v1), v2 ), v3 )=20
> =20
> =20
> III. If you define a __getitem__ method for all of the objects, =20
> then you can use the dictionary syntax without the explicit=20
> __dict__ references -- something like: =20
> =20
> root[v1][v2][v3]=20
> =20
> =20
> =20
> In the example below, the three print statements at the bottom=20
> all print the same object. =20
> =20
> =20
> class Fubar:=20
> def __getitem__( self, what ):=20
> return getattr( self, what )=20
> =20
> class Bar(Fubar):=20
> def __init__( self ):=20
> self.fubar =3D Fubar()=20
> =20
> class Foo(Bar):=20
> def __init__(self):=20
> self.bar =3D Bar()=20
> =20
> class Root(Foo):=20
> def __init__(self):=20
> self.foo =3D Foo()=20
> =20
> v1,v2,v3 =3D 'foo','bar','fubar'=20
> =20
> root =3D Root()=20
> =20
> print getattr( getattr( getattr(root,v1), v2 ), v3 )=20
> print root.__dict__[v1].__dict__[v2].__dict__[v3]=20
> print root[v1][v2][v3]=20
> =20
> =20
> ---| Steven D. Majewski (804-982-0831) <sdm7g@Virginia.EDU> |---=20=
> ---| Department of Molecular Physiology and Biological Physics |---=20=
> ---| University of Virginia Health Sciences Center |---=20=
> ---| P.O. Box 10011 Charlottesville, VA 22906-0011 |---=20=
> "All operating systems want to be unix, =20
> All programming languages want to be lisp." =20
> =20
> =20
> =20
--Apple-Mail-794195924-1
content-transfer-encoding: quoted-printable
content-type: text/enriched;
charset=us-ascii
<=
flushleft><smaller><fontfamily><param>Monaco</param><x-tabstops><param>28L=
;56L;84L;112L;140L;168L;196L;224L;252L;280L;308L;336L;</param>Hello =
Steven,
Thanks a lot for your quite comprehensive and didactic answer. Also many =
thanks to those who emailed me privately (essentially suggesting to use =
'eval')
The third form root[foo][bar][fubar] is IMHO the most elegant (ie most =
pythonic) although still slightly not as elegant as root.foo.bar.fubar =
which clearly indicates attribute access vs. mapping element access =
(although with the current Python implementation that's quite similar). =
But it will serve my purpose perfectly.
For some context here's how I want to use it.=20
In a Web Application I'm currently developing I'm using a Template class =
to implement templates (HTML, email or whatever kind of text templates).=20=
Templates can have attributes which are Templates themselves, hence my =
question.=20
Template instances are basically in-memory version of a files on disk =
with the added bonus that the accessor method __getattr__ takes care of =
refreshing the in-memory version of file if the file on disk has changed =
since last stored in memory. This provide a simple form of automatic =
update and caching at the cost of having an explicit accessor method. A =
trade-in between that an re-reading the files from disk everytime, or on =
request but then the templates wouldn't be automatically updated.=20
Since I'm lazy :-) I'd rather have the computer do the work and handle =
the automatic update thing whenever a template on disk is changed (I may =
change this design if checking the file moddate for each request is too =
much of a performance hit, but it doesn't seem to be).
Again thanks for your input. I'm going to go the __getitem__ route.
=3D tmk =3D
PS: If I were more knowledgeable about Python I'd probably file a PEP =
for the 'parameterize dot notation' :-). Or would that be a bad idea?
On Wednesday, September 20, 2000, at 12:00 AM, Steven D. Majewski wrote:
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> On Tue, 19 Sep 2000, Tattoo =
Mabonzo K. wrote: </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,6363,1212</param>> > </color>
<color><param>0000,6363,1212</param>> > In UserLand's Frontier, paths to =
'objects' are denoted using a </color>
<color><param>0000,6363,1212</param>> > syntax such as the following: =
</color>
<color><param>0000,6363,1212</param>> > </color>
<color><param>0000,6363,1212</param>> > root.foo.bar.fubar (1) </color>
<color><param>0000,6363,1212</param>> > </color>
<color><param>0000,6363,1212</param>> > Now suppose that v1, v2, v3 are =
variables holding the values </color>
<color><param>0000,6363,1212</param>> > 'foo', 'bar', 'fubar' =
respectively, the following notation is </color>
<color><param>0000,6363,1212</param>> > equivalent to (1): > </color>
<color><param>0000,6363,1212</param>> > root.[v1].[v2].[v3] (2) </color>
<color><param>0000,6363,1212</param>> > </color>
<color><param>0000,6363,1212</param>> > I was wondering if there's a way =
in Python to achieve the same </color>
<color><param>0000,6363,1212</param>> > ie 'parameterize'(is that a =
correct word anyway?) the path to an object </color>
<color><param>0000,6363,1212</param>> > an object path. After all, =
Python seems to support syntax such as > </color>
<color><param>0000,6363,1212</param>> > root.foo().bar().fubar </color>
<color><param>0000,6363,1212</param>> > (meaning that the intermediate =
steps in the previous path are not taken </color>
<color><param>0000,6363,1212</param>> > 'literally' if you see what I =
mean). > </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> There are several ways to =
dynamically access object attributes in Python, </color>
<color><param>0000,0000,DEDE</param>> but you don't get anything like =
the Frontier syntax without some extra </color>
<color><param>0000,0000,DEDE</param>> work. </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> I. Classes and instances in Python =
have a __dict__ attribute which is the </color>
<color><param>0000,0000,DEDE</param>> objects attribute dictionary, =
so you could say something like: </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> =
root.__dict__[v1].__dict__[v2].__dict__[v3] </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> II. There is a getattr function, =
which will: </color>
<color><param>0000,0000,DEDE</param>> [1] work for things that don't =
have __dict__'s but do have </color>
<color><param>0000,0000,DEDE</param>> attributes, like functions for =
example. </color>
<color><param>0000,0000,DEDE</param>> [2] for objects and classes, it =
will search back thru the </color>
<color><param>0000,0000,DEDE</param>> inheritance tree, if =
necessary, for an ancestor that defines </color>
<color><param>0000,0000,DEDE</param>> the attribute. ( For example, =
using the definitions below: </color>
<color><param>0000,0000,DEDE</param>> root.__dict__['__getitem__'] =
would fail, while </color>
<color><param>0000,0000,DEDE</param>> getattr( root, '__getitem__' ) =
would return: </color>
<color><param>0000,0000,DEDE</param>> <<method Fubar.__getitem__ of =
Root instance at ...> ) </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> But the syntax would be nested =
rather than chained: </color>
<color><param>0000,0000,DEDE</param>> getattr( getattr( =
getattr(root,v1), v2 ), v3 ) </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> III. If you define a __getitem__ =
method for all of the objects, </color>
<color><param>0000,0000,DEDE</param>> then you can use the =
dictionary syntax without the explicit </color>
<color><param>0000,0000,DEDE</param>> __dict__ references -- =
something like: </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> root[v1][v2][v3] =
</color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> In the example below, the three =
print statements at the bottom </color>
<color><param>0000,0000,DEDE</param>> all print the same object. =
</color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> class Fubar: </color>
<color><param>0000,0000,DEDE</param>> def __getitem__( self, =
what ): </color>
<color><param>0000,0000,DEDE</param>> return getattr( =
self, what ) </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> class Bar(Fubar): </color>
<color><param>0000,0000,DEDE</param>> def __init__( self ): =
</color>
<color><param>0000,0000,DEDE</param>> self.fubar =3D =
Fubar() </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> class Foo(Bar): </color>
<color><param>0000,0000,DEDE</param>> def __init__(self): =
</color>
<color><param>0000,0000,DEDE</param>> self.bar =3D Bar() =
</color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> class Root(Foo): </color>
<color><param>0000,0000,DEDE</param>> def __init__(self): =
</color>
<color><param>0000,0000,DEDE</param>> self.foo =3D Foo() =
</color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> v1,v2,v3 =3D 'foo','bar','fubar' =
</color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> root =3D Root() </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> print getattr( getattr( =
getattr(root,v1), v2 ), v3 ) </color>
<color><param>0000,0000,DEDE</param>> print =
root.__dict__[v1].__dict__[v2].__dict__[v3] </color>
<color><param>0000,0000,DEDE</param>> print root[v1][v2][v3] </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> ---| Steven D. Majewski =
(804-982-0831) <<sdm7g@Virginia.EDU> |--- </color>
<color><param>0000,0000,DEDE</param>> ---| Department of Molecular =
Physiology and Biological Physics |--- </color>
<color><param>0000,0000,DEDE</param>> ---| University of Virginia =
Health Sciences Center |--- </color>
<color><param>0000,0000,DEDE</param>> ---| P.O. Box 10011 =
Charlottesville, VA 22906-0011 |--- </color>
<color><param>0000,0000,DEDE</param>> "All operating systems =
want to be unix, </color>
<color><param>0000,0000,DEDE</param>> All programming =
languages want to be lisp." </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> </color>
<color><param>0000,0000,DEDE</param>> </color>
</x-tabstops></fontfamily></smaller></flushleft>=
--Apple-Mail-794195924-1--