-1

Here is the basic class code:

class test:
    for i in range(10):
        exec(f'a{i}={i+1}')

My first attempt to create the list a_all was to do the following:

exec(f'a_all=[test.ak for k in range(0,10,2)]')

However, this doesn't work as exec does not 'unstring' ak the way I want it to. Other attempts failed because the exec function returns None. I'm not even confident anymore that exec could actually work.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
Zuter_242
  • 103
  • 3
  • 4
    What are you trying to do? `exec` on a constant string is entirely pointless, since you can just... run the Python code as code. What is the goal here? – Silvio Mayolo Apr 27 '22 at 00:29
  • It seems like a list would be a better idea for the class variable: `a = [i+1 for i in range(10)]` . Then `a_all=[test.a[k] for k in range(0,10,2)]`, but we have no idea why you are jumping through these hoops instead of just using regular python data structures. – Mark Apr 27 '22 at 00:35

2 Answers2

2

Your non-listcomp code works as written (kinda surprised by that), defining attributes of test, so just use that if it's what you need (it's almost certainly a bad idea, but you do you).

This doesn't work in your listcomp code because:

  1. test doesn't exist until the class definition completes (after you dedent at the end), so test.ANYTHING doesn't work inside the definition of test (you assign to top-level names, and they become attributes of test when the class finishes being defined, but they're just scoped names without test. qualification before then)
  2. Omitting test doesn't work in Python 3 because listcomps have their own scope in Python 3; even if you fake it out to assign to each of your names in turn, the iteration variables don't leak to outer scope on Python 3.

In any event, what you're doing is nonsensical:

  1. Your plain for loop code works, but
  2. It's a bad idea; just have a single class attribute of the list and have users index it as needed. There's basically never a good reason to have a programmatically generated list of numbered variable names. That's reinventing lists, badly.

So just use:

class test:
    a = range(0, 10, 2)  # Or list(range(0, 10, 2)) if it must be mutable

and user's can do test.a[0], test.a[3], whatever they need.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
-2

You can use setattr and getattr to set class attributes.

class test:
    def __init__(self):
        for i in range(10):
            setattr(self, f"a{i}", i + 1)

t = test()
for i in range(10):
    print(f"{t.a1=}  a{i}={getattr(t, f'a{i}')=}")
Lukas Schmid
  • 1,895
  • 1
  • 6
  • 18
  • 2
    The OP was trying to do this to set *class* attributes. You're using it to set *instance* attributes. It's not the same thing, and it can't be done inside a class definition to set class attributes (because `setattr` needs a reference to the thing to set the attributes on, and the class doesn't exist yet to set things on). – ShadowRanger Apr 27 '22 at 00:36