Setting an accessible Python function's variable from outside a function - python

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

Related

printing variable inside a def, inside a class

I am new to object oriented programming, what I want to do basically is print a variable inside a def which is in its turn inside a class, I think there's probably a very simple answer but I just can't figure it out, thanks for the assistance, here's my code:
class test():
def test2():
x = 12
print(test.test2.x)
this gives me the following error:
Traceback (most recent call last):
File "/home/vandeventer/x.py", line 4, in <module>
print(test.test2.x)
AttributeError: 'function' object has no attribute 'x'
when I try:
class test():
def test2():
x = 12
print(test.x)
I get:
Traceback (most recent call last):
File "/home/vandeventer/x.py", line 4, in <module>
print(test.x)
AttributeError: type object 'test' has no attribute 'x'
You can't do what you want; local variables only exist during the lifetime of a function call. They are not attributes of the function nor are they available outside of the call in any other way. They are created when you call the function, destroyed again when the function exits.
You can set attributes on function objects, but those are independent of locals:
>>> class test():
... def test2():
... pass
... test2.x = 12
...
>>> test.test2.x
12
If you need to keep a value a function produced, either return the value, or assign it to something that lasts longer than the function. Attributes on the instance are a common place to keep things:
>>> class Foo():
... def bar(self):
... self.x = 12
...
>>> f = Foo()
>>> f.bar()
>>> f.x
12
If you want to print that value you could also use a return statement and the self parameter.
class test():
def test2(self):
x = 12
return x
test = test()
print(test.test2())
I do not know if this fully answers your questions but it is a way to print your x.

How to protect class attributes in Python?

How to protect class from adding attributes in that way:
class foo(object):
pass
x=foo()
x.someRandomAttr=3.14
If you want an immutable object, use the collections.namedtuple() factory to create a class for you:
from collections import namedtuple
foo = namedtuple('foo', ('bar', 'baz'))
Demo:
>>> from collections import namedtuple
>>> foo = namedtuple('foo', ('bar', 'baz'))
>>> f = foo(42, 38)
>>> f.someattribute = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'foo' object has no attribute 'someattribute'
>>> f.bar
42
Note that the whole object is immutable; you cannot change f.bar after the fact either:
>>> f.bar = 43
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
Override the __setattr__ method:
>>> class Foo(object):
def __setattr__(self, var, val):
raise TypeError("You're not allowed to do this")
...
>>> Foo().x = 1
Traceback (most recent call last):
File "<ipython-input-31-be77d2b3299a>", line 1, in <module>
Foo().x = 1
File "<ipython-input-30-cb58a6713335>", line 3, in __setattr__
raise TypeError("You're not allowed to do this")
TypeError: You're not allowed to do this
Even Foo's subclasses will raise the same error:
>>> class Bar(Foo):
pass
...
>>> Bar().x = 1
Traceback (most recent call last):
File "<ipython-input-35-35cd058c173b>", line 1, in <module>
Bar().x = 1
File "<ipython-input-30-cb58a6713335>", line 3, in __setattr__
raise TypeError("You're not allowed to do this")
TypeError: You're not allowed to do this

global variable usage

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

Lambdas, callable class instances, and scoping; why doesn't it work in Python 2.7?

Can someone explain to me why the following code produces the exception it does?
>>> class CallableKlass(object):
def __init__(self, callible):
self.callible = callible
def __call__(self, arg):
return self.callible(arg)
>>> class Klass(object):
d = {'foo': 'bar'}
m = CallableKlass(lambda x: d[x])
>>> Klass.m('foo')
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
Klass.m('foo')
File "<pyshell#5>", line 5, in __call__
return self.callible(arg)
File "<pyshell#9>", line 3, in <lambda>
m = CallableKlass(lambda x: d[x])
NameError: global name 'd' is not defined
The class namespace (stuff defined directly in the class body) is not accessible from within functions defined in that namespace. A lambda is just a function, so this applies to lambdas as well. Your CallableKlass is a red herring. The behavior is the same in this simpler case:
>>> class Foo(object):
... d = {'foo': 'bar'}
... (lambda stuff: d[stuff])('foo')
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
class Foo(object):
File "<pyshell#3>", line 3, in Foo
(lambda stuff: d[stuff])('foo')
File "<pyshell#3>", line 3, in <lambda>
(lambda stuff: d[stuff])('foo')
NameError: global name 'd' is not defined
>>> class Foo(object):
... d = {'foo': 'bar'}
... def f(stuff):
... d[stuff]
... f('foo')
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
class Foo(object):
File "<pyshell#4>", line 5, in Foo
f('foo')
File "<pyshell#4>", line 4, in f
d[stuff]
NameError: global name 'd' is not defined
you should use Klass.d inside lambda, as the variables declared inside a class becomes attribute of that class.
That's why your program raised that error, as it is not able to find anything like d in global variables.:
class Klass(object):
d = {'foo': 'bar'}
m = CallableKlass(lambda x: Klass.d[x])

Impossible to set an attribute to a string?

Usually, you can set an arbitrary attribute to a custom object, for instance
----------
>>> a=A()
>>> a.foo=42
>>> a.__dict__
{'foo': 42}
>>>
----------
On the other hand, you can't do the same binding with a string object :
----------
>>> a=str("bar")
>>> a.foo=42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'foo'
>>> a.__dict__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__dict__'
>>>
----------
Why ?
Because the str type is a type wich does not has an attribute dict. From the docs, "Classes" section:
A class has a namespace implemented by a dictionary object.
Class attribute references are translated to lookups in this
dictionary, e.g., C.x is translated to C.__dict__["x"]
You can also enforce something similar on custom objects:
>>> class X(object):
... __slots__=('a', )
...
>>> a = X()
>>> a.a = 2
>>> a.foo = 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'X' object has no attribute 'foo'
In general, you should not be setting nor modifying fields of objects that you are not supposed to. The documentation of the specific data type should reference you what fields are available for public modification.
For example, an ReadOnlyPoint object, where the x and y coordinates are set only on object construction:
>>> class ReadOnlyPoint(object):
... __slots__ = ('_x', '_y')
... def __init__(self, x, y):
... self._x = x
... self._y = y
... def getx(self):
... return self._x
... def gety(self):
... return self._y
... x = property(getx)
... y = property(gety)
...
>>> p = ReadOnlyPoint(2, 3)
>>> print p.x, p.y
2 3
>>> p.x = 9
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>> p._x = 9
>>> print p.x, p.y
9 3
While the x and y properties are read-only, accessing the object internals allows you to alter the object's state.
The inhability to add a new field to an str object is an implementation detail, specific to the Python version that you are using.
http://docs.python.org/reference/datamodel.html
If the class has a setattr() or delattr() method, this is
called instead of updating the instance dictionary directly.
http://docs.python.org/reference/datamodel.html#object.setattr

Categories