Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Re: "Aliasing" an object's __str__ to a different method

Reply
Thread Tools

Re: "Aliasing" an object's __str__ to a different method

 
 
Jeffrey E. Forcier
Guest
Posts: n/a
 
      07-23-2005
Thanks for all the additional replies thus far!

Apparently the issue, as stated implicitly or explicitly by most of
you, is that new-style class instances essentially defer their magic
methods to the class's static versions of same. This is good to know

Ironically, the reason I'm using new-style classes is that I only
read up on them very recently, and was attempting to get myself into
the habit of inheriting from 'object' by default. Go figure.

Anyway, to take a step back, the *actual* actual reason for my
investigation into this issue is that I'm attempting to create a
collection of classes representing HTML page/form elements, many of
which are represented differently depending on whether they're in a
"view" or "edit" state.

And ideally I wanted to be able to hold a collection of these objects
and toggle them all to one state or the other, then bandy them about
as if they were strings, e.g. mixing them with literal strings via str
(obj).

Clearly there are at least a handful of ways to accomplish this, but
the one that came to mind first was, as I said at the beginning, to
define both behaviors on each object and then have the ability to
point __str__ to one or the other. I suppose now I need to figure out
which is more important, that ease-of-use of overriding __str__ or
whatever benefits new-style classes give (something I'm still a bit
unclear on).

Thanks again,
Jeff

--
Jeffrey E. Forcier
Junior Developer, Research and Development
Stroz Friedberg, LLC
15 Maiden Lane, 12th Floor
New York, NY 10038
[main]212-981-6540 [direct]212-981-6546
http://www.strozllc.com

This message is for the named person's use only. It may contain
confidential, proprietary or legally privileged information. No right to
confidential or privileged treatment of this message is waived or lost
by any error in transmission. If you have received this message in
error, please immediately notify the sender by e-mail or by telephone at
212.981.6540, delete the message and all copies from your system and
destroy any hard copies. You must not, directly or indirectly, use,
disclose, distribute, print or copy any part of this message if you are
not the intended recipient.

 
Reply With Quote
 
 
 
 
Bengt Richter
Guest
Posts: n/a
 
      07-24-2005
On Sat, 23 Jul 2005 10:59:56 -0400, "Jeffrey E. Forcier" <(E-Mail Removed)> wrote:

>Thanks for all the additional replies thus far!
>
>Apparently the issue, as stated implicitly or explicitly by most of
>you, is that new-style class instances essentially defer their magic
>methods to the class's static versions of same. This is good to know


Actually, it's not just the "magic" methods. If you have an instance
a of a newstyle class A, any attribute lookup a.attr will undergo the
same search first to see if attr is a descriptor object, and if not,
*then* to look in the instance attribute directory. But the descriptor
search doesn't start in inst.__dict__, it goes through the chain of
classes and base classes provided by type(inst).mro(), which starts in
type(inst). And for our class A instance a, type(a) will be A, so the
search for a.attr starts there. Same applies to a.__str__. This ensures
that all instances of the same class will share the same methods. The way
a method, which is just a class variable with a function as its value, gets
to be a callable bound method, is the same as any attribute lookup looking
for a descriptor with a __get__ method (which a function also has, for this purpose).
If the descriptor doesn't have a __set__ method as well, then an instance attribute
takes priority. If there is a __set__ method, and instance attribute can't shadow
the attribute name, and the descriptor __get__ method takes precedence. Unshadowed,
a method search looks something like

cbm = ((base for base in type(inst).mro() if 'attr' in base.__dict__)
.next().__dict__['attr'].__get__(inst, type(inst)))

if this doesn't succeed and meet the __set__ vs shadowing logic, then you get
the instance attribute per se.

Jumping ahead using a MyClass inst as an example:

>>> cbm = ((base for base in type(inst).mro() if '__str__' in base.__dict__)

... .next().__dict__['__str__'].__get__(inst, type(inst)))
>>> cbm

<bound method MyClass.View of I, <__main__.MyClass object at 0x02FB91AC>, am being viewed>

This looks a little strange because the repr of the bound method includes a repr of the thing bound to,
which returns the Edit/View presentation (after the 'of' above).
(A possible reason to consider using just __str__ and letting __repr__ be).

A function's __get__ method will deliver a bound method if the lookup
is via an inst, or an unbound method if the lookup is via the class, in which
case None is passed to __get__ instead of the instance.

The upshot is that you can create descriptors __str__ and __repr__for your class that will
return bound methods using __str__ and __repr__ function attributes of your instance (if they exist)
instead of the normal class attributes, and we can chose from several normal class attributes according
to a general mode flag of the class. E.g., using your original example, and rearranging things a bit,
we can do something like what (I think) you wanted: (The first class below defines descriptors and the
example uses two instances in MyClass)

>>> class InstanceMethodSetterAndBinder(object):

... def __init__(self, inst_attr_name):
... # lambda self:'?? no %s format ??'% object.__repr__(self)
... self.inst_attr_name = inst_attr_name
... def __get__(self, inst, cls=None):
... if inst is None: return self
... default = getattr((cls or type(inst)), 'SharedEVMethod', None)
... if default is None:
... def default(self):
... return '<?? no SharedEVMethod for %s ??>'% object.__repr__(inst)
... return vars(inst).get(self.inst_attr_name, default).__get__(inst, cls)
... def __set__(self, inst, value):
... inst.__dict__[self.inst_attr_name] = value
... def __delete__(self, inst):
... try: del inst.__dict__[self.inst_attr_name]
... except KeyError: pass
...
>>> class MyClass(object):

... __str__ = InstanceMethodSetterAndBinder('__str__')
... __repr__ = InstanceMethodSetterAndBinder('__repr__')
... @staticmethod
... def Edit(self):
... return "I, %s, am being edited" % (object.__repr__(self)) # %s on self recurses!!
... @staticmethod
... def View(self):
... return "I, %s, am being viewed" % (object.__repr__(self)) # %s on self recurses!!
... SharedEVMethod = View
... def setEdit(self, shared=True):
... if not shared:
... self.__str__ = self.__repr__ = self.Edit
... else:
... type(self).SharedEVMethod = self.Edit
... def setView(self, shared=True):
... if not shared:
... self.__str__ = self.__repr__ = self.View
... else:
... type(self).SharedEVMethod = self.View
... def delInstEVM(self):
... del self.__str__
... del self.__repr__
...
>>> inst = MyClass()
>>> inst2 = MyClass()
>>> inst3 = MyClass()
>>> inst

I, <__main__.MyClass object at 0x02FB91AC>, am being viewed
>>> inst2

I, <__main__.MyClass object at 0x02FB91CC>, am being viewed
>>> inst3

I, <__main__.MyClass object at 0x02FB91EC>, am being viewed
>>> inst.setEdit()
>>> inst

I, <__main__.MyClass object at 0x02FB91AC>, am being edited
>>> inst2

I, <__main__.MyClass object at 0x02FB91CC>, am being edited
>>> inst3

I, <__main__.MyClass object at 0x02FB91EC>, am being edited
>>> inst2.setView(False)
>>> inst

I, <__main__.MyClass object at 0x02FB91AC>, am being edited
>>> inst2

I, <__main__.MyClass object at 0x02FB91CC>, am being viewed
>>> inst3

I, <__main__.MyClass object at 0x02FB91EC>, am being edited
>>> inst2.setView() # all
>>> inst2.setEdit(False) # just inst
>>> inst

I, <__main__.MyClass object at 0x02FB91AC>, am being viewed
>>> inst2

I, <__main__.MyClass object at 0x02FB91CC>, am being edited
>>> inst3

I, <__main__.MyClass object at 0x02FB91EC>, am being viewed
>>> inst2.delInstEVM()
>>> inst2

I, <__main__.MyClass object at 0x02FB91CC>, am being viewed

You could use this kind of thing in a base class and specialize
in subclasses to override stuff, and you can do other stuff too.
Your choices are more varied that you probably thought

>
>Ironically, the reason I'm using new-style classes is that I only
>read up on them very recently, and was attempting to get myself into
>the habit of inheriting from 'object' by default. Go figure.
>
>Anyway, to take a step back, the *actual* actual reason for my
>investigation into this issue is that I'm attempting to create a
>collection of classes representing HTML page/form elements, many of
>which are represented differently depending on whether they're in a
>"view" or "edit" state.
>
>And ideally I wanted to be able to hold a collection of these objects
>and toggle them all to one state or the other, then bandy them about

^^^^^^^^^^^^^^^
does that mean all instances with a single toggling action, or each
individually? You could have both. I.e., a general mode flag and the
ability to assign an arbitrary __str__ and/or __repr__ override for
a particular instance. See example, where all are toggled by default.

>as if they were strings, e.g. mixing them with literal strings via str
>(obj).

Note that your example set __repr__ also, which is not used for str(x)
if x.__str__ exists.
>
>Clearly there are at least a handful of ways to accomplish this, but
>the one that came to mind first was, as I said at the beginning, to
>define both behaviors on each object and then have the ability to
>point __str__ to one or the other. I suppose now I need to figure out
>which is more important, that ease-of-use of overriding __str__ or
>whatever benefits new-style classes give (something I'm still a bit
>unclear on).
>

Those aren't your only choices

Regards,
Bengt Richter
 
Reply With Quote
 
 
 
 
Jeffrey E. Forcier
Guest
Posts: n/a
 
      07-24-2005
On Jul 24, 2005, at 5:00 AM, Bengt Richter wrote:

> Actually, it's not just the "magic" methods. [...]


Thanks for the clarification/explanation =)

> This looks a little strange because the repr of the bound method
> includes a repr of the thing bound to,
> which returns the Edit/View presentation (after the 'of' above).
> (A possible reason to consider using just __str__ and letting
> __repr__ be).


Yea, I must apologize, I pasted in a slightly different version of
the class in my original email than I intended to...I fully
understand the difference between __str__ and __repr__ and that bit
of code where I attempted to bind to both was me attempting to
discern exactly what was going on. The "real" version would only be
binding to __str__ and leaving __repr__ alone so it could be used as
intended =)

> A function's __get__ method will deliver a bound method if the lookup
> is via an inst, or an unbound method if the lookup is via the
> class, in which
> case None is passed to __get__ instead of the instance.
>
> The upshot is that you can create descriptors __str__ and
> __repr__for your class that will
> return bound methods using __str__ and __repr__ function attributes
> of your instance (if they exist)
> instead of the normal class attributes, and we can chose from
> several normal class attributes according
> to a general mode flag of the class.


[big-arse snip of code/output]

I half-understood this and what followed, but that's my fault and not
that of your explanation. Honestly, I'm still trying to elevate my
Python knowledge from a primarily quick-scripting level to one
suitable for larger applications (or at least, more intelligent
scripts =)). Specifically with things like descriptors and their ilk,
I need to reread the various docs and PEPs out there.

But, thanks for the detailed example, and you can be sure I'll return
to it in the near future after some more reading.


> You could use this kind of thing in a base class and specialize
> in subclasses to override stuff, and you can do other stuff too.
> Your choices are more varied that you probably thought


Oh, I know there's a whole host of ways to accomplish this, I just
tend to get narrowly focused on a single option or couple of options
for stretches of time, heh.

>> And ideally I wanted to be able to hold a collection of these objects
>> and toggle them all to one state or the other, then bandy them about
>>

> ^^^^^^^^^^^^^^^
> does that mean all instances with a single toggling action, or each
> individually? You could have both. I.e., a general mode flag and the
> ability to assign an arbitrary __str__ and/or __repr__ override for
> a particular instance. See example, where all are toggled by default.


Well, either, depending on how flexible I want the overall design to
be, but primarily all at once. E.g. I'd have a Page or PageBody
container class holding a bunch of (implementing the same interface)
objects as discussed, and would want all of those sub-objects to be
in the same mode. In other words...a page is either displaying text
fields for editing, or plain text for display (but with myriad form
elements, not just text fields, of course).


Thanks again,
Jeff

--
Jeffrey E. Forcier
Junior Developer, Research and Development
Stroz Friedberg, LLC
15 Maiden Lane, 12th Floor
New York, NY 10038
[main]212-981-6540 [direct]212-981-6546
http://www.strozllc.com

This message is for the named person's use only. It may contain
confidential, proprietary or legally privileged information. No right to
confidential or privileged treatment of this message is waived or lost
by any error in transmission. If you have received this message in
error, please immediately notify the sender by e-mail or by telephone at
212.981.6540, delete the message and all copies from your system and
destroy any hard copies. You must not, directly or indirectly, use,
disclose, distribute, print or copy any part of this message if you are
not the intended recipient.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: Problem with __str__ method and character encoding Chris Angelico Python 0 12-07-2012 02:33 PM
Re: Problem with __str__ method and character encoding peter Python 0 12-07-2012 02:22 PM
substitution __str__ method of an instance netimen Python 5 10-23-2008 09:49 PM
cpython list __str__ method for floats [david] Python 6 09-12-2007 11:48 PM
"Aliasing" an object's __str__ to a different method Jeffrey E. Forcier Python 7 07-24-2005 12:45 AM



Advertisments