2

If I have a python class which allows for an options parameter upon instantiation, how can I dynamically set a function to it, based upon the value of that options parameter. For example, if I have the code

def hello1():
    print(self.name,"says hi")

def hello2():
    print(self.name,"says hello")

class A:
    def __init__(self, name, opt=0):
        if opt == 1:
            setattr(self,'hello',hello1)
        else:
            setattr(self,'hello',hello2)

if __name__ == "__main__":
    a1 = A("my")
    a2 = A("name",1)
    a1.hello()
    a2.hello()

I get the traceback error

Traceback (most recent call last):
  File "dynamic_classes.py", line 17, in <module>
    a1.hello()
  File "dynamic_classes.py", line 5, in hello2
    print(self.name,"says hello")
NameError: global name 'self' is not defined
5
  • Do you realize that getattr(a, 'b', c) is an obscure way to write a.b = c? Commented Aug 6, 2013 at 22:03
  • I understand that. I am writing a wrapper around zmq which instantiates processes with a special connection method, either a bind, or connect method, which is defined at instantiation Commented Aug 6, 2013 at 22:06
  • So, why do you use setattr (just noticed the typo in my first comment), rather than plain old attribute assignment? Commented Aug 6, 2013 at 22:07
  • Here is a copy of my current code pastebin.com/9QeY0p0y, maybe this will illuminate this. I do not want to have to write a connect method for each class, also, I will add extra protection to the bind method Commented Aug 6, 2013 at 22:09
  • I am only talking about the lines of the form setattr(self, 'connect', <something>). These are exactly equivalent to self.connect = <something>, so why don't you do that? Commented Aug 6, 2013 at 22:11

2 Answers 2

5

Your functions do not define a self parameter, nor will they ever get one.

You need to use methods; you can create these from the functions by treating them as descriptors and explicitly calling .__get__() on them:

def hello1(self):
    print(self.name,"says hi")

def hello2(self):
    print(self.name,"says hello")

class A:
    def __init__(self, name, opt=0):
        if opt == 1:
            setattr(self, 'hello', hello1.__get__(self, type(self))
        else:
            setattr(self, 'hello', hello2.__get__(self, type(self)))

Normally, the .__get__() method is called on functions when accessing them on a class (either directly or via an instance). This doesn't happen for functions added directly on an instance however, so you need to do it manually.

Sign up to request clarification or add additional context in comments.

Comments

0

You can also use MethodType from types module.

import types

def hello1(self):
   print(self.name,"says hi")

def hello2(self):
   print(self.name,"says hello")

class A:
   def __init__(self, name, opt=0):
       self.name = name
       if opt == 1:
           self.hello = types.MethodType(hello1, self)
       else:
           self.hello = types.MethodType(hello2, self)

A('a').hello()   # ('a', 'says hello')

A('a', 1).hello() # ('a', 'says hi')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.