I want to access a class attribute by a string with its name.
Something like:
class a:
b=[]
c='b'
eval('a.'+c+'=1')
But that doesn't work in Python.
How can I do this?
Use setattr:
In [1]: class a:
...: b = []
...:
In [2]: setattr(a, 'b', 1)
In [3]: a.b
Out[3]: 1
Use getattr for the reverse:
In [4]: getattr(a, 'b')
Out[4]: 1
In [5]: getattr(a, 'x', 'default')
Out[5]: 'default'
I very much suspect, though, that there is a better way to achieve whatever your goal is. Have you tried using a dictionary instead of a class?
eval is for evaluation, use exec to 'execute' statements:
exec('a.'+c+'=1')
Yet, consider the risk of using both. And you can check out this answer for the difference between expressions and statements.
Since you are looking to set attribute by name, setattr explained in hop's answer is a better practice, and safer than using exec.
Related
Suppose I have a dataclass with a set method. How do I extend the repr method so that it also updates whenever the set method is called:
from dataclasses import dataclass
#dataclass
class State:
A: int = 1
B: int = 2
def set(self, var, val):
setattr(self, var, val)
Ex:
In [2]: x = State()
In [3]: x
Out[3]: State(A=1, B=2)
In [4]: x.set("C", 3)
In [5]: x
Out[5]: State(A=1, B=2)
In [6]: x.C
Out[6]: 3
The outcome I would like
In [7]: x
Out[7]: State(A=1, B=2, C=3)
The dataclass decorator lets you quickly and easily build classes that have specific fields that are predetermined when you define the class. The way you're intending to use your class, however, doesn't match up very well with what dataclasses are good for. You want to be able to dynamically add new fields after the class already exists, and have them work with various methods (like __init__, __repr__ and presumably __eq__). That removes almost all of the benefits of using dataclass. You should instead just write your own class that does what you want it to do.
Here's a quick and dirty version:
class State:
_defaults = {"A": 1, "B": 2}
def __init__(self, **kwargs):
self.__dict__.update(self._defaults)
self.__dict__.update(kwargs)
def __eq__(self, other):
return self.__dict__ == other.__dict__ # you might want to add some type checking here
def __repr__(self):
kws = [f"{key}={value!r}" for key, value in self.__dict__.items()]
return "{}({})".format(type(self).__name__, ", ".join(kws))
This is pretty similar to what you get from types.SimpleNamespace, so you might just be able to use that instead (it doesn't do default values though).
You could add your set method to this framework, though it seems to me like needless duplication of the builtin setattr function you're already using to implement it. If the caller needs to dynamically set an attribute, they can call setattr themselves. If the attribute name is constant, they can use normal attribute assignment syntax instead s.foo = "bar".
I would like to know how to convert a python object from a dictionary (using python3 btw). I realize that this question has been asked (and answered) already (here). However, in my case the object is given entirely in terms of #property values, for example:
class Test:
#property
def value(self):
return 1.0
Regarding conversion to a dictionary: The __dict__ dictionary of the Test class is empty, and consequently, the vars
function does not work as expected:
>>> vars(Test())
{}
Still, I can use gettattr(Test(), 'value'), to obtain 1.0, so
the value is present.
Note: The reason I am coming up with this apparently contrived example is that I am trying to convert a cython cdef class (containing parameters) to a dictionary. The recommended way to wrap c structures with properties using cython is indeed based on properties.
I think you could use dir:
a = Test()
dir(a)
Output:
['__doc__', '__module__', 'value']
So you could maybe do something like:
d = {}
for attr in dir(a):
if not attr.startswith("__"):
d[attr] = getattr(a, attr)
Output:
d = {'value': 1.0}
Maybe you could abuse that:
In [10]: type(Test().__class__.__dict__['value']) is property
Out[10]: True
So you check the class of the object and if it has attribute of type property.
Here is how I would do it:
t = Test()
dictionary = {attr_name: getattr(t, attr_name)
for attr_name, method in t.__class__.__dict__.items()
if isinstance(method, property)}
It is even worse that that. You could imagine to build an instance __dict__ at init time, but that would not solve anything, except for read_only constant properties. Because the value in the dict will be a copy of the property at the time it was taken, and will not reflect future changes.
In ruby it is idiomatic to write a function that may be called like this:
open_database(:readonly) // or
open_database(:readonly, :remote, :force)
In these cases the :readonly are "symbols" and are used as "flags" to modify the behavior of the open_database call.
We would implement this as follows in ruby:
def func(*params)
if params.include? :readonly
puts "readonly"
end
end
What is the idiomatic way to do this in Python?
There is no such syntactic sugar on Python.
The correct way to do this would be to use default keyword arguments:
def open_database(readonly=False, remote=False, force=False):
# ...
You can then:
open_database(readonly=True, force=True) # remote=False (default)
If you want to get as close as possible to ruby, you can do argument unpacking:
def specify_flags(*args):
return {x: True for x in args}
open_database(**specify_flags('readonly', 'force')) # Same as readonly=True, force=True
You can do this, which is almost exactly what you want:
In [1]: def open_database(**kwargs):
...: if 'readonly' in kwargs:
...: print 'Setting up read only'
...: if 'remote' in kwargs:
...: print 'Setting up remote'
...:
In [2]: open_database()
In [3]: open_database(remote=0)
Setting up remote
In [4]:
You just have to specify a value for the keyword argument. Note that this could actually come in handy later, but is not pretty if you really don't need it.
im calling them keyed arrays because if i knew what they were called i could find the answer myself =-)
ok, for example:
parser = OptionParser(conflict_handler="resolve")
parser.add_option("-x", dest="var_x", help="")
parser.add_option("-y", dest="var_y", help="")
(options, args) = parser.parse_args()
generates an option object that can be used like this:
foobar = options.var_x
what are these called and where would i find some documentation on how to create and use them?
One class that does something very similar is namedtuple:
In [1]: from collections import namedtuple
In [2]: Point = namedtuple('Point', ['x', 'y'])
In [4]: p = Point(1, 2)
In [5]: p.x
Out[5]: 1
In [6]: p.y
Out[6]: 2
One poss is to wrap a dictionary in an object see below for class definition:
class Struct:
def __init__(self, **entries):
self.__dict__.update(entries)
Then just use a dictionary in constructor like so:
adictionary = {'dest':'ination', 'bla':2}
options = Struct(**adictionary)
options.dest
options.bla
options.dest will return 'ination'
options.bla would return 2
If you do help(options) at the interactive terminal, you'll see this is an optparse.Values instance. It's not intended for making your own things, really.
Using attribute access for key–value pairs is usually silly. Much of the time people who insist on it should really just be using a dict.
The main built-in way to do something along these lines is collections.namedtuple.
I was looking for a way to dynamically add static methods to a python class.
My attempt was as following:
class C(object):
a = None
k = 2
C.a = lambda x: k*x
print C.a(2)
Unfortunately, I get an error saying that C instance is required as the first argument to a. Effectively, python thinks that a is an instance method of class C and not a class method.
What are the reasons for this? How can I overcome the problem?
Use staticmethod:
>>> C.a = staticmethod(lambda x: k*x)
>>> print C.a(2)
4