The following code works as expected
name = "Test"
myname = ""
exec('myname ="' + name + '"')
print(myname)
Which shows as result:
Test
Problem
However, if I define the same within a function in a class and execute it I get as result an empty string.
class new(object):
def __init__(self, name):
self.print(name)
def print(self, name):
myname = ""
exec('myname ="' + name + '"')
print(myname)
a = new("My name")
The above is a toy example code of a bigger code.
Question
How to define the function so as to get the same result? The exec function is actually needed in the bigger code.
You can pass a dictionary as the globals (or locals) for exec.
def print(self, name):
d = {"myname": ""}
exec('myname ="' + name + '"', d)
print(d["myname"])
Related
class Student:
def __init__(self,m1,m2):
self.m1=m1
self.m2=m2
def add(self,s1,s2):
summ1 = self.m1 + self.m2
summ2 = s1.m1 + s1.m2
summ3 = s2.m1 + s2.m2
std1=Student(89,99)
std2=Student(95,99)
std3=Student(95,99)
std1.add(std2,std3)
print(summ1)
print(summ2)
print(summ3)
why summ1 is not getting printed even it is defined in function?
Well summ1,summ2,summ3 are defined in add function when I try to print them this code is giving me error.
Error is
NameError: name 'summ1' is not defined
summ1,summ2,summ3 are local variables defined in the function add and they are not visible outside of this function. If you replace them by self.summ1, self.summ2, self.summ3, then print(std1.summ1) etc. will work.
As AnkurSaxena said, you can not access your variables the way you try it.
The following code should solve your problem:
class Student:
def __init__(self,m1,m2):
self.m1=m1
self.m2=m2
self.summ1 = None
self.summ2 = None
self.summ3 = None
def add(self,s1,s2):
self.summ1 = self.m1 + self.m2
self.summ2 = s1.m1 + s1.m2
self.summ3 = s2.m1 + s2.m2
std1=Student(89,99)
std2=Student(95,99)
std3=Student(95,99)
std1.add(std2,std3)
print(std1.summ1)
print(std1.summ2)
print(std1.summ3)
I am trying to run some code that allows me to either call the name Student or Programmer from the class I called Master_programmer. Here is the code I used.
class Master_programmer:
capabilities = []
student = "SoloLearn Student"
programmer = "Programmer"
def Student(self):
return 'SoloLearn Student'
def Programmer(self):
return 'Programmer'
def __init__(self, name):
self.name = name
def add_capabilities(self, capability):
self.capabilities.append(capability)
m1 = Master_programmer(programmer)
print(m1.Student, m1.Programmer)
a.add_capabilities('Stay Inspired')
b.add_capabilities('Find Clients')
b.capability
After running the above code, I get the following error
Traceback (most recent call last):
File "./Playground/file0.py", line 21, in <module>
m1 = Master_programmer(programmer)
NameError: name 'programmer' is not defined
Now, my question is, how do I get my code to deliver the expected results? e.g when I request for the Name 'programmer' to be called up, I expect it to bring up Programmer and then allow me to add capabilities to the programmer like "Find Clients". And for Student it must be "Stay Inspired".
I guess the below code and its comments will answer your question.
class Master_programmer:
STATIC_VARIABLE_ONE_FOR_EVERY_INSTANCES = 'This is Static Var'
def __init__(self, name):
self.name = name
self.capabilities = []
self.student = "SoloLearn Student"
self.programmer = "Programmer"
def get_student(self):
return self.student
def get_programmer(self):
return self.programmer
def add_capabilities(self, capability):
self.capabilities.append(capability)
# Create instance for your class and name it coder (or whatever you like)
coder = Master_programmer('Replace me with student name')
# to call coder object's variable
# you need to call it by object name just like below
print('capabilities: ', coder.capabilities)
print(coder.programmer)
print(coder.student)
coder.add_capabilities('Stay Inspired')
coder.add_capabilities('Find Clients')
print(coder.get_student())
print(coder.get_programmer())
print('capabilities: ', coder.capabilities)
print()
# you can invoke Static variables usign directly class name
# you can invoke usign instance name as well but, it is not convention
print(Master_programmer.STATIC_VARIABLE_ONE_FOR_EVERY_INSTANCES)
print()
# if you change Static member, it will get change for all of your instances
coder_2 = Master_programmer('Replace me with student name')
Master_programmer.STATIC_VARIABLE_ONE_FOR_EVERY_INSTANCES = 'changed'
print()
# print static var using both ways
print(Master_programmer.STATIC_VARIABLE_ONE_FOR_EVERY_INSTANCES)
print(coder.STATIC_VARIABLE_ONE_FOR_EVERY_INSTANCES)
print(coder_2.STATIC_VARIABLE_ONE_FOR_EVERY_INSTANCES)
m1 = Master_programmer(programmer)
print(m1.Student, m1.Programmer)
Is calling the variable programmer if you wan to refer to programmer = "Programmer" in the Master_programmer class you need to use Master_programmer.programmer instead.
Though your code will later crash if you don't initialse a and b too since you need to define them too like normal variables e.g. a = Master_programmer("EEZi") to call them and/ or work with them
Thank you all for your answers. Here is the final code that I went with and it works really well. Many Thanks to you.
class Master_programmer:
STATIC_VARIABLE_ONE_FOR_EVERY_INSTANCES = 'This is Static Var'
def __init__(self, name):
self.name = name
self.capabilities = []
self.student = "SoloLearn Student"
self.programmer = "Programmer"
def get_student(self):
return self.student
def get_programmer(self):
return self.programmer
def add_capabilities(self, capability):
self.capabilities.append(capability)
coder = Master_programmer('EEZi')
coder.add_capabilities('Stay Inspired!')
coder.add_capabilities('Find Clients')
a = coder.get_student()
b = coder.get_programmer()
capabilities = coder.capabilities
for i in range(0,1):
print(a)
print("Listen here, just", coder.capabilities[0], "\n")
print(b)
print("Hustle hard and", coder.capabilities[1])
I try to get the list of class from python file using python. After a few search, I get the code which I think it's work as follow
def get_class_from_file(class_obj, file, path='app', exclude=[]):
class_list = []
module = importlib.import_module(path + '.' + file)
for x in dir(module) :
app_cls = getattr( importlib.import_module(path + '.' + file), x )
try :
if app_cls and issubclass(app_cls, class_obj) and app_cls != class_obj and app_cls not in exclude:
class_list.append( (file, x) )
except TypeError :
pass
return class_list
However, I found out that the code don't get only the list of the class, but It still keep showing me the superclass of the class inside the file, here is example
file_1.py
class A:
pass
class B(A):
pass
file_2.py
class C(B):
pass
class D:
pass
when I call the function as
class_list = get_class_from_file(A, 'file_2')
I expect the result would be [C], but It return [C, B] as B is one of super class of C
Please help me fix this, I just want class inside the given file, not any superclass of them. By the way, I use exclude for fixing it at first, but It isn't give me a long run solution.
The problem is that imported modules are also found. You can check a class'
__module__ attribute to see if it originates from the current module or was imported into it.
You also have importlib.import_module(path + '.' + file) twice, I removed one of them. I renamed x to name.
def get_class_from_file(class_obj, file, path='app', exclude=[]):
class_list = []
module_path = path + '.' + file
module = importlib.import_module(module_path)
for name in dir(module) :
app_cls = getattr(module, name)
try:
if (issubclass(app_cls, class_obj) and
app_cls != class_obj and
app_cls not in exclude and
app_cls.__module__ == module_path):
class_list.append( (file, name) )
except TypeError:
# Not a class
pass
return class_list
I am having some problem accessing class instances. I am calling the class from a procedure, name of instance is defined in some variable. I want the instance name to be created of that value and then want to access it, but when i access it is giving error. Can some one please help to resolve this issue.
class myclass:
def __init__(self,object):
self.name = object
def mydef():
global a1
b = "a1"
b = myclass(b)
mydef()
print a1.name
Second Problem:
In my actual script, I have to create a large number of such instances from this function (around 100). So defining their name as global would be painful, is there a way i could access those instances outside function without having to declare them as global.
Modification:
class myclass:
def __init__(self,object,typename):
self.name = object
self.typeid = typename
def mydef():
file_han = open(file,"r")
while True:
line = file_han.readline()
if not line:
break
start = line.find('"')
end = line.find('"',start+1)
string_f = line[start+1:end]
myclass(string_f,'a11')
mydef(file)
print def.name
print def.typeid
File Contents are :
a11 "def"
a11 "ghi"
a11 "eff"
Here's how I'd do it. I don't know why you're messing around with globals, if you'd care to explain, I'll update my answer.
class Myclass(object):
def __init__(self, name):
self.name = name
def mydef():
return Myclass("a1")
a1 = mydef()
print a1.name
Gather your instances in a list:
instances = []
for x in range(1000):
instances.append(Myclass("Instance {0}".format(x)))
print instance[42].name
Note the changes:
Class names should be capitalized
Use object as the base class of your classes (since python 2.2, but no longer necessary in 3.x)
Don't shadow the built-in object with your parameter name
Just use the string "a1" directly as a parameter instead of assigning it to a variable
Return something from the function instead of passing the result by global variable
RE: Comment
You haven't said anything about the format of these files, so I'll just give an example where the file to be read contains one class name per line, and nothing else:
def mydef(filename):
ret = []
with open(filename) as f:
for line in f:
# Call `strip` on line to remove newline and surrounding whitespace
ret.append(Myclass(line.strip()))
return ret
So if you have several files and wish to add all your instances from all your files to a large list, do it like this:
instances = []
for filename in ["myfile1", "myfile2", "myfile3"]:
instances.extend(mydef(filename))
RE: OP Edit
def mydef(filename):
ret = []
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
ret.append(Myclass(string_f))
return ret
i = mydef("name_of_file")
RE: Comment
Oh, you want to access them by name. Then return a dict instead:
def mydef(filename):
ret = {}
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
ret[string_f] = Myclass(string_f)
return ret
i = mydef("name_of_file")
print i["ghi"].name # should print "ghi"
RE: Comment
If I understand you correctly, you want to have it both ways -- index by both line number and name. Well then why don't you return both a list and a dictionary?
def mydef(filename):
d = {}
L = []
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
instance = Myclass(string_f)
d[string_f] = instance
L.append(instance)
return L, d
L, d = mydef("name_of_file")
print d["ghi"].name
print L[3]
print L.index(d["ghi"])
You could use class as repository for your instances, for example
class Named(object):
def __init__(self,name):
self.name = name
def __new__(cls,name):
instance = super(type,cls).__new__(cls,name)
setattr(cls,name,instance)
return instance
def __repr__(self):
return 'Named[%s]'%self.name
Named('hello')
Named('x123')
Named('this is not valid attribute name, but also working')
print(Named.hello,Named.x123,getattr(Named,'this is not valid attribute name, but also working'))
What's the best way to pass a method and a method parameter to another method?
Is there a better way to do the following?
def method1(name)
return 'Hello ' + name
def method2(methodToCall, methodToCallParams, question):
greetings = methodToCall(methodToCallParams)
return greetings + ', ' + question
method2(method1, 'Sam', 'How are you?')
If you want to package the invocation up in one hit, you can use the functools module:
from functools import partial
def some_function(param_one, param_two):
print "Param One: %s" % param_one
print "Param Two: %s" % param_two
def calling_function(target):
target()
calling_function(partial(some_function, "foo", "bar"))
You can do tweakier things with functools.partial too, such as binding only some parameters, leaving you with a function with a new signature. It's overkill in a lot of cases to use it but it certainly has it's place.
You could do it this way:
def method1(name):
def wrapper():
return 'Hello ' + name
return wrapper
def method2(method, question):
output = method()
return output + ', ' + question
method2(method1(name = 'Sam'), 'How are you?')
You can of course pass some variables in the method() call too:
def method1(name):
def wrapper(greeting):
return greeting + name
return wrapper
def method2(method, question):
output = method(greeting = 'Hello ')
return output + ', ' + question
method2(method1(name = 'Sam'), 'How are you?')
You can used functools.partial to do this, as jkp pointed out
However, functools is new in Python 2.5, so to handle this in the past I used the following code (this code is in the Python docs for functools.partial, in fact).
# functools is Python 2.5 only, so we create a different partialfn if we are
# running a version without functools available
try:
import functools
partialfn = functools.partial
except ImportError:
def partialfn(func, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*(args + fargs), **newkeywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
Another option, if you are working on a Python version pre 2.5 is to use a lambda as a closure:
def some_func(bar):
print bar
def call_other(other):
other()
call_other(lambda param="foo": some_func(param))
HTH
You're thinking of currying, where you bind a function and arguments together to be called later. Usually currying is used so that you can add additional arguments at the time the function is actually called.
Rather than re-write the wheel, here's a link to an example: http://code.activestate.com/recipes/52549/.
If, however, the case you've mocked up in the question really is that simple, you can pass a list of args as positional parameters, or a list of kwargs as named parameters, to another function.
def method1(name):
return 'Hello %s' % name
args = ['Joe']
method1(*args)
def method1a(name=None, salutation=None):
return 'Hello %s %s' % (name, salutation)
kwargs = {'name':'Joe', 'salutation':'Mr'}
method1a(**kwargs)