How do I use a keyword as a variable name?
Solution 1
As mentioned in the comments, from
is a Python keyword so you can't use it as a variable name, or an attribute name. So you need to use an alternative name, and do a conversion when reading or writing the JSON data.
To do the output conversion you can supply a new encoder for json.dumps
; you can do that by overriding the ExchangeRates.json
method. To do the input conversion, override ExchangeRates.from_json
.
The strategy is similar in both cases: we create a copy of the dictionary (so we don't mutate the original), then we create a new key with the desired name and value, then delete the old key.
Here's a quick demo, tested on Python 2.6 and 3.6:
import json
class PropertyEquality(object):
def __eq__(self, other):
return (isinstance(other, self.__class__) and self.__dict__ == other.__dict__)
def __ne__(self, other):
return not self.__eq__(other)
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, ', '.join(['%s=%s' % (k, v) for (k, v) in self.__dict__.items()]))
class JsonAware(PropertyEquality):
def json(self):
return json.dumps(self, cls=GenericEncoder)
@classmethod
def from_json(cls, json):
return cls(**json)
class ExchangeRatesEncoder(json.JSONEncoder):
def default(self, obj):
d = obj.__dict__.copy()
d['from'] = d['frm']
del d['frm']
return d
class ExchangeRates(JsonAware):
def __init__(self, frm, to, rate):
self.frm = frm
self.to = to
self.rate = rate
def json(self):
return json.dumps(self, cls=ExchangeRatesEncoder)
@classmethod
def from_json(cls, json):
d = json.copy()
d['frm'] = d['from']
del d['from']
return cls(**d)
# Test
a = ExchangeRates('a', 'b', 1.23)
print(a.json())
jdict = {"from": "z", "to": "y", "rate": 4.56, }
b = ExchangeRates.from_json(jdict)
print(b.json())
typical output
{"from": "a", "to": "b", "rate": 1.23}
{"from": "z", "to": "y", "rate": 4.56}
Solution 2
Add a single underscore to your preferred names: from_ and to_
(see PEP 8)
class ExchangeRates(JsonAware):
def __init__(self, from_, to_, rate):
self.from = from_
self.to = to_
self.rate = rate
Solution 3
Use a synonym. Try "origin" or "source" instead.
Related videos on Youtube
user4659009
Updated on October 21, 2022Comments
-
user4659009 over 1 year
I have the following class with the variables
from
,to
andrate
.from
is a keyword. If I want to use it in the init method below, what's the correct way to write it?More context: The class needs the
from
variable explicitly as it's part of a json required by a POST endpoint written up by another developer in a different language. So changing the variable name is out of the question.class ExchangeRates(JsonAware): def __init__(self, from, to, rate): self.from = from self.to = to self.rate = rate
JsonAware code:
class PropertyEquality(object): def __eq__(self, other): return (isinstance(other, self.__class__) and self.__dict__ == other.__dict__) def __ne__(self, other): return not self.__eq__(other) def __repr__(self): return '%s(%s)' % (self.__class__.__name__, ', '.join(['%s=%s' % (k, v) for (k, v) in self.__dict__.items()])) class JsonAware(PropertyEquality): def json(self): return json.dumps(self, cls=GenericEncoder) @classmethod def from_json(cls, json): return cls(**json)
GenericEncoder code:
class GenericEncoder(json.JSONEncoder): def default(self, obj): return obj.__dict__
-
jonrsharpe about 8 yearsYou can't use it as an identifier, because it's a keyword. That's what keyword means! Use e.g.
from_
instead. -
jonrsharpe about 8 yearsYou could do it that way if you like:
setattr(self, 'from', kwargs.get('from'))
, but then you have to pass it in via a dictionary too:rates = ExchangeRates(..., **{'from': whatever})
and can only access it viagetattr(rates, 'from')
. It's much less awkward to rename it. See e.g. stackoverflow.com/q/9746838/3001761 -
Dilettant about 8 yearsflagged in red sounds like an IDE trying to assist the author ;-) I would follow @jonrsharpe's advice.
-
jonrsharpe about 8 yearsYou could expand the question with that context and a minimal reproducible example (what's
JsonAware
?), there are probably ways to handle parsing to and from JSON where the keys are keywords. But you definitely can't do it directly.
-
-
Eduardo Pignatelli about 3 yearsOther languages, such as C#, work around this using the
@
symbol, e.g.@string
. It would be nice to have that in python, e.g.@lambda
. -
PM 2Ring about 3 years
-
Eduardo Pignatelli about 3 yearsThe
@
symbol is arbitrary, it can really be anything. The problem I find with the underscore is that it actually modifies the name of the variable (i.e. it will end with the underscore).