I've been thinking in circles about these aspects of Pythonic design
and I'm curious what everyone else is doing and thinks. There are 3
issues here:
1) 'Declaring' attributes - I always felt it was good code practice to
declare attributes in a section of the class namespace. I set anything
that is constant but anything variable is set again in __init__():
Class A(object):
name = "a name"
type = "a typee"
childobject = None
def __init__(self, obj):
self.childobject = object
This makes it easy to remember and figure out what is in the class.
Granted there is nothing to enforce this, but that is why I called it
'code practice'. Do you agree or is this just extra work?
2) Internal attributes (starting with 2x'_') aren't inherited. Do you
just switch to a single '_' when you want an "internal" attribute
inherited? These are attributes I want the classes to use but not the
user of these classes. Of course, like anything else in Python, these
aren't really private. It is just a convention, right? (The example
for #3 shows this.)
3) It isn't possible to override a piece of a Property Descriptor. To
get around this, I define the necessary functions in the class but I
define the descriptor in the __new__() method so the inherting class
can override the methods. Am I overlooking some basic design principle
here? This seems like a lot of work for a simple behavior. Example:
class Base(object):
def __new__(cls):
setattr(cls,
"state",
property(fget = cls._Get_state,
fset = cls._Set_state,
fdel = None,
doc = cls._doc_state))
obj = super(Base, cls).__new__(cls)
return obj
state = None # Set in __new__()
_state = True
_doc_state = "The state of this object"
def _Get_state(self): return self._state
def _Set_state(self, value): self._state = value
class Child(Base):
def _Get_state(self):
# Do some work before getting the state.
print "Getting the state using the child's method"
return self._state
print Child().state
Please share your thoughts,
- Rafe
There's nothing like "declaration" of variables/attributes/whatever in
Python.
> - I always felt it was good code practice to
> declare attributes in a section of the class namespace. I set anything
> that is constant but anything variable is set again in __init__():
>
> Class A(object):
> name = "a name"
> type = "a typee"
> childobject = None
>
> def __init__(self, obj):
> self.childobject = object
>
> This makes it easy to remember and figure out what is in the class.
> Granted there is nothing to enforce this, but that is why I called it
> 'code practice'. Do you agree or is this just extra work?
It's not only extra work, it's mostly a WTF. You create class attributes
for no other reasons than to mimic some other mainstream languages. If I
was to maintain such code, I'd loose valuable time wondering where these
class attributes are used.
>
> 2) Internal attributes (starting with 2x'_') aren't inherited.
Yes they are. But you need to manually mangle them when trying to access
them from a child class method. FWIW, that *is* the point of
__name_mangling : making sure these attributes won't be accidentally
overwritten in a child class.
> Do you
> just switch to a single '_' when you want an "internal" attribute
> inherited? These are attributes I want the classes to use but not the
> user of these classes. Of course, like anything else in Python, these
> aren't really private. It is just a convention, right? (The example
> for #3 shows this.)
Yes. The (*very* strong) convention is that
_names_with_simple_leading_underscore denote implementation attributes.
> 3) It isn't possible to override a piece of a Property Descriptor. To
> get around this, I define the necessary functions in the class but I
> define the descriptor in the __new__() method so the inherting class
> can override the methods. Am I overlooking some basic design principle
> here? This seems like a lot of work for a simple behavior. Example:
>
> class Base(object):
> def __new__(cls):
> setattr(cls,
> "state",
> property(fget = cls._Get_state,
> fset = cls._Set_state,
> fdel = None,
> doc = cls._doc_state))
>
> obj = super(Base, cls).__new__(cls)
> return obj
>
> state = None # Set in __new__()
> _state = True
> _doc_state = "The state of this object"
> def _Get_state(self): return self._state
> def _Set_state(self, value): self._state = value
pep08 : attribute names (including methods) should be all_lower.
> class Child(Base):
> def _Get_state(self):
> # Do some work before getting the state.
> print "Getting the state using the child's method"
> return self._state
>
> print Child().state
How often do you really need to override a property ? (hint : as far as
I'm concerned, it never happened so far). Now you have two solutions :
either redefine the whole property in the derived class, or, if you
really intend your property to be overriden, provide a "template method"
hook.
I'd say you're making things much more complicated than they need to be.
In Python 2.6 and 3.0 you can override the setter, getter or deleter of
a property in a subclass. You may be able to find a pure Python
implementation written by Guido. My C implementation in the core works
almost the same.
Christian
To add to what others have already said, it is not only 'just extra work',
it is also quite dangerous. See:
class A(object):
children = []
Now *all* A instances share the *same* list, as it was defined as a class
attribute. If you ever forget to set it to something else in __init__,
you're in for big surprises.
What I'm doing is set all instance attributes right at the beginning of
the __init__ with a huge comment before them, like:
class A(object):
def __init__(self):
## INSTANCE ATTRIBUTES:
## --------------------
self.children = []
This way, you still can 'figure out what is in the class' quite quickly,
without the drawbacks of declaraing class attributes.
HTH
--
python -c "print ''.join([chr(154 - ord(c)) for c in
'U(17zX(%,5.zmz5(17l8(%,5.Z*(93-965$l7+-'])"
> To add to what others have already said, it is not only 'just extra
> work', it is also quite dangerous. See:
>
> class A(object):
> children = []
the OP is aware of that, of course:
> I set anything that is constant but anything variable is set again in
> __init__()
as long as if you're aware of the issues involved (which you should be
if you're using Python professionally), using class-level attributes is
a perfectly valid Python style.
</F>
Using class attributes is perfectly valid Python style, indeed. But in
this case - ie: using class attributes as a pseudo-declaration of
instance attributes -, I would not call this good style : it's a waste
of time, a violation of DRY, and a potential source of confusion for the
class's users / maintainers.
Thanks Bruno, and everyone ! These are exactly the type of hard
answers I was hoping for. I'm mostly converted but my brain still
needs a Pythonic push from time to time. Looks like have some some
clean up to perform...with confidence.
I'm interested to see the implementation of getter, etc overrides in
2.6/3.0. I have two classes that could be simplified with this. For
example, I have a class which does a lot of work and has about 5 key
properties. I want to inherit it, and just trigger an event (update
something only stored in the child) after 4 of these attributes are
finished being set. I was thinking about using a callback which is
empty in the parent or __setattr__() (but I hat using this unless I
have to, it is still troublesome to me).
- Rafe
IOW : a template method. Probably one of the most known, most evident
and most useful design pattern. But...
> or __setattr__() (but I hat using this unless I
> have to, it is still troublesome to me).
Don't use __setattr__ if you can avoid it. It *is* troublesome - and
costly too.
Now, remember that the property class is just an handy shortcut for the
most common use of computed attributes. The more generic mechanism
properties are built upon - the descriptor protocol - is nothing
complicated, so when you hit the limits of properties (or when
property-based code becomes too tangled/messy/whatever), you can write
your own custom descriptor objects.