2

Here is code, the class 'demo' defined by exec is not working when create a demo instance in _getTestObj().

FileName: test.py

class runOneIni():
    def _getTestObj(self):
        demo(self.tcName,secSetup,doc)



def start():   
    #implicit define 'demo' class by exec is not working, get error in runOneIni->_getTestObj, Error is :
    #  NameError: name 'demo' is not defined
    a='global demo'
    exec(a)

    str="class demo(tInvokeMethod.tInvokeMethod): pass'
    exec(str)

    #Explict define demo class is working
    #global demo
    #class demo(tInvokeMethod.tInvokeMethod): pass


if __name__ == '__main__':
    start()    
brike
  • 313
  • 4
  • 10

6 Answers6

1

(1) You have an unterminated string

(2) It is unnecessary to use exec to do this. class is itself an executable statement, which can appear anywhere any other statement can (except for a place where an expression statement is required).

Marcin
  • 48,559
  • 18
  • 128
  • 201
1

You could do something like this:

class SomeBaseClass(object):
    def __init__(self):
        self.a = 1
        self.b = 2

def make_new_class(name):
    class TemplateClass(SomeBaseClass):
        def __init__(self):
            SomeBaseClass.__init__(self)
            self.a = 3
    return type(name, (TemplateClass,), {})

o1 = SomeBaseClass()
print o1.a, o1.b

NewClass = make_new_class('NewClass')
o2 = NewClass()
print o2.a, o2.b

Result:

1 2
3 2
pillmuncher
  • 10,094
  • 2
  • 35
  • 33
0

I might be a little late to the party but I came up with something that seems to work okay. It will even correct type because of the setting property.

I'm sure this is all horribly unpythonic, but I think it's kinda fun.

def generateClass(propertyNames,propertyTypes):


    string = 'class generatedClass(object):\n    def __init__(self):\n'

    for pN in propertyNames:
        string += '        self._m' + pN + ' = None\n'


    string += '    \n    \n'

    i = 0
    for pN in propertyNames:
        string += '    @property\n' \
            '    def ' + pN + '(self):\n' \
            '        return self._m' + pN + '\n' \
            '    @' + pN + '.setter' +'\n' \
            '    def ' + pN + '(self,a'+ pN + '):\n' \
            '        if a' + pN + ':\n'\
            '            self._m'+ pN + ' = ' + propertyTypes[i] + '(a' + pN + ')\n'\
            '        \n'
        i += 1

    exec(string)
    return generatedClass()

if __name__ == '__main__':
    c = generateClass(['SomePropertyName'],['str'])
    print c.__dict__
    setattr(c,'SomePropertyName','some string')
    print c.__dict__
horriblyUnpythonic
  • 853
  • 2
  • 14
  • 34
0

You need to add the global demoin the same exec string. here the code with the result

class RunOneIni:
    def _getTestObj(self):
        self.tcName = 'tn'
        print(demo(self.tcName, 'secSetup', 'doc').__class__.__name__)


def start():
    t = 'class tInvokeMethod:\n\tclass tInvokeMethod:\n\t\tpass'
    exec(t)
    d = 'global demo\nclass demo(tInvokeMethod.tInvokeMethod):\n\tdef __init__(self, *args): pass'
    exec(d)
    demo()


if __name__ == '__main__':
    start()
    RunOneIni()._getTestObj()
Aram SEMO
  • 146
  • 8
0

The problem is not with defining a class via exec. The following works as intended:

exec 'class hi: pass'

Your problem is that "global" inside an exec statement has no effect outside it. According to the python documentation for exec:

the global is a directive to the parser. It applies only to code parsed at the same time as the global statement. In particular, a global statement contained in an exec statement does not affect the code block containing the exec statement, and code contained in an exec statement is unaffected by global statements in the code containing the exec statement.

alexis
  • 48,685
  • 16
  • 101
  • 161
0

Why are you doing that? (exec apart)
Why are you trying to do that with exec?

Also, doing it with exec will:

  1. Not work.
  2. Give different results in python-2.x and in python-3.x.

Example:

class demo:
    a = 'a'

print(demo.a)

def start():
    global demo
    class demo: b = "b"

    try:
        print(demo.a)
    except AttributeError:
        print(demo.b)

if __name__ == '__main__':
    start()

    try:
        print(demo.a)
    except AttributeError:
        print(demo.b)

That either in python-2.x and in python-3.x will give:

a
b
b

And now let's try it with exec:

class demo:
    a = 'a'

print(demo.a)

def start():
    exec('global demo', globals(), locals())

    exec('class demo: b = "b"', globals(), locals())

    try:
        print(demo.a)
    except AttributeError:
        print(demo.b)

if __name__ == '__main__':
    start()

    try:
        print(demo.a)
    except AttributeError:
        print(demo.b)

Output python2.7:

a
b
a

Output python3.2:

a
a
a

Q: How to 'dynamically create the class'?

As kindall already told you, exec is not the way to do that.

A metaclass or a class factory does that, but are you sure you actually need that?

Community
  • 1
  • 1
Rik Poggi
  • 28,332
  • 6
  • 65
  • 82
  • what I want to do is dynamic create class, in this example the class named 'demo', but the class name is not fixed, it is variable. So my idea is using string to assemble create class statement, the exec the string. – brike Feb 20 '12 at 15:54
  • Well, then, dynamically create the class, you hardly need `exec` to do that! – kindall Feb 20 '12 at 15:55
  • how to 'dynamically create the class' ? – brike Feb 20 '12 at 16:22
  • @brike: Are you sure you actually need that? Anyway `exec` is not the way to do it. – Rik Poggi Feb 20 '12 at 18:32