3

Question

I want to accomplish the following:

tmp = do_stuff(tmp2)
if tmp != None:
    num = tmp

However the variables to be assigned in my problem are variables (better: properties) of an object instance:

class mycls(object):
    def __init__(self):
        self.__a, self._b, self.c = 2, 3, 5
    def set_a(self, val): self.__a = val
    def set_b(self, val): self._b = val
    def set_c(self, val): self.c = val
    A = property(fset = set_a)
    B = property(fset = set_b)
    C = property(fset = set_c)
tmp2 = [7, 11, 13]
inst = mycls()
tmp = do_stuff(tmp2[0])
if tmp != None: inst.A = tmp
tmp = do_stuff(tmp2[1])
if tmp != None: inst.B = tmp
tmp = do_stuff(tmp2[2])
if tmp != None: inst.C = tmp

Obviously the last part looks highly repetitive and in my case needs to be applied to over 10 variables. My question now is: how can those last 6 lines be compressed?

Own attempts at solving the problem

Ideally I would prefer a solution like:

for i in [[inst.A, 0], [inst.B, 1], [inst.C, 2]]:
    tmp = do_stuff(tmp2[i[1]])
    if tmp != None: i[0] = tmp

However this doesn't work (because the inst.X are evaluated and you can't store primitive datatypes by reference/pointer). Another approach I came up with was to use the variable names as strings and fiddle with inst.__dict__, e.g. like this:

for i in [["A", 0], ["B", 1], ["C", 2]]:
    tmp = do_stuff(tmp2[i[1]])
    if tmp != None: inst.__dict__[i[0]] = tmp

However this plan was foiled by the fact that A, B and C are properties.

LISP-like macros would be an enormous help here, unfortunately Python doesn't seem to support macros and I don't want to add dependencies to one of the macro libraries for Python I found on-line (which I didn't test since I won't be able to use them anyway).

I also want to avoid using anonymous functions in a list since this will likely result in the same amount of code as in the second code listing.

My last resort to solve this problem would currently be evals, which I wanted to avoid at all cost.

3
  • Why not use lambda functions? Commented Aug 25, 2012 at 14:30
  • @Peter Kirby: my goal is to reduce the amount of code, not just transform it into a different form. In the case I misunderstood, please clarify. Commented Aug 25, 2012 at 14:33
  • I did misunderstand, sorry. However, Martjin's answer is correct, and should work. Commented Aug 25, 2012 at 14:34

1 Answer 1

5

You are looking for setattr():

for i in [["A", 0], ["B", 1], ["C", 2]]:
    tmp = do_stuff(tmp2[i[1]])
    if tmp != None: setattr(inst, i[0], tmp)

To quote the documentation:

This is the counterpart of getattr(). The arguments are an object, a string and an arbitrary value. The string may name an existing attribute or a new attribute. The function assigns the value to the attribute, provided the object allows it. For example, setattr(x, 'foobar', 123) is equivalent to x.foobar = 123.

Note that since None is a singleton in python, usually one tests for it using the is or is not operators:

for i in [["A", 0], ["B", 1], ["C", 2]]:
    tmp = do_stuff(tmp2[i[1]])
    if tmp is not None:
        setattr(inst, i[0], tmp)

and the PEP 8 python styleguide discourages compound statements; keep the if suite on it's own line, even if it is just one line.

Sign up to request clarification or add additional context in comments.

2 Comments

Considering the styleguide comments regarding indentation: When writing example code, I try to keep it as short as possible. While the statements in PEP 8 are most certainly helpful in programs and projects, I don't think the guidelines hold for minimal example code.
Well, in a 3 or a 4 line example isn't going to make much odds; I find the clear indentation more readable, and with example code you want to go for maximum readability. :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.