Setting an attribute without calling __setattr__()

George Sakkis george.sakkis at gmail.com
Sat Apr 26 04:41:27 CEST 2008


On Apr 25, 5:01 pm, Joshua Kugler <jkug... at bigfoot.com> wrote:

> My init lookslike this:
>
>     def __init__(self, obj=None):
>         if type(obj).__name__ in 'list|tuple|set|frozenset':
>             self.me = []
>             for v in obj:
>                 self.me.append(ObjectProxy(v))
>         elif type(obj) == dict:
>             self.me = {}
>             for k,v in obj.items():
>                 self.me[k] = ObjectProxy(v)

As an aside, unrelated to your question, Python encourages "duck
typing" instead of exact type matching. Unless you have a good reason
to restrict obj to one of the 5 types you hardcoded (a rather rare
need), it is more flexible to write it as:

     def __init__(self, obj=None):
         if hasattr(obj, 'items'):
             # assume obj is a mapping type instance
             self.me = dict((k,ObjectProxy(v)) for k,v in obj.items())
         else:
             try: # check if obj is an iterable instance
                 self.me = map(ObjectProxy, obj)
             except TypeError:
                 # handle other cases here
                 # self.me = ...


A downside of this flexibility is that it may be more liberal than it
should. For instance, if obj just happens to have an 'items()' method
but it's not really a mapping type, the assumption is violated. Python
3 deals with such potential ambiguities by introducing Abstract Base
Classes (ABCs) [1] that allow a class to make explicit its semantics.
So in Py3K the hasattr() test above would rather be written as
"isinstance(obj, Mapping)", where Mapping is the ABC that represents
(read-only) mappings.

A more difficult problem is that even if a class derives from some
ABC, you may not always want to treat its instances as such. The
typical gotcha is that strings are iterable, but in many (most?)
applications they are to be treated as atomic values, not as sequences
of characters. So in the example above if obj is a string, self.me
will be a list of ObjectProxy instances, one per character; probably
not what you intend. Of course we can check for "isinstance(obj,str)"
but then we're back at explicit type checking. There is no general way
to express something lke "atomic value that also happens to be
iterable (but pretend it's not)" because it's inherently domain-
dependent.

George

[1] http://www.python.org/dev/peps/pep-3119/



More information about the Python-list mailing list