I have one basic question,I am declaring xmlfile as global in xml function,can I use it in another subroutine without any issues?does the order of subroutines matter?
def xml():
global xmlfile
file = open('config\\' + productLine + '.xml','r')
xmlfile=file.read()
def table():
parsexml(xmlfile)
The order in which the functions are written does not matter.
The value of xmlfile will be determined by the order in which the functions are called.
However, it is generally better to avoid reassigning values to globals inside of functions -- it makes analyzing the behavior of functions more complicated. It is better to use function arguments and/or return values, (or perhaps use a class and make the variable a class attribute):
def xml():
with open('config\\' + productLine + '.xml','r') as f:
return f.read()
def table():
xmlfile = xml()
parsexml(xmlfile)
First of all, I completely agree with the other comments about avoiding global variables. You should start by redesigning to avoid them. But to answer your question:
The order of definitions of the subroutine doesn't matter, the order in which you call them does:
>>> def using_func():
... print a
...
>>> using_func()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in using_func
NameError: global name 'a' is not defined
>>> def defining_func():
... global a
... a = 1
...
>>> using_func()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in using_func
NameError: global name 'a' is not defined
>>> defining_func()
>>> using_func()
1
Related
When using the builtin globals() function it seems to do this: when I try to access a global value that I set to change from within the class (not a class global as it would be overwritten per initialization. The global I made is supposed to be kept and used no matter how many initializations of the class there are.
Like some example code:
somevalue = False
class SomeClass(object):
"""
...
"""
def __init__(self):
self.change_global_value()
def change_global_value(self):
"""
Changes global module values that this class is in.
"""
globals().somevalue = True # Error. (line 14)
self.__module__.globals().somevalue = True # Error. (line 14, after some changes)
somevalue = True # Error as well. (line 14, after some more changes)
The Tracebacks that happen:
Traceback (most recent call last):
File "<stdin>", line 14, in <module>
globals().somevalue = True # Error.
AttributeError: 'dict' object has no attribute 'somevalue'
Traceback (most recent call last):
File "<stdin>", line 14, in <module>
self.__module__.globals().somevalue = True # Error.
AttributeError: 'str' object has no attribute 'globals'
Traceback (most recent call last):
File "<stdin>", line 14, in change_global_value
somevalue = True # Error as well.
UnboundLocalError: local variable 'somevalue' referenced before assignment
globals() returns a dict so you can assign a new value using globals()['somevalue'] = 'newvalue':
somevalue = False
class SomeClass(object):
"""
...
"""
def __init__(self):
self.change_global_value()
def change_global_value(self):
"""
Changes global module values that this class is in.
"""
globals()['somevalue'] = True
The preferred form is just defining a variable as global:
somevalue = False
class SomeClass(object):
"""
...
"""
def __init__(self):
self.change_global_value()
def change_global_value(self):
"""
Changes global module values that this class is in.
"""
global somevalue
somevalue = True
Note this is usually a bad practice in the general case and especially in classes.
I am curious how I can assign a variable from outside a function object. Before I tried it, I thought I knew how it can be done.
>>> def f():
... print(x)
...
>>> f.x=2
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f
NameError: name 'x' is not defined
>>>
I then tried:
>>> class c:
... def f(self):
... print(x)
...
>>> y=c();y.x=2;y.f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f
NameError: name 'x' is not defined
The same error. Now, I thought, this just has to work:
>>> class c:
... def makef(self):
... return lambda x=x: print(x)
...
>>> y = c();y.x = 2;y.makef()()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in makef
NameError: name 'x' is not defined
Alas, it did not. How can I assign a variable accessible to a function after the function has been defined? This is just a curiosity. There's really no reason (that I can think of) for not just passing a parameter.
class Name:
def __init__(self):
self.x = None
def f(self):
print self.x
a = Name()
a.x = 'Value'
a.f()
output
$ Value
I discovered a way of doing what I was trying to accomplish. I need to modify the object's dictionary:
>>> def f():
... print(x)
...
>>> f.__dict__['x'] = 2
>>> f()
2
Basically if you define your variable in the main program, you can then use the global keyword to reference it.
bah = 1
def function():
global bah
bah = 2
So I've looked at similar questions, and I've found some solutions to this, but I can't quite figure out how to do this.
What I'm trying to do is add a method to a class from a string. I can do this with the setattr() method, but that won't let me use self as an attribute in the extra method. Here's an example: (and I apologize for the variable names, I always use yolo when I'm mocking up an idea)
class what:
def __init__(self):
s = 'def yolo(self):\n\tself.extra = "Hello"\n\tprint self.extra'
exec(s)
setattr(self,"yolo",yolo)
what().yolo()
returns this:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: yolo() takes exactly 1 argument (0 given)
and if s = 'def yolo():\n\tself.extra = "Hello"\n\tprint self.extra'
then I get this result:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 2, in yolo
NameError: global name 'self' is not defined
This essentially means that I cannot dynamically create methods for classes, which I know is bad practice and unpythonic, because the methods would be unable to access the variables that the rest of the class has access to.
I appreciate any help.
You have to bind your function to the class instance to turn it into a method. It can be done by wrapping it in types.MethodType:
import types
class what:
def __init__(self):
s = 'def yolo(self):\n\tself.extra = "Hello"\n\tprint self.extra'
exec(s)
self.yolo = types.MethodType(yolo, self)
what().yolo()
On a side note, why do you even need exec in this case? You can just as well write
import types
class what:
def __init__(self):
def yolo(self):
self.extra = "Hello"
print self.extra
self.yolo = types.MethodType(yolo, self)
what().yolo()
Edit: for the sake of completeness, one might prefer a solution through the descriptor protocol:
class what:
def __init__(self):
def yolo(self):
self.extra = "Hello"
print self.extra
self.yolo = yolo.__get__(self)
what().yolo()
Another way, seems more elegant to me:
class what:
pass
ld = {}
exec("""
def yolo(self):
self.extra = "Hello"
print(self.extra)
""", None, ld)
# print('locals got: {}'.format(ld))
for name, value in ld.items():
setattr(what, name, value)
what().yolo()
I want to make an #pure decorator for Python, part of this is being able to selectively disallow access to the global scope of the function.
Is there a way to programmatically change which dictionary thing serves as a function's global/external scope?
So for instance in the following I want to be able to intercept the access to f in h and throw an error, but I want to allow access to g because it's a pure function.
def f():
print("Non-pure function")
#pure
def g(i):
return i + 1
#pure
def h(i):
f()
return g(i)
You would have to create a new function object from the old one:
newfunc = type(h)(h.__code__, cleaned_globals, h.__name__, h.__defaults__, h.__closure__)
Here, cleaned_globals is a dictionary that is to be used as the global namespace for the newly created function object. All other arguments echo the original function's.
cleaned_globals could be based on a copy of h.__globals__, of course.
Demo:
>>> def h(i):
... f()
... return g(i)
...
>>> def g(i):
... return i + 1
...
>>> def f():
... print("Non-pure function")
...
>>> h(1)
Non-pure function
2
>>> cleaned_globals = {'g': g}
>>> newfunc = type(h)(h.__code__, cleaned_globals, h.__name__, h.__defaults__, h.__closure__)
>>> newfunc(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in h
NameError: global name 'f' is not defined
>>> cleaned_globals['f'] = lambda: print('Injected function')
>>> newfunc(1)
Injected function
2
Maybe my coffee is not strong enough this morning, but this behavior is confusing me right now:
>>> a = 'foo'
>>> def func1():
... print a
...
>>> def func2():
... print a
... a = 'bar'
...
>>> func1()
foo
>>> func2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in func2
UnboundLocalError: local variable 'a' referenced before assignment
(Note that it's the print a statement that's raising the error in func2(), not a = 'bar'.)
Can somebody explain to me what's going on here?
Because a is being set inside func2, Python assumes it's a local variable. Put a global a declaration before the print statement:
def func2():
global a
print a
a = 'bar'
See also this question about Python scoping rules.