1

Recently I wrote a program as follows:

empty_list = []
for row in rows:
    if row.num1 != 0:
        empty_list.extend(row.amt1)
    if row.num2 != 0:
         empty_list.extend(row.amt2)
    if row.num3 != 0:
         empty_list.extend(row.amt3)
    if row.num4 != 0:
         empty_list.extend(row.amt4)

this pattern goes on till num10.

Basically we are extending the list till we find row.num{d} = 0.

My question is since the variables are numbered, can we do something in a pythonic way or in a loop. The example is simplified. We are importing legacy data from an old dbase format.

vb_rises
  • 1,847
  • 1
  • 9
  • 14
Shh
  • 986
  • 9
  • 18
  • you can try np.where(row != 0), here row should be numpy array. – vb_rises Jul 23 '19 at 10:38
  • Related [How to access object attribute given string corresponding to the name of that attribute](https://stackoverflow.com/a/2612615/8608146) – Phani Rithvij Jul 23 '19 at 10:44
  • 1
    if you define `row.num` and `row.atm` as tuple, can use indexing (for example, `a.atm[1]`) and make code simpler. – Masoud Jul 23 '19 at 10:44
  • @Shh can you show the structure of row? It would be easier to refine the answer then. – BarathVutukuri Jul 23 '19 at 10:44
  • @snakecharmerb: getattr should be the best possible solution. – Shh Jul 23 '19 at 10:58
  • @BarathVutukuri: As said earlier, it's the fields from dbase file. It has around 356 columns. I have given columns which are relevant to the question. – Shh Jul 23 '19 at 11:00
  • I think the data structure of having single elements in single attribute in such a manner is pretty bad. As suggested by @Masoud you should rearrange the data in arrays or lists. – Sven-Eric Krüger Jul 23 '19 at 11:04
  • XY problem. Don't create variables with names like this. Use list of tuples/dictionary instead – Jean-François Fabre Jul 23 '19 at 11:16
  • @Jean-FrançoisFabre OP said they're importing from `dBase` a database which I'm assuming doesn't allow changing class declarations. – Phani Rithvij Jul 23 '19 at 11:18

3 Answers3

1

I'm guessing the class structure of a row is like this.

# This is a mock class
class Row:
    def __init__(self):
        self.num1 = 32
        self.num2 = 23
        self.num3 = 323
        self.num4 = 213
        self.num5 = 23
        self.num6 = 0
        self.amt1 = [20]
        self.amt2 = [320]
        self.amt3 = [320]
        self.amt4 = [340]
        self.amt5 = [30]
        self.amt6 = [330]

Then you can use getattr like this

row = Row()
empty_list = []
i = 1
while (getattr(row, "num{}".format(i)) != 0):
    empty_list.extend(getattr(row, "amt{}".format(i)))
    i += 1
Phani Rithvij
  • 4,030
  • 3
  • 25
  • 60
1
import itertools
import contextlib

for row in rows:
    with contextlib.supress(AttributeError):
        for i in itertools.count(start=1):
            if getattr(row, f'num{i}') != 0:
                empty_list.extend(getattr(row, f'amt{i}'))
                break

should work. For each row, getattr is used until AttributeError is raised and next row is processed.

Note: the above code uses f-strings, so you need python 3.6+ to use them. If you use an older version, simply use .format().

asikorski
  • 882
  • 6
  • 20
0

You can try to use eval() function

empty_list = []
for row in rows:
    for i in range(1, 11):
        if eval('row.num' + str(i)) != 0:
            empty_list.extend(eval('row.atm' + str(i)))