Python 类与模块属性

2022-01-13 00:00:00 python module attributes class-design

问题描述

我有兴趣听到一些关于 Python 中的类属性的讨论.例如,什么是类属性的好用例?在大多数情况下,我想不出一个类属性比使用模块级属性更可取的情况.如果这是真的,那为什么还有他们呢?

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. 类和/或子类使用的常量值.这可能包括永远不会改变但可能需要一次性初始化的幻数"字典键或列表索引.
  2. 默认类属性,在极少数情况下为类的特殊实例更新.
  3. 用于表示在所有实例之间共享的类的内部状态的全局数据结构.
  4. 初始化许多默认属性的类,不受构造函数参数的影响.

一些相关帖子:
类和实例属性的区别


解决方案

#4:我从不使用类属性来初始化默认实例属性(通常放在 __init__ 中的那些).例如:

#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

永远不会:

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 = []

使用户列表在所有对象之间共享,在这种情况下,这是不希望的.根据它们的类型将它们拆分为 __init__ 中的类属性和赋值会令人困惑,因此我总是将它们全部放在 __init__ 中,反正我觉得这样更清楚.

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.

至于其余部分,我通常将特定于类的值放在类中.这并不是因为全局变量是邪恶的"——它们不像在某些语言中那么重要,因为它们仍然局限于模块,除非模块本身太大——但是如果外部代码想要访问它们,将所有相关值放在一个地方很方便.比如在module.py中:

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

然后:

from module import Obj

try:
    o = Obj()
    o.go()
except o.Exception:
    print "error"

除了允许子类更改值(这并不总是需要)之外,这意味着我不必费力地导入异常名称和使用 Obj 所需的一堆其他东西."from module import Obj, ObjException, ..." 很快就会让人厌烦.

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.

相关文章