Python Class vs. Module Attributes

為{幸葍}努か 提交于 2020-01-20 19:17:50

问题


I'm interested in hearing some discussion about class attributes in Python. For example, what is a good use case for class attributes? For the most part, I can not come up with a case where a class attribute is preferable to using a module level attribute. If this is true, then why have them around?

The problem I have with them, is that it is almost too easy to clobber a class attribute value by mistake, and then your "global" value has turned into a local instance attribute.

Feel free to comment on how you would handle the following situations:

  1. Constant values used by a class and/or sub-classes. This may include "magic number" dictionary keys or list indexes that will never change, but possible need one-time initialization.
  2. Default class attribute, that in rare occasions updated for a special instance of the class.
  3. Global data structure used to represent an internal state of a class shared between all instances.
  4. A class that initializes a number of default attributes, not influenced by constructor arguments.

Some Related Posts:
Difference Between Class and Instance Attributes


回答1:


#4: I never use class attributes to initialize default instance attributes (the ones you normally put in __init__). For example:

class Obj(object):
    def __init__(self):
        self.users = 0

and never:

class Obj(object):
    users = 0

Why? Because it's inconsistent: it doesn't do what you want when you assign anything but an invariant object:

class Obj(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:

class Obj(object):
    class Exception(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.




回答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 xxx
class X:
    MAX_THREADS = 100
    ...

# main program
from 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.

class NiceDiff:
    """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.



回答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__.




回答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.



来源:https://stackoverflow.com/questions/1250779/python-class-vs-module-attributes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!