如果只有一个实例,我应该使用实例属性还是类属性?

发布于 2024-08-30 06:54:23 字数 1695 浏览 3 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

奢华的一滴泪 2024-09-06 06:54:23

无论如何,如果您只有一个实例,最好为每个实例创建所有变量,因为它们的访问速度会更快(一点点)(由于从类到实例的“继承”,“查找”级别少了一层),与这个小小的优势相比,没有任何缺点。

If you have only one instance anyway, it's best to make all variables per-instance, simply because they will be accessed (a little bit) faster (one less level of "lookup" due to the "inheritance" from class to instance), and there are no downsides to weigh against this small advantage.

蓝眸 2024-09-06 06:54:23

进一步呼应迈克的Alex 的 建议并添加我自己的颜色...

使用实例属性是典型的...更惯用的 Python。类属性不常用,因为它们的用例是特定的。对于静态方法和类方法与“普通”方法来说也是如此。它们是解决特定用例的特殊构造,否则它是由异常程序员创建的代码,想要炫耀他们了解 Python 编程的一些不起眼的角落。

亚历克斯在他的回复中提到,由于查找级别较低,访问速度会(稍微)快一些……让我为那些还不知道这是如何工作的人进一步澄清。它与变量访问非常相似 - 其搜索顺序为:

  1. 局部变量
  2. 局部变量全局变量
  3. 内置变量

对于属性访问,顺序为:

  1. 实例
  2. 基类 由 MRO(方法解析顺序)

这两种技术都以“由内而外”的方式工作,这意味着首先检查最本地的对象,然后检查外层相继检查。

在上面的示例中,假设您正在查找 path 属性。当遇到像“self.path”这样的引用时,Python 将首先查看实例属性是否匹配。当失败时,它会检查实例化对象的类。最后,它将搜索基类。正如 Alex 所说,如果在实例中找到您的属性,则不需要在其他地方查找,因此可以节省一点时间。

但是,如果您坚持使用类属性,则需要额外的查找。 或者,您的另一种选择是通过类而不是实例引用对象,例如,MyController.path 而不是 self.path 。这是一个直接查找,它将绕过延迟查找,但正如 alex 在下面提到的,它是一个全局变量,所以你会丢失你认为要保存的那部分(除非你创建对 [global] 类名的本地引用)。

最重要的是,大多数时候您应该使用实例属性。然而,有时类属性是完成这项工作的正确工具。同时使用两者的代码需要最勤奋的努力,因为使用 self 只会让您获得实例属性对象和对同名类属性的影子访问。在这种情况下,您必须通过类名访问属性才能引用它。

Further echoing Mike's and Alex's advice and adding my own color...

Using instance attributes are the typical... the more idiomatic Python. Class attributes are not used used as much, since their use cases are specific. The same is true for static and class methods vs. "normal" methods. They're special constructs addressing specific use cases, else it's code created by an aberrant programmer wanting to show off they know some obscure corner of Python programming.

Alex mentions in his reply that access will be (a little bit) faster due to one less level of lookup... let me further clarify for those who don't know about how this works yet. It is very similar to variable access -- the search order of which is:

  1. locals
  2. nonlocals
  3. globals
  4. built-ins

For attribute access, the order is:

  1. instance
  2. class
  3. base classes as determined by the MRO (method resolution order)

Both techniques work in an "inside-out" manner, meaning the most local objects are checked first, then outer layers are checked in succession.

In your example above, let's say you're looking up the path attribute. When it encounters a reference like "self.path", Python will look at the instance attributes first for a match. When that fails, it checks the class from which the object was instantiated from. Finally, it will search the base classes. As Alex stated, if your attribute is found in the instance, it doesn't need to look elsewhere, hence your little bit of time savings.

However, if you insist on class attributes, you need that extra lookup. Or, your other alternative is to refer to the object via the class instead of the instance, e.g., MyController.path instead of self.path. That's a direct lookup which will get around the deferred lookup, but as alex mentions below, it's a global variable, so you lose that bit that you thought you were going to save (unless you create a local reference to the [global] class name).

The bottom-line is that you should use instance attributes most of the time. However, there will be occasions where a class attribute is the right tool for the job. Code using both at the same time will require the most diligence, because using self will only get you the instance attribute object and shadows access to the class attribute of the same name. In this case, you must use access the attribute by the class name in order to reference it.

北笙凉宸 2024-09-06 06:54:23

如有疑问,您可能需要一个实例属性。

类属性最好保留在有意义的特殊情况下。唯一非常常见的用例是方法。将类属性用于实例需要知道的只读常量的情况并不少见(尽管这样做的唯一好处是如果您还想从类外部进行访问) ),但在其中存储任何状态时您当然应该谨慎,这很少是您想要的。即使您只有一个实例,您也应该像编写其他类一样编写该类,这通常意味着使用实例属性。

When in doubt, you probably want an instance attribute.

Class attributes are best reserved for special cases where they make sense. The only very-common use case is methods. It isn't uncommon to use class attributes for read-only constants that instances need to know (though the only benefit to this is if you also want access from outside the class), but you should certainly be cautious about storing any state in them, which is seldom what you want. Even if you will only have one instance, you should write the class like you would any other, which usually means using instance attributes.

尴尬癌患者 2024-09-06 06:54:23

同样的问题 Performance of accessing class variables in Python - 代码这里改编自@Edward Loper

局部变量是访问速度最快的,几乎与模块变量紧密相关,其次是类变量,然后是实例变量。

您可以从 4 个范围访问变量:

  1. 实例变量 (self.varname)
  2. 类变量 (Classname.varname)
  3. 模块变量 (VARNAME)
  4. 局部变量 (varname)

测试:

import timeit

setup='''
XGLOBAL= 5
class A:
    xclass = 5
    def __init__(self):
        self.xinstance = 5
    def f1(self):
        xlocal = 5
        x = self.xinstance
    def f2(self):
        xlocal = 5
        x = A.xclass
    def f3(self):
        xlocal = 5
        x = XGLOBAL
    def f4(self):
        xlocal = 5
        x = xlocal
a = A()
'''
print('access via instance variable: %.3f' % timeit.timeit('a.f1()', setup=setup, number=300000000) )
print('access via class variable: %.3f' % timeit.timeit('a.f2()', setup=setup, number=300000000) )
print('access via module variable: %.3f' % timeit.timeit('a.f3()', setup=setup, number=300000000) )
print('access via local variable: %.3f' % timeit.timeit('a.f4()', setup=setup, number=300000000) )

结果:

access via instance variable: 93.456
access via class variable: 82.169
access via module variable: 72.634
access via local variable: 72.199

Same question at Performance of accessing class variables in Python - the code here adapted from @Edward Loper

Local Variables are the fastest to access, pretty much tied with Module Variables, followed by Class Variables, followed by Instance Variables.

There are 4 scopes you can access variables from:

  1. Instance Variables (self.varname)
  2. Class Variables (Classname.varname)
  3. Module Variables (VARNAME)
  4. Local Variables (varname)

The test:

import timeit

setup='''
XGLOBAL= 5
class A:
    xclass = 5
    def __init__(self):
        self.xinstance = 5
    def f1(self):
        xlocal = 5
        x = self.xinstance
    def f2(self):
        xlocal = 5
        x = A.xclass
    def f3(self):
        xlocal = 5
        x = XGLOBAL
    def f4(self):
        xlocal = 5
        x = xlocal
a = A()
'''
print('access via instance variable: %.3f' % timeit.timeit('a.f1()', setup=setup, number=300000000) )
print('access via class variable: %.3f' % timeit.timeit('a.f2()', setup=setup, number=300000000) )
print('access via module variable: %.3f' % timeit.timeit('a.f3()', setup=setup, number=300000000) )
print('access via local variable: %.3f' % timeit.timeit('a.f4()', setup=setup, number=300000000) )

The result:

access via instance variable: 93.456
access via class variable: 82.169
access via module variable: 72.634
access via local variable: 72.199
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文