Je veux définir un ensemble de constantes dans une classe comme:
class Foo(object):
(NONEXISTING,VAGUE,CONFIRMED) = (0,1,2)
def __init__(self):
self.status = VAGUE
Cependant, je reçois
NameError: global name 'VAGUE' is not defined
Existe-t-il un moyen de définir ces constantes pour qu'elles soient visibles à l'intérieur de la classe sans recourir à global
ou self.NONEXISTING = 0
etc.?
Lorsque vous attribuez des noms dans le corps de la classe, vous créez des attributs de la classe. Vous ne pouvez pas vous y référer sans vous référer directement ou indirectement à la classe. Vous pouvez utiliser Foo.VAGUE
comme le disent les autres réponses, ou vous pouvez utiliser self.VAGUE
. Vous n'avez pas à assigner aux attributs de self
.
Habituellement, en utilisant self.VAGUE
est ce que vous voulez car il permet aux sous-classes de redéfinir l'attribut sans avoir à réimplémenter toutes les méthodes qui les utilisent - pas que cela semble être une chose sensée à faire dans cet exemple particulier, mais qui sait.
essayez au lieu de:
self.status = VAGUE
celui-là:
self.status = Foo.VAGUE
vous DEVEZ spécifier la classe
En Python3, vous pouvez également référencer VAGUE
comme:
type(self).VAGUE
De cette façon, vous le faites clairement référence en tant qu'attribut de classe et non en tant qu'attribut d'objet, mais cette manière est robuste contre un changement de nom de la classe. De plus, si vous remplacez VAGUE
dans une sous-classe, la valeur de la sous-classe sera utilisée, comme si vous deviez utiliser self.VAGUE
.
Notez que cette méthode ne semble pas fonctionner en Python2, du moins pas dans mes tests, où type(self)
a renvoyé instance
au lieu de la classe que j'ai instanciée. Par conséquent, la réponse de Thomas Wouters est probablement préférable, compte tenu de l'étendue de Python2.
La seule façon est d'y accéder via le nom de classe tel que
Foo.VAGUE
Si vous accédez uniquement à VAGUE dans le __init__
fonction, ou une fonction, il faut la déclarer à l'intérieur pour y accéder comme vous le souhaitez.
Utiliser self est également pour l'instance de la classe.
Celui-ci n'est PAS RECOMMANDÉ POUR TOUT CODE par aucun moyen, mais un hack laid comme ci-dessous peut être fait. J'ai fait cela juste pour avoir une meilleure compréhension de Python AST API, donc toute personne qui l'utilise dans du code réel devrait être abattue avant de faire du mal: -)
#!/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()