Python Class Vs. Module Attributes
Solution 1:
#4:
I never use class attributes to initialize default instance attributes (the ones you normally put in __init__
). For example:
classObj(object):def__init__(self):
self.users = 0
and never:
classObj(object):
users =0
Why? Because it's inconsistent: it doesn't do what you want when you assign anything but an invariant object:
classObj(object):
users = []
causes the users list to be shared across all objects, which in this case isn't wanted. It's confusing to split these into class attributes and assignments in __init__
depending on their type, so I always put them all in __init__
, which I find clearer anyway.
As for the rest, I generally put class-specific values inside the class. This isn't so much because globals are "evil"--they're not so big a deal as in some languages, because they're still scoped to the module, unless the module itself is too big--but if external code wants to access them, it's handy to have all of the relevant values in one place. For example, in module.py:
classObj(object):
classException(Exception): pass
...
and then:
from module import Obj
try:
o = Obj()
o.go()
except o.Exception:
print"error"
Aside from allowing subclasses to change the value (which isn't always wanted anyway), it means I don't have to laboriously import exception names and a bunch of other stuff needed to use Obj. "from module import Obj, ObjException, ..." gets tiresome quickly.
Solution 2:
what is a good use case for class attributes
Case 0. Class methods are just class attributes. This is not just a technical similarity - you can access and modify class methods at runtime by assigning callables to them.
Case 1. A module can easily define several classes. It's reasonable to encapsulate everything about class A
into A...
and everything about class B
into B...
. For example,
# module xxxclassX:
MAX_THREADS = 100
...
# main programfrom xxx import X
if nthreads < X.MAX_THREADS: ...
Case 2. This class has lots of default attributes which can be modified in an instance. Here the ability to leave attribute to be a 'global default' is a feature, not bug.
classNiceDiff:
"""Formats time difference given in seconds into a form '15 minutes ago'."""
magic = .249
pattern = 'in {0}', 'right now', '{0} ago'
divisions = 1# there are more default attributes
One creates instance of NiceDiff to use the existing or slightly modified formatting, but a localizer to a different language subclasses the class to implement some functions in a fundamentally different way and redefine constants:
classРазница(NiceDiff): # NiceDiff localized to Russian'''Из разницы во времени, типа -300, делает конкретно '5 минут назад'.'''
pattern = 'через {0}', 'прям щас', '{0} назад'
Your cases:
- constants -- yes, I put them to class. It's strange to say
self.CONSTANT = ...
, so I don't see a big risk for clobbering them. - Default attribute -- mixed, as above may go to class, but may also go to
__init__
depending on the semantics. - Global data structure --- goes to class if used only by the class, but may also go to module, in either case must be very well-documented.
Solution 3:
Class attributes are often used to allow overriding defaults in subclasses. For example, BaseHTTPRequestHandler has class constants sys_version and server_version, the latter defaulting to "BaseHTTP/" + __version__
. SimpleHTTPRequestHandler overrides server_version to "SimpleHTTP/" + __version__
.
Solution 4:
Encapsulation is a good principle: when an attribute is inside the class it pertains to instead of being in the global scope, this gives additional information to people reading the code.
In your situations 1-4, I would thus avoid globals as much as I can, and prefer using class attributes, which allow one to benefit from encapsulation.
Post a Comment for "Python Class Vs. Module Attributes"