Python 类与模块属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1250779/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python Class vs. Module Attributes
提问by cmcginty
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?
我有兴趣听到一些关于 Python 中类属性的讨论。例如,类属性的良好用例是什么?在大多数情况下,我无法想出类属性比使用模块级属性更可取的情况。如果这是真的,那么为什么要让他们在身边?
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:
请随意评论您将如何处理以下情况:
- 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.
- Default class attribute, that in rare occasions updated for a special instance of the class.
- Global data structure used to represent an internal state of a class shared between all instances.
- A class that initializes a number of default attributes, not influenced by constructor arguments.
- 类和/或子类使用的常量值。这可能包括永远不会改变但可能需要一次性初始化的“幻数”字典键或列表索引。
- 默认类属性,在极少数情况下为类的特殊实例更新。
- 用于表示在所有实例之间共享的类的内部状态的全局数据结构。
- 初始化许多默认属性的类,不受构造函数参数的影响。
Some Related Posts:
Difference Between Class and Instance Attributes
一些相关帖子:
类和实例属性之间的区别
采纳答案by Glenn Maynard
#4:
I neveruse class attributes to initialize default instance attributes (the ones you normally put in __init__
). For example:
#4:我从不使用类属性来初始化默认实例属性(您通常放入的那些__init__
)。例如:
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.
导致用户列表在所有对象之间共享,在这种情况下是不需要的。__init__
根据它们的类型将它们分成类属性和分配是令人困惑的,所以我总是把它们都放在 中__init__
,无论如何我觉得这更清楚。
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:
至于其余的,我通常将特定于类的值放在类中。这并不是因为全局变量是“邪恶的”——它们不像在某些语言中那么重要,因为它们仍然限定在模块范围内,除非模块本身太大——但是如果外部代码想要访问它们,将所有相关值放在一个地方很方便。例如,在 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.
除了允许子类更改值(无论如何这并不总是需要的),这意味着我不必费力地导入异常名称和使用 Obj 所需的一堆其他东西。“from module import Obj, ObjException, ...” 很快就让人厌烦了。
回答by ilya n.
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.
案例 0.类方法只是类属性。这不仅仅是技术上的相似性——您可以在运行时通过将可调用对象分配给它们来访问和修改类方法。
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,
案例 1.一个模块可以轻松定义多个类。将所有 about class A
intoA...
和所有 about class B
into封装起来是合理的B...
。例如,
# 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.
案例 2.这个类有很多可以在实例中修改的默认属性。这里将属性保留为“全局默认值”的能力是一项功能,而不是错误。
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 andredefine constants:
可以创建 NiceDiff 的实例以使用现有的或稍微修改的格式,但是不同语言的本地化器将类子类化,以完全不同的方式实现一些功能并重新定义常量:
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 onlyby the class, but may also go to module, in either case must be verywell-documented.
- 常量——是的,我把它们放在课堂上。说起来很奇怪
self.CONSTANT = ...
,所以我不认为破坏他们有很大的风险。 - 默认属性 -- 混合,如上所示可能会转到类,但也可能会转到
__init__
取决于语义。 - 如果使用全局数据结构---去上课只能由类,也可以去模块,在任何情况下必须是非常良好的记录。
回答by Martin v. L?wis
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__
.
类属性通常用于允许覆盖子类中的默认值。例如,BaseHTTPRequestHandler 有类常量 sys_version 和 server_version,后者默认为"BaseHTTP/" + __version__
。SimpleHTTPRequestHandler 将 server_version 覆盖为"SimpleHTTP/" + __version__
.
回答by Eric O Lebigot
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.
在您的情况 1-4 中,因此我会尽可能避免使用全局变量,并且更喜欢使用类属性,这样可以从封装中受益。