在python类中定义常量,真的需要self吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3995546/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 13:45:52  来源:igfitidea点击:

Defining constants in python class, is self really needed?

pythonconstantsvisibility

提问by Theodor

I want to define a set of constants in a class like:

我想在类中定义一组常量,例如:

class Foo(object):
   (NONEXISTING,VAGUE,CONFIRMED) = (0,1,2)
   def __init__(self):
       self.status = VAGUE

However, I get

但是,我得到

NameError: global name 'VAGUE' is not defined

Is there a way of defining these constants to be visiable inside the class without resorting to globalor self.NONEXISTING = 0etc.?

有没有定义这些常量是类中visiable而不诉诸的方式globalself.NONEXISTING = 0等?

采纳答案by Thomas Wouters

When you assign to names in the class body, you're creating attributes of the class. You can't refer to them without referring to the class either directly or indirectly. You can use Foo.VAGUEas the other answers say, or you can use self.VAGUE. You do not have to assignto attributes of self.

当您在类主体中分配名称时,您正在创建类的属性。你不能在不直接或间接引用类的情况下引用它们。您可以Foo.VAGUE像其他答案所说的那样使用,也可以使用self.VAGUE. 您不必分配给 的属性self

Usually, using self.VAGUEis what you want because it allows subclasses to redefine the attribute without having to reimplement all the methods that use them -- not that that seems like a sensible thing to do in this particular example, but who knows.

通常, usingself.VAGUE是您想要的,因为它允许子类重新定义属性,而不必重新实现使用它们的所有方法——在这个特定示例中这似乎不是一件明智的事情,但谁知道呢。

回答by Matus

try instead of:

尝试代替:

self.status = VAGUE

this one:

这个:

self.status = Foo.VAGUE

you MUST specify the class

你必须指定类

回答by Iacks

The only way is to access it through the class name such as

唯一的方法是通过类名访问它,例如

Foo.VAGUE

If accessing just VAGUE inside the __init__function, or a function, it must be declared inside that to access it the way you want.

如果仅访问__init__函数或函数内部的 VAGUE ,则必须在其中声明它才能以您想要的方式访问它。

Using self is for the instance of the class also.

使用 self 也适用于类的实例。

回答by Taisuke Yamada

This one is NOT RECOMMENDED FOR ANY CODE by any means, but an ugly hack like below can be done. I did this just to have better understanding of Python AST API, so anyone who uses this in real-world code should be shot before it does any harm :-)

无论如何,不​​推荐任何代码使用此方法,但可以完成如下丑陋的 hack。我这样做只是为了更好地理解 Python AST API,所以任何在实际代码中使用它的人都应该在它造成任何伤害之前被枪杀:-)

#!/usr/bin/python
# -*- coding: utf-8-unix -*-
#
# AST hack to replace symbol reference in instance methods,
# so it will be resolved as a reference to class variables.
#

import inspect, types, ast

def trim(src):
    lines = src.split("\n")
    start = lines[0].lstrip()
    n = lines[0].index(start)
    src = "\n".join([line[n:] for line in lines])
    return src

#
# Method decorator that replaces symbol reference in a method
# so it will use symbols in belonging class instead of the one
# in global namespace.
#
def nsinclude(*args):
    # usecase: @nsinclude()
    # use classname in calling frame as a fallback
    stack = inspect.stack()
    opts  = [stack[1][3]]

    def wrap(func):
        if func.func_name == "tempfunc":
            return func

        def invoke(*args, **kw):
            base = eval(opts[0])

            src = trim(inspect.getsource(func))
            basenode = ast.parse(src)

            class hackfunc(ast.NodeTransformer):
                def visit_Name(self, node):
                    try:
                        # if base class (set in @nsinclude) can resolve
                        # given name, modify AST node to use that instead
                        val = getattr(base, node.id)

                        newnode = ast.parse("%s.%s" % (opts[0], node.id))
                        newnode = next(ast.iter_child_nodes(newnode))
                        newnode = next(ast.iter_child_nodes(newnode))
                        ast.copy_location(newnode, node)
                        return ast.fix_missing_locations(newnode)
                    except:
                        return node

            class hackcode(ast.NodeVisitor):
                def visit_FunctionDef(self, node):
                    if func.func_name != "tempfunc":
                        node.name = "tempfunc"
                        hackfunc().visit(node)

            hackcode().visit(basenode)

            newmod = compile(basenode, '<ast>', 'exec')
            eval(newmod)
            newfunc = eval("tempfunc")
            newfunc(*args, **kw)
        return invoke


    # usecase: @nsinclude
    if args and isinstance(args[0], types.FunctionType):
        return wrap(args[0])

    # usecase: @nsinclude("someclass")
    if args and args[0]:
        opts[0] = args[0]
    return wrap

class Bar:
    FOO = 987
    BAR = 876

class Foo:
    FOO = 123
    BAR = 234

    # import from belonging class
    @nsinclude
    def dump1(self, *args):
        print("dump1: FOO = " + str(FOO))


    # import from specified class (Bar)
    @nsinclude("Bar")
    def dump2(self, *args):
        print("dump2: BAR = " + str(BAR))

Foo().dump1()
Foo().dump2()

回答by Zeust the Unoobian

In Python3, you can also reference VAGUEas:

在 Python3 中,您还可以引用VAGUE为:

type(self).VAGUE

This way, you are clearly referencing it as a class attribute and not an object attribute, yet this way is robust against a name change of the class. Also if you override VAGUEin a subclass, the value from the subclass will be used, just like if you were to use self.VAGUE.

通过这种方式,您显然是将其作为类属性而不是对象属性来引用,但这种方式对于类的名称更改是健壮的。此外,如果您VAGUE在子类中进行覆盖,则将使用来自子类的值,就像您要使用self.VAGUE.

Note that this method does not appear to work in Python2, at least not in my tests, where type(self)returned instanceinstead of the class I instantiated. Therefore Thomas Wouters's answer is probably preferable, considering how widespread Python2 still is.

请注意,此方法在 Python2 中似乎不起作用,至少在我的测试中不起作用,type(self)返回的instance不是我实例化的类。因此,考虑到 Python2 的普及程度,Thomas Wouters 的回答可能更可取。