What am I missing about how `setattr()` works in this context? How can I use `setattr Python` properly to achieve what I’m trying to do?

How do I use setattr() in Python?

I’m trying to understand the basics of how to use setattr() correctly in Python, and I encountered an issue while attempting to use a class method to return data and then pass that data into another method. My goal is to get a better understanding of how classes work, specifically in relation to setting attributes dynamically.

I thought setattr() might be the solution, but I ran into an error in my code. Here’s what I’ve tried so far:

#! /bin/python2.6

class HolyGrail(object):

    def __init__(self):
        self.start = 'start_at_init'

    def run_it(self):
        start = setattr(self, 'name', 'get_thing')
        start = self.name

        value_returned = start()  # I believe this == self.get_thing()
        use_it(value_returned)

    def get_thing(self):
        return "The Knights Who Say ... Ni!"

    def use_it(self, x):
        print x
        print "We want a shrubbery!"

my_instance = HolyGrail()
my_instance.run_it()

I also tried an alternate approach:

class HolyGrail(object):

    def __init__(self):
        self.start = 'get_thing'

    def run_it(self):
        go_do_it = getattr(self, start)
        first_output = go_do_it()
        use_it(first_output)

    def get_thing(self):
        return "The Knights Who Say ... Ni!"

    def use_it(self, x):
        print x
        print "We want a shrubbery!"

my_instance = HolyGrail()
my_instance.run_it()

But I keep getting errors like TypeError: 'str' object is not callable and NameError: global name 'start' is not defined.

What am I missing about how setattr() works in this context? How can I use setattr Python properly to achieve what I’m trying to do?

You can use setattr() to dynamically assign a method name to an instance attribute. However, you need to ensure that you’re calling the method correctly.

Here’s a corrected version of your code:

class HolyGrail(object):

    def __init__(self):
        self.start = 'get_thing'

    def run_it(self):
        # Using setattr to assign the method name to an attribute
        setattr(self, 'name', self.get_thing)
        
        # Calling the method stored in 'name' attribute
        value_returned = self.name()
        self.use_it(value_returned)

    def get_thing(self):
        return "The Knights Who Say ... Ni!"

    def use_it(self, x):
        print(x)
        print("We want a shrubbery!")

my_instance = HolyGrail()
my_instance.run_it()

Here, I have use setattr() to store a reference to the get_thing() method in the name attribute. Later, we call self.name() to execute the method.

You can use getattr() to retrieve a method dynamically based on its name. This is especially useful when you need to access a method whose name is stored in a variable or attribute. Here’s an example:

class HolyGrail(object):

    def __init__(self):
        self.start = 'get_thing'

    def run_it(self):
        # Using getattr to access the method dynamically
        go_do_it = getattr(self, self.start)
        first_output = go_do_it()
        self.use_it(first_output)

    def get_thing(self):
        return "The Knights Who Say ... Ni!"

    def use_it(self, x):
        print(x)
        print("We want a shrubbery!")

my_instance = HolyGrail()
my_instance.run_it()

Here, we use getattr(self, self.start) to dynamically retrieve the get_thing() method based on the start attribute and then call it.

If you don’t need dynamic assignment of the method, you can simply call the method directly without using setattr(). This approach is more straightforward and avoids unnecessary complexity.

class HolyGrail(object):

    def __init__(self):
        pass

    def run_it(self):
        # Directly calling the method
        value_returned = self.get_thing()
        self.use_it(value_returned)

    def get_thing(self):
        return "The Knights Who Say ... Ni!"

    def use_it(self, x):
        print(x)
        print("We want a shrubbery!")

my_instance = HolyGrail()
my_instance.run_it()

Here, we directly call self.get_thing() to get the value and pass it to self.use_it(). This method is simpler and doesn’t require setattr() or getattr().