how to pass the name of a variable as a variable - python

How can I set the variable I want to change as a function argument? I want to define only one function, and not set_a(value), set_b(value), set_c(value), ...
class MyVarClass:
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
# this works, but I don't want to write n functions
def set_a(myvar_object, value):
myvar_object.a = value
# this is what I actually want:
def set_vars(myvar_object, var_name, value):
myvar_object.var_name = value
myvar = MyVarClass()
# I want to do the same as myvar.a = 4
set_a(myvar, 4) # works as intended, now myvar.a is 4
set_vars(myvar, a, 4) # error, a is not defined

What you usually do is to create a method to the class like this:
class MyVarClass:
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def set_a(self, value):
self.a = value
If, for some reason, can't do it like this and you only have the name of the attribute as string, then you can use setattr:
setattr(myvar_object, 'a', value)
But usually what you do is just this line:
myvar_object.a = 4

This is done with setattr.
def set_vars(myvar_object, var_name, value):
setattr(myvar_object, var_name, value)
This isn't necessarily the best way of doing this. It often suggests a different data structure would be better, but in case that isn't the case here.
You'll note if you go this route, there isn't much reason to have a def rather than just call setattr directly, unless you think you'll change things in the future.

what about using a dict:
class MyVarClass:
def __init__(self):
self.vars = {"a": 1, "b": 2, "c": 3}
def set_vars(myvar_object, var_name, value):
myvar_object.vars[var_name] = value

**
var_name = ''
class MyVarClass:
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
# this is what I actually want:
def set_vars(myvar, var_name, value):
myvar.var_name = value
print (myvar.var_name)
myvar = MyVarClass()
set_vars(myvar, "b", 6)
**

Related

How to find an attribute in self.__init__?

class C:
def __init__(self):
self.a = 1
self.b = 2
def __setattr__(self,name,value):
if a in self.__init__: #Determine if a is an instance of __init__ function
do something
The above code will return an error and says
if name in self.__init__:
TypeError: argument of type 'method' is not iterable
If I don't iterate through self.__init__ function, how else am I supposed to know what attributes are defined in self.__init__ function?
If an attribute is set in init, I want to set the name prefixed by "somestring_" and append it to self__dict__: e.g., if I print self.__dict__ after self.__setattr__, it will print {'somestring_a': 1, 'somestring_b': 2}
Add an attribute that lists the attributes that are set in __init__, and use that.
class C:
predefined = ['a', 'b']
def __init__(self):
self.a = 1
self.b = 2
def __setattr__(self,name,value):
if name in self.predefined:
do something
else:
do something else
Another option would be to copy the keys of self.__dict__ at the end of the __init__ method:
class C:
def __init__(self):
self.a = 1
self.b = 2
self.predefined = set(self.__dict__)
def __setattr__(self,name,value):
if name in self.predefined:
do something
else:
do something else
class C():
def __init__(self, a, b):
self.a = a
self.b = b
a = C(1, 2)
print(a.__dict__)
>>> {'a': 1, 'b': 2}
So __dict__.keys() will give you the list of attributes ...
BUT :::
if you will check the list of your attributes in __setattr__ , you have to keep in mind that this function is also called when you do a = C(1, 2) so you shouldn't check your attributes in this level of code.

Python shorthand for a tuple of a set of class attributes

Say i am using a class from some python package that looks like the following
class foo(object):
def __init__(self):
self.a = None
self.b = None
self.c = None
self.d = None
self.e = None
self.f = None
Now I need to use attributes b, d, and e of object foobar of class foo in some operation, say call a function qux for instance:
print qux(foobar.b, foobar.d, foobar.e)
Is there any way to create a shorthand version of this, something like the following imagined code:
print qux(*foobar.[b,d,e])
Note the constraints: neither the class nor the function can be changed.
Well, getattr and setattr get you close:
Assignment with setattr (not needed for the next to work, just here for illustration):
class foo(object):
def __init__(self):
for name in 'abcdef':
setattr(self, name, None)
Using values with getattr:
print qux(*(getattr(foobar, name) for name in 'bde'))
With normal, longer names you'd need to do in ['foo', 'bar'] instead.
Since you can't modify the class, how about a function that takes an instance and any number of attribute names, and returns a tuple:
class Foo(object):
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def getitems(obj, *items):
values = []
for item in items:
values.append(getattr(obj, item))
return tuple(values)
f = Foo()
print getitems(f, 'a', 'c') # prints (1, 3)
qux(*getitems(f, 'a', 'c'))
If you are willing to modify the class, you can override __getitem__ to accept a tuple of keys.
class Foo(object):
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def __getitem__(self, item):
if isinstance(item, basestring):
# treat single key as list of length one
item = [item]
values = []
for key in item:
# iterate through all keys in item
values.append(getattr(self, key))
return tuple(values)
f = Foo()
print f['a', 'c'] # prints (1, 3)
qux(*f['a', 'c'])

How to create a simple function within a class in Python?

I am starting to work with classes in Python, and am learning how to create functions within classes. Does anyone have any tips on this sample class & function that I am testing out?
class test:
def __init__(self):
self.a = None
self.b = None
self.c = None
def prod(self):
return self.a * self.b
trial = test
trial.a = 4
trial.b = 5
print trial.prod
Ideally the result would be to see the number 20.
You need to:
Create an instance of test.
Invoke the prod method of that instance.
Both of these can be accomplished by adding () after their names:
trial = test()
trial.a = 4
trial.b = 5
print trial.prod()
Below is a demonstration:
>>> class test:
... def __init__(self):
... self.a = None
... self.b = None
... self.c = None
... def prod(self):
... return self.a * self.b
...
>>> trial = test()
>>> trial.a = 4
>>> trial.b = 5
>>> print trial.prod()
20
>>>
Without the parenthesis, this line:
trial = test
is simply assigning the variable trial to class test itself, not an instance of it. Moreover, this line:
print trial.prod
is just printing the string representation of test.prod, not the value returned by invoking it.
Here is a reference on Python classes and OOP.
Ideally you could also pass in the values to a, b, c as parameters to your object's constructor:
class test:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def prod(self):
return self.a * self.b
Then, constructing and calling the function would look like this:
trial = test(4, 5, None)
print trial.prod()

how to create nicer variable interface in python class

I want a variable to do more than just be set when I set it.
and the interface to be as clean as possible.
short: what I'd want:
# have class with a variable that I can access:
print myInstance.var
42
# change the variable
myInstance.var = 23
# have the change kick off another method:
self.var was changed: 23!!
hmm.. so what I can do: Use the variable and a setter method:
class Test:
def __init__(self):
self.var = 1
print( 'self.var is: ' + str(self.var) )
def setVar(self, value):
self.var = value
print( 'self.var changed: ' + str(self.var) )
t = Test()
self.var is: 1
# so I have t.var at hand:
print t.var
1
# and change it this way
t.setVar(5)
self.var changed: 5
But then i have 2 different things to work with..
Ok I could make a method to interact with the var:
class Test:
def __init__(self):
self.var = 1
print( 'self.var is: ' + str(self.var) )
def method(self, value=None):
if value == None:
return self.var
self.var = value
print( 'self.var changed: ' + str(self.var) )
t = Test()
self.var is: 1
# to get the value then:
print t.method()
1
# to set it:
t.method(4)
self.var changed: 4
# and verifiy:
print t.method()
4
This is nice already. I've seen it in different post on other languages. but I dunno. Is there a be better solution in python?!?
Maybe I'm paranoid but but to me it'd just feel nicer to just do t.var = 5 and have something kicked off too.
I think you want python Properties. Check this out. Something like:
class Test:
def __init__(self):
self._var = 1
#property
def var(self):
return self._var
#var.setter
def var(self, value):
# add stuff here that you want to happen on var assignment
self._var = value
You can use a property. Note that if the setter method is expensive, it's better to use a method. People expect attribute access to be fast.
class Foo(object):
def __init__(self):
self._var = None
#property
def var(self):
return self._var
#var.setter
def var(self, whatever):
self._var = whatever
do_whatever()
x = Foo()
print x.var # prints None
x.var = 2 # sets x.var and does whatever

Pseudo-dicts as properties

I have a Python class C which should have two pseudo-dicts a and b. The term pseudo-dicts means that the dictionaries don't actually exist and that they are “recomputed” each time a key is accessed.
In pseudocode this would look like this:
class C:
def a.__getitem__(self, key):
return 'a'
def b.__getitem__(self, key):
return 'b'
>>> c = C()
>>> c.a['foo']
'a'
>>> c.b['bar']
'b'
I could implement a class for a and b, but since both have just a few short methods, I wonder whether there is a more elegant and compact way to do this.
Why not just define your own class?
class PseudoDict(object):
def __init__(self, c):
self.c = c
def __getitem__(self, key):
return self.c.somethingmagical()
class C(object):
def __init__(self):
self.a = PseudoDict(self)
self.b = PseudoDict(self)
c = C()
print c.a['foo']
print c.b['bar']
I'm not sure where the values for these 'pseudo-dicts' are coming from, so you'll have to update the __getitem__ method.
Like this?
from collections import defaultdict
class C:
a = defaultdict(lambda:'a')
b = defaultdict(lambda:'b')
c=C()
print c.a['foo']
print c.b['bar']
Or maybe like this for real calculation functions?
from collections import defaultdict
class C:
def __init__(self):
self.a = defaultdict(self.geta)
self.b = defaultdict(self.getb)
def geta(self):
return 'a'
def getb(self):
return 'b'
c=C()
print c.a['foo']
print c.b['bar']

Categories