Python类与模块属性

2024-06-07 13:09:54 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我遇到的问题是,错误地删除一个类属性值几乎太容易了,然后您的“全局”值就变成了一个本地实例属性。

请随意评论您将如何处理以下情况:

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

一些相关帖子:
Difference Between Class and Instance Attributes


Tags: 模块实例字典属性错误评论情况用例
3条回答

类属性通常用于允许重写子类中的默认值。例如,BaseHTTPRequestHandler具有类常量sys_version和server_version,后者默认为"BaseHTTP/" + __version__。simplehttpprequesthandler将服务器版本重写为"SimpleHTTP/" + __version__

what is a good use case for class attributes

案例0。类方法只是类属性。这不仅仅是一个技术上的相似性——您可以在运行时通过为类方法分配可调用项来访问和修改它们。

案例1。一个模块可以很容易地定义几个类。把关于class A的所有内容封装到A...中,把关于class B的所有内容封装到B...中是合理的。例如

# module xxx
class X:
    MAX_THREADS = 100
    ...

# main program
from xxx import X

if nthreads < X.MAX_THREADS: ...

案例2。这个类有很多默认属性,可以在实例中修改。在这里,将属性保留为“全局默认值”是一个特性,而不是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

一个创建NiceDiff实例以使用现有的或稍加修改的格式,但一个指向不同语言的本地化程序将该类子类化,以一种根本不同的方式实现某些函数重新定义常量:

class Разница(NiceDiff): # NiceDiff localized to Russian
    '''Из разницы во времени, типа -300, делает конкретно '5 минут назад'.'''

    pattern = 'через {0}', 'прям щас', '{0} назад'

您的案例:

  • 常量——是的,我把它们放到了课堂上。说self.CONSTANT = ...很奇怪,所以我看不出击倒他们的大风险。
  • 默认属性——mixed,如上所述,可以转到类,但也可以转到__init__,具体取决于语义。
  • 全局数据结构---如果类仅使用则转到类,但也可以转到模块,在任何情况下都必须非常有文档记录。

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

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

从不:

class Obj(object):
    users = 0

为什么?因为它是不一致的:当你分配一个不变的对象时,它不会做你想做的事情:

class Obj(object):
    users = []

导致用户列表在所有对象之间共享,在本例中这是不需要的。在__init__中根据它们的类型将它们分为类属性和赋值是很混乱的,所以我总是将它们都放在__init__中,不管怎样,我发现它们更清晰。


至于其余的部分,我通常会将特定于类的值放在类中。这并不是因为globals是“邪恶的”——它们不像某些语言那样重要,因为它们的作用域仍然是模块,除非模块本身太大——但是如果外部代码想要访问它们,那么将所有相关值放在一个位置就很方便了。例如,在module.py中:

class Obj(object):
    class Exception(Exception): pass
    ...

然后:

from module import Obj

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

除了允许子类更改值(这并不总是需要的),这意味着我不必费力地导入异常名称和使用Obj所需的一堆其他东西。”从模块导入Obj,ObjException,…“很快变得烦人。

相关问题 更多 >

    热门问题