Why must a new global variable be created to reference the current class instance in “exec”?
I have a class that contains ~20 methods, and in def __init__(self, ...):
I have to call many of these methods (~9) but I didn't want to have to call each individual method one by one.
So I took the easy way out and created two list list comprehensions, that use exec
to call each method:
[exec("self.create%s()" % x) for x in "ArticleObjects SeriesObjects ArticleList SearchList".split(" ")]
[exec("self.compile%sPage(self)" % x) for x in "About Screenshots Search Contact Articles".split(" ")]
When I ran this code using python3 filename.py
I got an error, that read:
NameError: name 'self' is not defined
Through trial and error I found that; in order to get this code to work I had to create a copy of self
called instance
and make the new instance
variable a global variable and then call the method using ClassName.methodName(instance)
instead of self.methodName()
:
With the working code being:
global instance; instance = self
[exec("ClassNamecreate%s(instance)" % x) for x in "ArticleObjects SeriesObjects ArticleList SearchList".split(" ")]
[exec("ClassName.compile%sPage(instance)" % x) for x in "About Screenshots Search Contact Articles".split(" ")]
Why is this? Why is the self
variable undefined in exec
despite it being available to the scope that exec
is being called in?
Update: I'm using Python 3.6.7
python class global-variables instance self
add a comment |
I have a class that contains ~20 methods, and in def __init__(self, ...):
I have to call many of these methods (~9) but I didn't want to have to call each individual method one by one.
So I took the easy way out and created two list list comprehensions, that use exec
to call each method:
[exec("self.create%s()" % x) for x in "ArticleObjects SeriesObjects ArticleList SearchList".split(" ")]
[exec("self.compile%sPage(self)" % x) for x in "About Screenshots Search Contact Articles".split(" ")]
When I ran this code using python3 filename.py
I got an error, that read:
NameError: name 'self' is not defined
Through trial and error I found that; in order to get this code to work I had to create a copy of self
called instance
and make the new instance
variable a global variable and then call the method using ClassName.methodName(instance)
instead of self.methodName()
:
With the working code being:
global instance; instance = self
[exec("ClassNamecreate%s(instance)" % x) for x in "ArticleObjects SeriesObjects ArticleList SearchList".split(" ")]
[exec("ClassName.compile%sPage(instance)" % x) for x in "About Screenshots Search Contact Articles".split(" ")]
Why is this? Why is the self
variable undefined in exec
despite it being available to the scope that exec
is being called in?
Update: I'm using Python 3.6.7
python class global-variables instance self
list comprehension in exec with empty locals: NameError
– Aran-Fey
Nov 25 '18 at 16:50
1
Apart from the unnecessary use ofexec
, it's an anti-pattern to use a list comp purely for side effects. If you don't need the resulting list, then please use a proper loop.
– PM 2Ring
Nov 25 '18 at 18:15
add a comment |
I have a class that contains ~20 methods, and in def __init__(self, ...):
I have to call many of these methods (~9) but I didn't want to have to call each individual method one by one.
So I took the easy way out and created two list list comprehensions, that use exec
to call each method:
[exec("self.create%s()" % x) for x in "ArticleObjects SeriesObjects ArticleList SearchList".split(" ")]
[exec("self.compile%sPage(self)" % x) for x in "About Screenshots Search Contact Articles".split(" ")]
When I ran this code using python3 filename.py
I got an error, that read:
NameError: name 'self' is not defined
Through trial and error I found that; in order to get this code to work I had to create a copy of self
called instance
and make the new instance
variable a global variable and then call the method using ClassName.methodName(instance)
instead of self.methodName()
:
With the working code being:
global instance; instance = self
[exec("ClassNamecreate%s(instance)" % x) for x in "ArticleObjects SeriesObjects ArticleList SearchList".split(" ")]
[exec("ClassName.compile%sPage(instance)" % x) for x in "About Screenshots Search Contact Articles".split(" ")]
Why is this? Why is the self
variable undefined in exec
despite it being available to the scope that exec
is being called in?
Update: I'm using Python 3.6.7
python class global-variables instance self
I have a class that contains ~20 methods, and in def __init__(self, ...):
I have to call many of these methods (~9) but I didn't want to have to call each individual method one by one.
So I took the easy way out and created two list list comprehensions, that use exec
to call each method:
[exec("self.create%s()" % x) for x in "ArticleObjects SeriesObjects ArticleList SearchList".split(" ")]
[exec("self.compile%sPage(self)" % x) for x in "About Screenshots Search Contact Articles".split(" ")]
When I ran this code using python3 filename.py
I got an error, that read:
NameError: name 'self' is not defined
Through trial and error I found that; in order to get this code to work I had to create a copy of self
called instance
and make the new instance
variable a global variable and then call the method using ClassName.methodName(instance)
instead of self.methodName()
:
With the working code being:
global instance; instance = self
[exec("ClassNamecreate%s(instance)" % x) for x in "ArticleObjects SeriesObjects ArticleList SearchList".split(" ")]
[exec("ClassName.compile%sPage(instance)" % x) for x in "About Screenshots Search Contact Articles".split(" ")]
Why is this? Why is the self
variable undefined in exec
despite it being available to the scope that exec
is being called in?
Update: I'm using Python 3.6.7
python class global-variables instance self
python class global-variables instance self
edited Nov 25 '18 at 16:29
LogicalBranch
asked Nov 25 '18 at 16:23
LogicalBranchLogicalBranch
141117
141117
list comprehension in exec with empty locals: NameError
– Aran-Fey
Nov 25 '18 at 16:50
1
Apart from the unnecessary use ofexec
, it's an anti-pattern to use a list comp purely for side effects. If you don't need the resulting list, then please use a proper loop.
– PM 2Ring
Nov 25 '18 at 18:15
add a comment |
list comprehension in exec with empty locals: NameError
– Aran-Fey
Nov 25 '18 at 16:50
1
Apart from the unnecessary use ofexec
, it's an anti-pattern to use a list comp purely for side effects. If you don't need the resulting list, then please use a proper loop.
– PM 2Ring
Nov 25 '18 at 18:15
list comprehension in exec with empty locals: NameError
– Aran-Fey
Nov 25 '18 at 16:50
list comprehension in exec with empty locals: NameError
– Aran-Fey
Nov 25 '18 at 16:50
1
1
Apart from the unnecessary use of
exec
, it's an anti-pattern to use a list comp purely for side effects. If you don't need the resulting list, then please use a proper loop.– PM 2Ring
Nov 25 '18 at 18:15
Apart from the unnecessary use of
exec
, it's an anti-pattern to use a list comp purely for side effects. If you don't need the resulting list, then please use a proper loop.– PM 2Ring
Nov 25 '18 at 18:15
add a comment |
3 Answers
3
active
oldest
votes
There's lots of good suggestions here for how to avoid the exec statement (which is generally bad), but to answer your question about why this happens, it's got more to do with the list comprehension. List comprehensions create a new scope, and when you call exec without a globals or locals argument, it uses the locals()
function:
Note: The default locals act as described for function locals() below
Source
Here you can see what the results of the locals()
function look like from within a list comprehension:
class Sample:
def __init__(self):
k = 4
print(locals())
exec("print(locals())")
[print(locals()) for x in range(1)]
[exec("print(locals())") for x in range(1)]
Sample()
output:
{'k': 4, 'self': <__main__.Sample object at 0x00000000030295C0>}
{'k': 4, 'self': <__main__.Sample object at 0x00000000030295C0>}
{'x': 0, '.0': <range_iterator object at 0x00000000030019F0>}
{'x': 0, '.0': <range_iterator object at 0x00000000030019F0>}
So, locals()
is the same inside or outside the exec. It's the list comprehension that changes it. Only, when you're outside an exec statement, the interpreter can fall past the locals of the list comprehension and find self in the outer scope. No such luck once you call exec.
Thanks for the answer, I've replaced theexec
and now I know what was causing my problem.
– LogicalBranch
Nov 26 '18 at 20:00
add a comment |
Using getattr
is simpler (and usually safer) than exec
. Try something along these lines:
def __init__(self):
suffixes = ["ArticleObjects", "SeriesObjects", ...]
for suffix in suffixes:
method = getattr(self, "create" + suffix)
method()
add a comment |
I wouldn't use exec
for this. While it may be the shortest version, it might also confuse both collaborators and code analysis tools. I'd use something like this instead:
class Test:
def __init__(self):
for f in (self.createA, self.createB, self.createC):
f()
def createA(self):
print("A")
def createB(self):
print("B")
def createC(self):
print("C")
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53469473%2fwhy-must-a-new-global-variable-be-created-to-reference-the-current-class-instanc%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
There's lots of good suggestions here for how to avoid the exec statement (which is generally bad), but to answer your question about why this happens, it's got more to do with the list comprehension. List comprehensions create a new scope, and when you call exec without a globals or locals argument, it uses the locals()
function:
Note: The default locals act as described for function locals() below
Source
Here you can see what the results of the locals()
function look like from within a list comprehension:
class Sample:
def __init__(self):
k = 4
print(locals())
exec("print(locals())")
[print(locals()) for x in range(1)]
[exec("print(locals())") for x in range(1)]
Sample()
output:
{'k': 4, 'self': <__main__.Sample object at 0x00000000030295C0>}
{'k': 4, 'self': <__main__.Sample object at 0x00000000030295C0>}
{'x': 0, '.0': <range_iterator object at 0x00000000030019F0>}
{'x': 0, '.0': <range_iterator object at 0x00000000030019F0>}
So, locals()
is the same inside or outside the exec. It's the list comprehension that changes it. Only, when you're outside an exec statement, the interpreter can fall past the locals of the list comprehension and find self in the outer scope. No such luck once you call exec.
Thanks for the answer, I've replaced theexec
and now I know what was causing my problem.
– LogicalBranch
Nov 26 '18 at 20:00
add a comment |
There's lots of good suggestions here for how to avoid the exec statement (which is generally bad), but to answer your question about why this happens, it's got more to do with the list comprehension. List comprehensions create a new scope, and when you call exec without a globals or locals argument, it uses the locals()
function:
Note: The default locals act as described for function locals() below
Source
Here you can see what the results of the locals()
function look like from within a list comprehension:
class Sample:
def __init__(self):
k = 4
print(locals())
exec("print(locals())")
[print(locals()) for x in range(1)]
[exec("print(locals())") for x in range(1)]
Sample()
output:
{'k': 4, 'self': <__main__.Sample object at 0x00000000030295C0>}
{'k': 4, 'self': <__main__.Sample object at 0x00000000030295C0>}
{'x': 0, '.0': <range_iterator object at 0x00000000030019F0>}
{'x': 0, '.0': <range_iterator object at 0x00000000030019F0>}
So, locals()
is the same inside or outside the exec. It's the list comprehension that changes it. Only, when you're outside an exec statement, the interpreter can fall past the locals of the list comprehension and find self in the outer scope. No such luck once you call exec.
Thanks for the answer, I've replaced theexec
and now I know what was causing my problem.
– LogicalBranch
Nov 26 '18 at 20:00
add a comment |
There's lots of good suggestions here for how to avoid the exec statement (which is generally bad), but to answer your question about why this happens, it's got more to do with the list comprehension. List comprehensions create a new scope, and when you call exec without a globals or locals argument, it uses the locals()
function:
Note: The default locals act as described for function locals() below
Source
Here you can see what the results of the locals()
function look like from within a list comprehension:
class Sample:
def __init__(self):
k = 4
print(locals())
exec("print(locals())")
[print(locals()) for x in range(1)]
[exec("print(locals())") for x in range(1)]
Sample()
output:
{'k': 4, 'self': <__main__.Sample object at 0x00000000030295C0>}
{'k': 4, 'self': <__main__.Sample object at 0x00000000030295C0>}
{'x': 0, '.0': <range_iterator object at 0x00000000030019F0>}
{'x': 0, '.0': <range_iterator object at 0x00000000030019F0>}
So, locals()
is the same inside or outside the exec. It's the list comprehension that changes it. Only, when you're outside an exec statement, the interpreter can fall past the locals of the list comprehension and find self in the outer scope. No such luck once you call exec.
There's lots of good suggestions here for how to avoid the exec statement (which is generally bad), but to answer your question about why this happens, it's got more to do with the list comprehension. List comprehensions create a new scope, and when you call exec without a globals or locals argument, it uses the locals()
function:
Note: The default locals act as described for function locals() below
Source
Here you can see what the results of the locals()
function look like from within a list comprehension:
class Sample:
def __init__(self):
k = 4
print(locals())
exec("print(locals())")
[print(locals()) for x in range(1)]
[exec("print(locals())") for x in range(1)]
Sample()
output:
{'k': 4, 'self': <__main__.Sample object at 0x00000000030295C0>}
{'k': 4, 'self': <__main__.Sample object at 0x00000000030295C0>}
{'x': 0, '.0': <range_iterator object at 0x00000000030019F0>}
{'x': 0, '.0': <range_iterator object at 0x00000000030019F0>}
So, locals()
is the same inside or outside the exec. It's the list comprehension that changes it. Only, when you're outside an exec statement, the interpreter can fall past the locals of the list comprehension and find self in the outer scope. No such luck once you call exec.
edited Nov 25 '18 at 17:08
answered Nov 25 '18 at 17:01
R. DavidsonR. Davidson
17019
17019
Thanks for the answer, I've replaced theexec
and now I know what was causing my problem.
– LogicalBranch
Nov 26 '18 at 20:00
add a comment |
Thanks for the answer, I've replaced theexec
and now I know what was causing my problem.
– LogicalBranch
Nov 26 '18 at 20:00
Thanks for the answer, I've replaced the
exec
and now I know what was causing my problem.– LogicalBranch
Nov 26 '18 at 20:00
Thanks for the answer, I've replaced the
exec
and now I know what was causing my problem.– LogicalBranch
Nov 26 '18 at 20:00
add a comment |
Using getattr
is simpler (and usually safer) than exec
. Try something along these lines:
def __init__(self):
suffixes = ["ArticleObjects", "SeriesObjects", ...]
for suffix in suffixes:
method = getattr(self, "create" + suffix)
method()
add a comment |
Using getattr
is simpler (and usually safer) than exec
. Try something along these lines:
def __init__(self):
suffixes = ["ArticleObjects", "SeriesObjects", ...]
for suffix in suffixes:
method = getattr(self, "create" + suffix)
method()
add a comment |
Using getattr
is simpler (and usually safer) than exec
. Try something along these lines:
def __init__(self):
suffixes = ["ArticleObjects", "SeriesObjects", ...]
for suffix in suffixes:
method = getattr(self, "create" + suffix)
method()
Using getattr
is simpler (and usually safer) than exec
. Try something along these lines:
def __init__(self):
suffixes = ["ArticleObjects", "SeriesObjects", ...]
for suffix in suffixes:
method = getattr(self, "create" + suffix)
method()
answered Nov 25 '18 at 16:29
PiotrPiotr
64976
64976
add a comment |
add a comment |
I wouldn't use exec
for this. While it may be the shortest version, it might also confuse both collaborators and code analysis tools. I'd use something like this instead:
class Test:
def __init__(self):
for f in (self.createA, self.createB, self.createC):
f()
def createA(self):
print("A")
def createB(self):
print("B")
def createC(self):
print("C")
add a comment |
I wouldn't use exec
for this. While it may be the shortest version, it might also confuse both collaborators and code analysis tools. I'd use something like this instead:
class Test:
def __init__(self):
for f in (self.createA, self.createB, self.createC):
f()
def createA(self):
print("A")
def createB(self):
print("B")
def createC(self):
print("C")
add a comment |
I wouldn't use exec
for this. While it may be the shortest version, it might also confuse both collaborators and code analysis tools. I'd use something like this instead:
class Test:
def __init__(self):
for f in (self.createA, self.createB, self.createC):
f()
def createA(self):
print("A")
def createB(self):
print("B")
def createC(self):
print("C")
I wouldn't use exec
for this. While it may be the shortest version, it might also confuse both collaborators and code analysis tools. I'd use something like this instead:
class Test:
def __init__(self):
for f in (self.createA, self.createB, self.createC):
f()
def createA(self):
print("A")
def createB(self):
print("B")
def createC(self):
print("C")
answered Nov 25 '18 at 16:31
FelixFelix
3,2212930
3,2212930
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53469473%2fwhy-must-a-new-global-variable-be-created-to-reference-the-current-class-instanc%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
list comprehension in exec with empty locals: NameError
– Aran-Fey
Nov 25 '18 at 16:50
1
Apart from the unnecessary use of
exec
, it's an anti-pattern to use a list comp purely for side effects. If you don't need the resulting list, then please use a proper loop.– PM 2Ring
Nov 25 '18 at 18:15