python binding of variable to particular expression - python

I am developing a simple application which hava a file Constants.py containing all configuration, it is like this
x = y
during execution of program , the value of y changes , I want value of x o get updated too , automatically, this can be reffered as binding, how can I achieve this

In Python variable names point at values. x=y tells Python that the variable name x should point at the value that y is currently pointing at.
When you change y, then the variable name y points at a new value, while the variable name x still points at the old value.
You can not achieve what you want with plain variable names.
I like KennyTM's suggestion to define x as a function since it makes explicit that the value of x requires running some code (the lookup of the value of y).
However, if you want to maintain a uniform syntax (making all the constants accessible in the same way), then you could use a class with properties (attributes which call getter and setter functions):
Constants.py:
class BunchOConstants(object):
def __init__(self, **kwds):
self.__dict__.update(kwds)
#property
def x(self):
return self.y
#x.setter
def x(self,val):
self.y=val
const=BunchOConstants(y=10,z='foo')
Your script.py:
import Constants
const=Constants.const
print(const.y)
# 10
print(const.x)
# 10
Here you change the "constant" y:
const.y='bar'
And the "constant" x is changed too:
print(const.x)
# bar
You can change x also,
const.x='foo'
and y too gets changed:
print(const.y)
# foo

If you change the value (object) itself, then all references to it will be updated:
>>> a = []
>>> b = a # b refers to the same object a is refering right now
>>> a.append('foo')
>>> print b
['foo']
However, if you make the name point to some other object, then other names will still reference whatever they were referencing before:
>>> a = 15
>>> print b
['foo']
That's how python works. Names are just references to objects. You can make a name reference the same object another name is referencing, but you can't make a name reference another name. Name attribution using the = operator (a = 15) changes what a refers to, so it can't affect other names.

if your configuration values are inside a class, you could do something like this:
>>> class A(object):
... a = 4
... #property
... def b(self):
... return self.a
...
then, every time you access b, it will return the value of a.

There is a simple solution you can do. Just define a property and ask for the fget value you defined.
For example:
a = 7
#property
def b():
return a
if you ask for b, you will get something like this <property object at 0x1150418> but if you do b.fget(), you will obtain the value 7
Now try this:
a = 9
b.fget() # this will give you 9. The current value of a
You don't need to have a class with this way, otherwise, I think you will need it.

Related

Dynamic Object Naming and Class Calling in Python

I'm developing a programming language in Python where you can program a simulation of simple machines. I have written a function that takes some input, parses it, and finds out what the first word is.
Now, for the first word insert, I need to take the next words obj, name, x, and y.
obj: what type of simple machine it is
name: what you want to call the object
x: X coordinate on the graph
y: Y coordinate on the graph
I have already made a function nextword that iterates through the rest of the code and defines each variable as those words, so with the following code:
insert pulley JohnThePulley 3 4
It sees first word is insert, and calls my insert function.
Then, it sets obj to pulley, name to JohnThePulley, and so on.
However, now I need to make an object in the daughter class pulley, under the mother class simple_machines, that has the name JohnThePulley, etc.
The situation I'm in is that for the first word insert, for example, I don't know at all what the next word will be, from all the choices of daughter classes that they can call. I need to create the specified object along with the provided name, the provided X coordinate and the provided Y coordinate.
I have tried doing simple formatting in python using '{}'.format(name) or .format(obj), but those don't work.
# Insert function
def insert(code):
c = 4
syntax = np.array([obj, name, x, y])
nextword(parser.code_array, syntax, c)
objc += 1
return
# Nextword function, code_array[0] is insert, syntax is an array that
# contains all the variables that need to be defined for any function
def nextword(code_array, syntax, c):
assert len(code_array) == c + 1, "Too Many Words!"
for m in range(0, c):
syntax[m] = code_array[m + 1]
return
# Mother Class simple_machines with properties
class simple_machines:
def __init__(self, obj, name, x, y, coords):
self.obj = (
obj
) # what type of obj, in this case, pulley
self.name = name # name, JohnThePulley
self.x = x # 3 in this case
self.y = y # 4 in this case
self.coords = (x, y) # (3,4) in this case
return
# Pulley Class, here so I can later define special properties for a pulley
class pulley(simple_machines):
def __init__(self, name, x, y):
super(simple_machines, self).__init__()
return
# Code that I tried
def insert(code):
c = 4
syntax = np.array([obj, name, x, y])
nextword(parser.code_array, syntax, c)
"{}".format(name) = "{}".format(obj)(
name, x, y
) # this is what my
# instantiation would look like, formatting an object with name, then
# calling a class formatted with obj, and inserting their input of
# name,x,y as the properties
return
I expect an object in pulley to be created with the name JohnThePulley, and the coordinates X = 3 and Y = 4. What I'd like to result in, in simpler terms, is an object called name in a class called obj with the attributes name.x, name.y, etc
However, I get errors like:
NameError: name 'obj' is not defined
or:
SyntaxError: can't assign to function call
The first one apparently means that the word obj isn't being assigned, but the second one apparently means that I can't format a function name or format a variable name and define it as a function (even though I'm instantiating it as a class).
What am I doing wrong? How can I fix this?
name 'obj' is not defined is because obj is defined in another function. You have to use MYOBJECT.obj, not obj alone, and also keep a reference to MYOBJECT.
'{}'.format(obj)(name,x,y) doesn't mean anything, '{}'.format(obj) is a string and isn't callable.
SyntaxError: can't assign to function call is the actual problem you seem to be interested in. You could do globals()['{}'.format(name)] = stuff but it doesn't work for local variables and objects (and your linter is not going to like it).
If you want to do the same for objects you can use setattr(MYOBJECT, '{}'.format(name), '{}'.format(obj))
All of the solutions above are in technical terms considered "ugly" and what you're probably looking for is a dictionary, while it isn't OOP, dictionaries are used behind the scenes to handle exactly what you want to do with objects. An object without methods is essentially a just dictionary.
mydico = dict()
mydico[name] = obj
Also, if name is a string, then '{}'.format(name) is equivalent to name.

Python: Keep changes on a variable made within a function

I have a question on a fairly simple task in python, however, I didn't manage to find a solution. I would like to assign a new value to an already existing variable in python. However, the changes I am doing to the variable within the function don't stick to the variable.
Here is a simplified example of my problem:
y = 1
x = None
def test(var):
var = y
return var
test(x)
print(x)
The print simply returns none. So the changes I have done to the variable within the function are non permanent.
How can I make the changes on the input-variable of the function permanent?
Thanks in advance!
Variables in Python are just names which refer to objects. In an expression, the name is a stand-in for the actual object. Saying test(x) means "pass the object referred to by x into test". It does not mean "pass the symbol x into test".
In addition, re-assigning a name only changes what object that name refers to. It affects neither the object nor any of its aliases.
In short, the name var you modify inside test has no relation to x at all.
The preferred way to have a function change something is by reassigning the result:
x = 2
def change(var):
return var * 2
x = change(x) # x now refers to 4 instead of 2
print(x)
If you want to change a name outside a function, you can use the nonlocal and global keywords:
x = 2
def change_x():
global x
x = x * 2
change_x() # x now refers to 4 instead of 2
print(x)
While this can make some trivial problems easy to solve, it is generally a bad idea for larger programs. Using global variables means one can no longer use the function in isolation; results may depend on how often and in what order such a function is called.
If you have some self-contained group of values and means to modify them, a class can be used to describe this:
class XY:
def __init__(self, x, y):
self.x, self.y = x, y
def swap(self):
self.x, self.y = self.y, self.x
my_values = XY(None, 1)
print(my_values.x, my_values.y)
my_values.swap()
print(my_values.x, my_values.y)
In contrast to global variables, you can create as many isolated instances of classes as needed. Each instance can be worked on in isolation, without affecting the others.
You can also use mutable values to make changes visible to the outside. Instead of changing the name, you modify the value.
x = [2] # x is a mutable list, containing the value 2 at the moment
def change(var):
var[0] = 4 # change leading element of argument
change(x) # x now contains 4 instead of 2
print(x)
This is an example of passing variables to functions by value. By default, when you pass a variable to a function in Python, it is passed by value.
What it means is, that a new variable with a new scope is created with the same value of x. So, any change that happens to the new x is not reflected to the x outside the function's scope.
If you want to get the value from the function back, you can use the return statement (as you have used). return returns the value back from the function. However, in your example there is no variable to receive it. Hence, it is lost.
You would have to call the function as x = test(x). This ensures that x receives the value back from the function.

Changing a variable's value inside a class in python

I have a variable:
var_1 = 5
I pass it to a class:
class x():
def __init__(self, val):
self.class_var_1 = val
object_1 = x(var_1)
I want to change var_1's value using class x, but it won't change
object_1.class_var_1 = 3
print var_1
5
var_1 isn't copied to object_1.class_var_1 with a reference to var_1.
How do I change var_1's value by changing object_1.class_var_1's value?
Python int is immutable. The object can never change its value. Thus you need to re-bind the name to a different object. You'll need code like this:
var_1 = ...
Substitute whatever you like on the right hand side.

Difference between Class variables and Instance variables

I have already read many answers here on Stack Exchange like Python - why use "self" in a class?
After reading these answers, I understand that instance variables are unique to each instance of the class while class variables are shared across all instances.
While playing around, I found that this code which gives the output [1]:
class A:
x = []
def add(self):
self.x.append(1)
x = A()
y = A()
x.add()
print "Y's x: ", y.x
However, this code gives 10 as the output, when in my opinion it should be 11:
class A:
x = 10
def add(self):
self.x += 1
x = A()
y = A()
x.add()
print "Y's x: ", y.x
Why A class variable is not updated when I run x.add()? I am not very experienced in programming, so please excuse me.
Class variables are shadowed by instance attribute. This means that when looking up an attribute, Python first looks in the instance, then in the class. Furthermore, setting a variable on an object (e.g. self) always creates an instance variable - it never changes the class variable.
This means that when, in your second example you do:
self.x += 1
which is (in this case, see footnote) equivalent to:
self.x = self.x + 1
what Python does is:
Look up self.x. At that point, self doesn't have the instance attribute x, so the class attribute A.x is found, with the value 10.
The RHS is evaluated, giving the result 11.
This result is assigned to a new instance attribute x of self.
So below that, when you look up x.x, you get this new instance attribute that was created in add(). When looking up y.x, you still get the class attribute. To change the class attribute, you'd have to use A.x += 1 explicitly – the lookup only happens when reading the value of an attribute.
Your first example is a classical gotcha and the reason you shouldn't use class attributes as "default" values for instance attributes. When you call:
self.x.append(1)
there is no assignment to self.x taking place. (Changing the contents of a mutable object, like a list, is not the same as assignment.) Thus, no new instance attribute is added to x that would shadow it, and looking up x.x and y.x later on gives you the same list from the class attribute.
Note: In Python, x += y is not always equivalent to x = x + y. Python allows you to override the in-place operators separately from the normal ones for a type. This mostly makes sense for mutable objects, where the in-place version will directly change the contents without a reassignment of the LHS of the expression. However, immutable objects (such as numbers in your second example) do not override in-place operators. In that case, the statement does get evaluated as a regular addition and a reassignment, explaining the behaviour you see.
(I lifted the above from this SO answer, see there for more details.)

Making a variable cross module in Python - Within a class and function

I'm trying to use a variable in other python modules, like this:
In a.py:
class Names:
def userNames(self):
self.name = 'Richard'
In z.py:
import a
d = a.Names.name
print d
However this doesn't recognise the variable name and the following error is received:
AttributeError: type object 'Names' has no attribute 'name'
Thanks
There are lots of different scopes a variable can be bound to, which is what you seem to be confused about. Here are a few:
# a.py
a = 1 # (1) is module scope
class A:
a = 2 # (2) is class scope
def __init__(self, a=3): # (3) is function scope
self.a = a # (4) self.a is object scope
def same_as_class(self):
return self.a == A.a # compare object- and class-scope variables
def same_as_module(self):
return self.a == a # compare object- and module-scope variables
Now see how these different variables (I only called them all a to make the point, please don't do this for real) are named, and how they all have different values:
>>> import a
>>> a.a
1 # module scope (1)
>>> a.A.a
2 # class scope (2)
>>> obj1 = a.A() # note the argument defaults to 3 (3)
>>> obj1.a # and this value is bound to the object-scope variable (4)
3
>>> obj.same_as_class()
False # compare the object and class values (3 != 2)
>>> obj2 = a.A(2) # now create a new object, giving an explicit value for (3)
>>> obj2.same_as_class()
True
Note we can also change any of these values:
>>> obj1.same_as_module()
False
>>> obj1.a = 1
>>> obj1.same_as_module()
True
For reference, your z.py above should probably look like:
import a
n = a.Names()
d.userNames()
d = n.name
print d
because a.Name is a class, but you're trying to refer to an object-scope variable. An object is an instance of a class: I've called my instance n. Now I have an object, I can get at the object-scope variable. This is equivalent to Goranek's answer.
In terms of my previous example, you were trying to access obj1.a without having an obj1 or anything like it. I'm not really sure how to make this clearer, without turning this into an introductory essay on OO and Python's type system.
"I've checked again and it's because I'm importing from is a Tornado Framework and the variable is within a class."
Accordingly, your problem is not the one shown in your question.
If you actually want to access the variable of a class (and likely, you don't), then do this:
from othermodule import ClassName
print ClassName.var_i_want
You probably want to access the variable as held inside an instance:
from othermodule import ClassName, some_func
classnameinstance = some_func(blah)
print classnameinstance.var_i_want
Update Now that you have completely changed your question, here is the answer to your new question:
IN this code:
class Names:
def userNames(self):
name = 'Richard'
name is not a variable accessible outside of the activation of the method userNames. This is known as a local variable. You would create an instance variable by changing the code to:
def userNames(self):
self.name = 'Richard'
Then, if you have an instance in a variable called classnameinstance you can do:
print classnameinstance.name
This will only work if the variable has been already created on the instance, as by calling userNames.
You don't need to import the class itself if there is some other way to receive instances of the class.
file:a.py
class Names:
def userNames(self):
self.name = 'Richard'
file:z.py
import a
c = a.Names()
c.userNames()
what_you_want_is = c.name
Btw, this code makes no sense..but this is apparently what you want
Better a.py
class Names:
def userNames(self, name):
self.name = name
Better z.py
import a
c = a.Names()
c.userNames("Stephen or something")
what_you_want_is = c.name
# what_you_want_is is "Stephen or something"

Categories

Resources