[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--