3

I was messing around with inherited classes and wondered if it was possible to set a custom object attribute using a method. It would work something like this:

class MyClass(object):
    def __init__(self):
        super.__init__()
    def setCustAttr(self, name, value):
        #...
g=MyClass()
g.setCustAttr("var",5)
g.var+=6
g.var="text"
  • Is there any way to do this?
  • Could you use exec("self."+string+"="+value)?
Mutantoe
  • 703
  • 8
  • 20
  • possible duplicate of [python create object and add attributes to it](http://stackoverflow.com/questions/2827623/python-create-object-and-add-attributes-to-it) – felipsmartins May 03 '15 at 19:11
  • Not a dupe of that question. That question is about `setattr` failing on `object`s. It's likely a dupe of something else. – user2357112 May 03 '15 at 19:14
  • I'm assuming you mean in addition to `g.var = 5`? – chepner May 03 '15 at 19:18

2 Answers2

9

This is what the setattr function does:

setattr(g, 'var', 5)
# g.var is now 5
user2357112
  • 260,549
  • 28
  • 431
  • 505
1

The arguments passed to setCustAttr are exactly the arguments you would pass to setattr.

def setCustAttr(self, name, value):
    setattr(self, name, value)

Why would you want a wrapper around setattr? You might try to perform some validation:

def setCustAttr(self, name, value):
    if name not in ['bar', 'baz']:
        raise ValueError("Custom attribute must be 'bar' or 'baz'")
    if name == 'bar' and value < 0:
        raise ValueError("'bar' attribute must be non-negative")
    if name == 'baz' and value % 2:
        raise ValueError("'baz' attribute must be even")

    setattr(self, name, value)

However, this doesn't prevent the user of your class from ignoring your setCustAttr method and assigning directly to the object:

g = MyClass()
g.bar = -5  # Negative bar!
g.baz = 3   # Odd baz!
g.quux = 2  # Non-bar/baz attribute!

Python has deep magic for providing more control over how attributes are set on an object (see __slots__, __{get,set}attr__, __getattribute__, properties, etc), but generally, they aren't used merely to prevent the examples shown above. The Python way is to just document how an instance of your class should be used, and trust the user to abide by your instructions. (And if they don't, caveat emptor.)

chepner
  • 497,756
  • 71
  • 530
  • 681
  • So there would be no need for another method? – Mutantoe May 03 '15 at 19:23
  • Not really. You might use a wrapper like this to provide validation. `g.setCustAttr("var", 5)` might first check that the value is greater than 0 (raising a `ValueError` if not), or that the first argument is from a restricted set of names (simulating part of the function of the `__slots__` attribute). However, a user of your class could still just ignore your method and write `g.var = 5` anyway. – chepner May 03 '15 at 19:27
  • So you would evaluate the new value before setting. Thanks! – Mutantoe May 03 '15 at 19:29