why python exec define class not working - python

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()

(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).

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

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.

Why are you doing that? (exec apart)
Why are you trying to do that with exec?
Also, doing it with exec will:
Not work.
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?

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__

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()

Related

Python Class - Can't find out how to use method return value within another method

So this is the class i'm testing:
class Test:
def find_string(self, string):
self.string = string
return string.find(string)
def add_string(self, string):
found = self.find_string('bar')
if found == -1:
string = string + ' bar'
return string
Here is my setup:
test_string = 'foo'
Test1 = Test()
new_string = Test1.add_string(string)
Results
Expected result: foo bar
Result: foo
If I replace the method call in add_string with the direct function find() it works fine. Please help me.
As for me all problem is that variables have similar names and this can be misleading.
Your string.find(string) means "bar".find("bar") but you expect "foo".find("bar")
You would have to use self.string = string in add_string() (instead of find_string()) and later in find_string() use self.string.find(string) instead of string.find(string) - and then you will have "foo" in self.string and "bar" in string so finally self.string.find(string) will mean "foo".find("bar")
class Test:
def find_string(self, string):
return self.string.find(string)
def add_string(self, string):
self.string = string
found = self.find_string('bar')
if found == -1:
string = string + ' bar'
return string
# --- main ---
test_string = 'foo'
test = Test() # PEP8: `lower_case_names` for variables
new_string = test.add_string(test_string)
print(new_string)
PEP 8 -- Style Guide for Python Code

`globals` not working inside a nested function

I'm making a decorator that allows me to make functions run as if their lines of code are written in main. To achieve this, I'm using globals().update(vars()) inside the function (works), but now inside the decorator it fails.
class Debugger:
#staticmethod
def in_main(func): # a decorator
def wrapper(): # a wrapper that remembers the function func because it was in the closure when construced.
exec(Debugger.convert_to_global(func)) # run the function here.
globals().update(vars()) # update the global variables with whatever was defined as a result of the above.
return wrapper
#staticmethod
def convert_to_global(name):
"""Takes in a function name, reads it source code and returns a new version of it that can be run in the main.
"""
import inspect
import textwrap
codelines = inspect.getsource(name)
# remove def func_name() line from the list
idx = codelines.find("):\n")
header = codelines[:idx]
codelines = codelines[idx + 3:]
# remove any indentation (4 for funcs and 8 for classes methods, etc)
codelines = textwrap.dedent(codelines)
# remove return statements
codelines = codelines.split("\n")
codelines = [code + "\n" for code in codelines if not code.startswith("return ")]
code_string = ''.join(codelines) # convert list to string.
temp = inspect.getfullargspec(name)
arg_string = """"""
# if isinstance(type(name), types.MethodType) else tmp.args
if temp.defaults: # not None
for key, val in zip(temp.args[1:], temp.defaults):
arg_string += f"{key} = {val}\n"
if "*args" in header:
arg_string += "args = (,)\n"
if "**kwargs" in header:
arg_string += "kwargs = {}\n"
result = arg_string + code_string
return result # ready to be run with exec()
example of reproducible failure:
#Debugger.in_main
def func():
a = 2
b = 22
func()
print(a)
Gives
NameError: name 'a' is not defined
I am not sure what you are trying to do. But messing with variables scope and encapsulation may yield very bad and unpredictable and undebuggable behavior.
I STRINGLY NOT RECOMMNED IT.
Now to your problem:
globals() is a tricky one as there is no one globals() dictionary.
You can verify it easily by print(id(globals()) and see.
What is working for your example is mutating the __main__ module __dict__ with the exec results.
This is done by exec(the_code_you_want_to_run, sys.modules['__main__'].__dict__.
The globals().update(vars()) is not needed.
Here is the code:
import sys
class Debugger:
#staticmethod
def in_main(func): # a decorator
def wrapper(): # a wrapper that remembers the function func because it was in the closure when construced.
exec(Debugger.convert_to_global(func), sys.modules['__main__'].__dict__) # run the function here on the scope of __main__ __dict__
# globals().update(vars()) # NOT NEEDED
return wrapper
#staticmethod
def convert_to_global(name):
"""Takes in a function name, reads it source code and returns a new version of it that can be run in the main.
"""
import inspect
import textwrap
codelines = inspect.getsource(name)
# remove def func_name() line from the list
idx = codelines.find("):\n")
header = codelines[:idx]
codelines = codelines[idx + 3:]
# remove any indentation (4 for funcs and 8 for classes methods, etc)
codelines = textwrap.dedent(codelines)
# remove return statements
codelines = codelines.split("\n")
codelines = [code + "\n" for code in codelines if not code.startswith("return ")]
code_string = ''.join(codelines) # convert list to string.
temp = inspect.getfullargspec(name)
arg_string = """"""
# if isinstance(type(name), types.MethodType) else tmp.args
if temp.defaults: # not None
for key, val in zip(temp.args[1:], temp.defaults):
arg_string += f"{key} = {val}\n"
if "*args" in header:
arg_string += "args = (,)\n"
if "**kwargs" in header:
arg_string += "kwargs = {}\n"
result = arg_string + code_string
return result # ready to be run with exec()

Replacing one method with another within a loop using lambda in Python [duplicate]

This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 6 months ago.
Here is an example of what I am trying to achieve. The class has a someMethod which has to be replaced with some other method (in this case returnStuff) when instance is created. I am using lambda to replace the method as the new one has an argument. Running the replaced method from a loop causes no problem, but running it after the loop turns all arguments to the same value. Replacing methods manualy works ok though. The code prints out everything needed to understand the problem.
def returnStuff(stuff):
return stuff
class SomeClass(object):
def __init__(self):
pass
def someMethod(self):
pass
classInstances = []
#RUN METHODS WITHIN CREATION LOOP
print 'STARTING CREATION LOOP:\n'
for i in range(1, 6):
classInstance = SomeClass()
classInstances.append(classInstance)
classInstance.someMethod = (lambda: returnStuff(i))
print 'I was returned from the Creation Loop and I am fabulous: ', classInstance.someMethod(), '\n'
print '====================================================================\n'
print 'RUN METHODS AFTER THE LOOP:\n'
#CALLING METHODS LATER ON
for inst in classInstances:
print 'I was returned after creation, and I am not who I want to be: ', inst.someMethod(), '\n'
print '====================================================================\n'
print 'TRYING MANUAL APPROACH (NO LOOP):\n'
classInstance1 = SomeClass()
classInstance1.someMethod = (lambda: returnStuff(1))
print 'I was returned from the manually replaced method. I\'m pretty fine: ', classInstance1.someMethod(), '\n'
classInstance2 = SomeClass()
classInstance2.someMethod = (lambda: returnStuff(2))
print 'I was returned from the manually replaced method. I\'m pretty fine: ', classInstance2.someMethod(), '\n'
classInstance3 = SomeClass()
classInstance3.someMethod = (lambda: returnStuff(3))
print 'I was returned from the manually replaced method. I\'m pretty fine: ', classInstance3.someMethod(), '\n'
classInstance4 = SomeClass()
classInstance4.someMethod = (lambda: returnStuff(4))
print 'I was returned from the manually replaced method. I\'m pretty fine: ', classInstance4.someMethod(), '\n'
classInstance5 = SomeClass()
classInstance5.someMethod = (lambda: returnStuff(5))
print 'I was returned from the manually replaced method. I\'m pretty fine: ', classInstance5.someMethod(), '\n'
Rather than using lambda (which doesn't properly create a closure for your i variable). You should just use partial or some other function factory.
E.g.
from functools import partial
for i in range(1, 6):
classInstance = SomeClass()
classInstances.append(classInstance)
classInstance.someMethod = partial(returnStuff, i)
or
def methodFactory(n):
def returnStuff():
return n
for i in range(1, 6):
classInstance = SomeClass()
classInstances.append(classInstance)
classInstance.someMethod = methodFactory(i)

output is not printing string in python

i have made a program but the output that i'm getting is
(<q3v3.Student instance at 0x023BB620>, 'is doing the following modules:', ' <q3v3.Module instance at 0x023BB670> <q3v3.Module instance at 0x023BB698>')
For example , the above output should give me Alice is doing following module : biology, chemistry
Help
this is my full code:
class Student :
def __init__(self,students):
self.students= students
print self.students
#def __str__(self): # when i used this i've got error type TypeError: __str__ returned non-string (type NoneType)
#print str(self.students)
class Module:
def __init__(self,modules):
self.modules = modules
print self.modules
#def __str__(self):
#print str(self.modules)
class Registrations (Student,Module):
def __init__(self):
self.list= []
self.stulist = []
self.modulist= []
def __iter__(self):
return iter(self.list)
def __str__(self):
return str(self.list)
def add(self,students,modules):
self.list.append((students,modules))
#print (self.list)
def students(self,modules):
for i in self.list:
if i[1] == modules:
self.modulist.append((i[0]))
return iter(self.modulist)
def __str__(self):
return str(self.students)
def modules(self,students):
for i in self.list:
if i[0] == students:
self.stulist.append((i[1]))
return iter(self.stulist)
def __str__(self):
return str(self.modules)
i need to import my program to be able to run it to this :
from q3v4 import *
james = Student('james')
alice = Student('alice')
mary = Student('mary')
agm = Module('agm')
ipp = Module('ipp')
r = Registrations()
r.add(james,agm)
r.add(alice,agm)
r.add(alice,ipp)
mstr = ''
for m in map(str,r.modules(alice)):
mstr = mstr+' '+m
print(alice, 'is doing the following modules:', mstr)
sstr = ''
for s in map(str,r.students(agm)):
sstr = sstr+' '+s
print(agm, 'has the following students:', sstr)
print(r)
You could define a __str__ method in your Student class, and do something like this:
def __str__(self):
return self.name # Here the string you want to print
Are you using Python 2? If so, print is a keyword, not a function. There are two ways to solve your problem:
Write print foo, bar instead of print(foo, bar).
The difference is that print(foo, bar) is actually printing out the tuple (foo, bar), which uses the repr() representation of each element, rather than its str().
At the very top of your file, write from __future__ import print_function. This will magically convert print from a keyword into a function, causing your code to work as expected.
If you are using Python 3, my answer is irrelevant.

How do I match a python function definition (and nothing else) with RegEx?

I'm trying to use RegEx within Python to parse out a function definition and NOTHING else. I keep running into problems though. Is RegEx the right tool to be using here?
i.e.
def foo():
print bar
-- Matches --
a = 2
def foo():
print bar
-- Doesn't match as there's code above the def --
def foo():
print bar
a = 2
-- Doesn't match as there's code below the def --
An example of a string I'm trying to parse is "def isPalindrome(x):\n return x == x[::-1]". But in reality that might contain lines above or below the def itself.
What RegEx expression would I have to use to achieve this?
No, regular expressions are not the right tool for this job. This is similar to people desperately trying to parse HTML with regular expressions. These languages are not regular. Thus you can't work around all quirks you will encounter.
Use the built-in parser module, build a parse tree, check for definition nodes and use them instead. It's even better to use the ast module as it is way more convenient to use. An example:
import ast
mdef = 'def foo(x): return 2*x'
a = ast.parse(mdef)
definitions = [n for n in ast.walk(a) if type(n) == ast.FunctionDef]
reg = re.compile('((^ *)def \w+\(.*?\): *\r?\n'
'(?: *\r?\n)*'
'\\2( +)[^ ].*\r?\n'
'(?: *\r?\n)*'
'(\\2\\3.*\r?\n(?: *\r?\n)*)*)',
re.MULTILINE)
EDIT
import re
script = '''
def foo():
print bar
a = 2
def foot():
print bar
b = 10
"""
opopo =457
def foor(x):
print bar
print x + 10
def g(u):
print
def h(rt,o):
assert(rt==12)
a = 2
class AZERT(object):
pass
"""
b = 10
def tabulae(x):
\tprint bar
\tprint x + 10
\tdef g(u):
\t\tprint
\tdef h(rt,o):
\t\tassert(rt==12)
a = 2
class Z:
def inzide(x):
print baracuda
print x + 10
def gululu(u):
print
def hortense(rt,o):
assert(rt==12)
def oneline(x): return 2*x
def scroutchibi(h%,n():245sqfg srot b#
'''
.
reg = re.compile('((?:^[ \t]*)def \w+\(.*\): *(?=.*?[^ \t\n]).*\r?\n)'
'|'
'((^[ \t]*)def \w+\(.*\): *\r?\n'
'(?:[ \t]*\r?\n)*'
'\\3([ \t]+)[^ \t].*\r?\n'
'(?:[ \t]*\r?\n)*'
'(\\3\\4.*\r?\n(?: *\r?\n)*)*)',
re.MULTILINE)
regcom = re.compile('("""|\'\'\')(.+?)\\1',re.DOTALL)
avoided_spans = [ma.span(2) for ma in regcom.finditer(script)]
print 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'
for ma in reg.finditer(script):
print ma.group(),
print '--------------------'
print repr(ma.group())
print
try:
exec(ma.group().strip())
except:
print " isn't a valid definition of a function"
am,bm = ma.span()
if any(a<=am<=bm<=b for a,b in avoided_spans):
print ' is a commented definition function'
print 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'
result
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
def foo():
print bar
--------------------
'def foo():\n print bar\n\n'
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
def foot():
print bar
--------------------
'def foot():\n print bar\n\n'
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
def foor(x):
print bar
print x + 10
def g(u):
print
def h(rt,o):
assert(rt==12)
--------------------
'def foor(x):\n\n\n print bar\n print x + 10\n def g(u):\n print\n\n def h(rt,o):\n assert(rt==12)\n'
is a commented definition function
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
def tabulae(x):
print bar
print x + 10
def g(u):
print
def h(rt,o):
assert(rt==12)
--------------------
'def tabulae(x):\n\n\n\tprint bar\n\tprint x + 10\n\tdef g(u):\n\t\tprint\n\n\tdef h(rt,o):\n\t\tassert(rt==12)\n'
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
def inzide(x):
print baracuda
print x + 10
def gululu(u):
print
def hortense(rt,o):
assert(rt==12)
--------------------
' def inzide(x):\n\n\n print baracuda\n print x + 10\n def gululu(u):\n print\n\n def hortense(rt,o):\n assert(rt==12)\n\n\n\n'
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
def oneline(x): return 2*x
--------------------
'def oneline(x): return 2*x\n'
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
def scroutchibi(h%,n():245sqfg srot b#
--------------------
'def scroutchibi(h%,n():245sqfg srot b#\n'
isn't a valid definition of a function
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

Categories