unpythonic use of property()?

Scott David Daniels Scott.Daniels at Acm.Org
Fri Apr 17 19:00:33 EDT 2009


Carl Banks wrote:
> On Apr 17, 10:21 am, J Kenneth King <ja... at agentultra.com> wrote:
>> Consider:
>>
>> code:
>> ------------------------------------------------------------------------
>>
>> class MyInterface(object):
>>
>>     def __get_id(self):
>>         return self.__id
>>
>>     id = property(fget=__get_id)
>>
>>     def __init__(self, id, foo):
>>         self.__id = id
>>         self.foo = foo
>>
>> class MyInterface2(object):
>>
>>     def __init__(self, id, foo):
>>         self._id = id
>>         self.foo = foo
>>
>>     @property
>>     def id(self):
>>         return self._id
>>
...
>> I was recently informed that it was 'unpythonic' and have since been a
>> little confused by the term. I've heard it bandied about before but
>> never paid much attention. What is 'unpythonic'? What about this example
>> is unpythonic?
> 
> There are different reasons someone might have said it.
> ...
> Some people think attribute name-mangling is unpythonic.  It's true
> that people sometimes mistakenly treat it a solid information hiding
> mechanism, but I wouldn't call its usage unpythonic when used as
> intended: as a way to avoid name-collisions.  If you think it's
> worthwhile to protect an attribute from being overwritten, you might
> as well guard against accidental conflict with the underlying name.

Here you are assuming that a user of your class could not possibly have a
valid reason for getting to the underlying variable.  Don't make those
decisions for someone else, in Python, "we are all adults here."

> Finally, some people think read-only attributes are unpythonic.  I
> think that's ridiculous, although in general I'd advise against making
> attributes read-only willy-nilly.  But there's a time and place for
> it.

Generally, properties are for doing some form of calculation, not
for making things read-only.  If the thing you were returning were
in some way calculated, it would make sense to use a property.  We
normally use properties to allow a later attribute access to provide
the same interface as the original did with a simple attribute access.

So, I would advocate using:

     class SimplerInterface(object):
         def __init__(self, id, foo):
             self.id = id
             self.foo = foo

Note that this allows:

     q = SimplerInterface('big', 'foo')
     print (q.id)
     q.id = 'small'
     print (q.id)

But this is only a more straightforward way of writing:

     q = MyInterface2('big', 'foo')
     print (q.id)
     q._id = 'small'
     print (q.id)

or even:

     q = MyInterface('big', 'foo')
     print (q.id)
     q._MyInterface__id = 'small'
     print (q.id)

See, someone can work around your protection.  If you say, "don't do
that," I'd reply, "just tell your users not to change id."  It is not
your job to protect those users who do not use your code properly from
themselves; that way lies madness.

> Last thing I'll advise is don't get too hung up on terms like
> "Pythonic".  Treat such labels are more of a red flag and get people
> who throw out the term to explain why.

Think of it as a comment like "that has a bad code smell" -- you can do
it if you like, but you should have satisfied yourself that your case is
sufficiently special as to require an unusual approach.  The PSU will
not come after you, as they are busy hunting down Barry & Guido.

--Scott David Daniels
Scott.Daniels at Acm.Org



More information about the Python-list mailing list