0

Hello all I have a custom class MyClass. I wish to iterate over its default values. I think my issue is best shown with an example:

class MyClass:
    def __iter__(self):
        for each in self.__dict__.values():
            yield each

    first_var: str = "asdf"
    second_var: str = "tasdt"


my_class = MyClass()

for var in my_class:  # this does not work, how can i get this to work?
    print(var)

my_class.first_var = "hello" # setting the variables makes it work
my_class.second_var = "world"

for var in my_class:  # now it works
    print(var)

As you can see from the example the first for loop does not print the default values of the class MyClass. How can I achieve that?

EDIT: Based on the comment by C Hecht i tried

def __iter__(self):
    for attribute in self.__dict__.keys():
        if attribute[:2] != '__':
            value = getattr(self, attribute)
            if not callable(value):
                print(attribute, '=', value)
                yield value

Still not getting those class attributes

rok
  • 9,403
  • 17
  • 70
  • 126
petro99
  • 35
  • 6
  • Does this answer your question? [Getting attributes of a class](https://stackoverflow.com/questions/9058305/getting-attributes-of-a-class) – C Hecht Aug 06 '21 at 09:17
  • Do you *only* want the class variables? Or do you also want any instance variables you might define in the future? – Blckknght Aug 06 '21 at 09:33

3 Answers3

2

Decorate Python class with @dataclass to achieve default initialization of the class instances fields. It's available since Python 3.7 and it implicitly adds __init__ constructor to the class which initializes the class instance with default values you specified.

from dataclasses import dataclass

@dataclass
class MyClass:
    def __iter__(self):
        for each in self.__dict__.values():
            yield each

    first_var: str = "asdf"
    second_var: str = "tasdt"


my_class = MyClass()

for var in my_class:
    print(var)

prints

asdf
tasdt
rok
  • 9,403
  • 17
  • 70
  • 126
1

The reason the above doesnt work is that self.__dict__ holds instance values. These are typically values that are added to the class through setting attributes:

my_class = MyClass()

my_class.__dict__ # {}

my_class.x = 1    # {'x': 1} 

If you want to access the class attributes first_var and second_var then you should look into the method vars

eg:


for k, v in vars(MyClass.items()): 
    print(x, y)
# __module__ __main__
# __iter__ <function MyClass.__iter__ at 0x10e22fca0>
# first_val first
# second_var second
# __dict__ <attribute '__dict__' of 'MyClass' objects>
# __weakref__ <attribute '__weakref__' of 'MyClass' objects>
# __doc__ None

If you wanted to just get values you wanted you would need to do something like:

def __iter__(self):
    for k, v in vars(type(self)).items(): # need type(self) to refer to the class
        if not k.startswith('_'): 
            yield v
user3645016
  • 603
  • 5
  • 7
0

The problem is because you are iterating over the "instance" attribute of the class Myclass not the attributes of the class itself. Those first_var and second_var are class attributes:

If you want to get all class attributes:

class MyClass:
    def __iter__(self):
        for each in self.__class__.__dict__.values():
            yield each

    first_var: str = "asdf"
    second_var: str = "tasdt"


my_class = MyClass()

for var in my_class:
    print(var)

Of course you may want to filter it by being callable or not, starting with dunder or ...

S.B
  • 13,077
  • 10
  • 22
  • 49