0

I'm new to Python, and I was wondering why I can't change the attribute for a class instance using a function, if I pass the instance as a function parameter For example, if I had:

class sol:
    def __init__(self):
        self.val = 0

def fun1(obj, attrib):
    obj[attrib] = 1

newSol = sol()

fun1(newSol, "val")

Why can't fun1 change the object attribute? Is there a way to change it, or is the "val" attribute immutable?

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
albert
  • 1,158
  • 3
  • 15
  • 35
  • 3
    Attribute access (`obj.attr`) and indexing (`obj[index]`) are entirely separate concepts in Python. You'd need to use `setattr(obj, attrib, 1)` to set an attribute indirectly. – jasonharper Sep 06 '18 at 00:00
  • Sorry, in my mind I was thinking of dicts as objects, and I was assuming the same syntax for setting dict attributes was the same as setting object attribute. Would the sytax dict[attrib] = 1 work for dicts only then? – albert Sep 06 '18 at 00:06
  • 1
    You can make your own class that supports indexing by implementing the `__setitem__()`/`__getitem__()` methods. – jasonharper Sep 06 '18 at 00:11
  • @albert `dict`s *are* objects. Everything in Python is an object. Dict objects cannot have attributes, and using `mydict[k] = v` does not create an attribute on the dict objects. – juanpa.arrivillaga Sep 06 '18 at 01:30
  • @juanpa.arrivillaga what I meant to say was I was thinking of all objects in Python as dicts. And I'm a little confused about what you said about dicts. Using mydict[k] = v does create a k attribute for mydict, does it not? – albert Sep 07 '18 at 02:00
  • @albert no, it does not. It assigns a key to a value, but these are not attributes – juanpa.arrivillaga Sep 07 '18 at 03:13
  • Hint: where the code says `self.val = 0`, why does it (correctly) **not** say `self['val'] = 0`? What do you think would happen if you tried that? What does happen if you do try it? Did you try *reading* the error message? – Karl Knechtel Aug 13 '22 at 09:33

1 Answers1

2

Python class instances and dict are completely different beasts; you're likely coming from a JavaScript background where obj.foo is equivalent to obj["foo"], but that's not how Python works.

If you want to set an attribute via a str name, use setattr:

def fun1(obj, attrib):
    setattr(obj, attrib, 1)
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • Ah ok I was just wondering that. Thanks for the clarification. – albert Sep 06 '18 at 00:06
  • It seems a little disingenuous to suggest that there's *no* relation between object attributes and dictionaries, considering that most objects store their attributes in a `__dict__` dict. – Patrick Haugh Sep 06 '18 at 00:08
  • 1
    @PatrickHaugh: Except when `__slots__` are involved, or it's a C built-in using descriptors to implement access, or when it's a subclass of `tuple` or `list` (e.g. anything made via `collections.namedtuple`) using `@property` to alias indices to names, etc. Yes, `__dict__` is implemented as a `dict`-like thing, often an actual `dict` (when it exists, which isn't always). But that's mostly an "in the weeds" implementation detail, and not relevant to how you *use* class instances in 99.999% of cases. Class instances don't quack like `dict`, so the relationship isn't relevant most of the time. – ShadowRanger Sep 06 '18 at 00:41