How can I iterate child elements in a loop? - python

I have some Obj like
class A:
a1 = b
where and b = B()
class B:
b1 = c
e.t.c
how can i iterate at a = A()
I'm looking for something like:
for i in [a, b, c, d]
result = a.b.c.d
I need to add a child element from the list each time depending on what is in the list
if i = 0 i get a
if i = 1 i want to get expression a.b
if i = 2 i want to get expression a.b.c
I want to be able to add a variable through a point.

Related

Using arguments as variable names: Why does it solve this problem?

I'm going through some material about functions and I'm writing Python code to make some sense of the pseudocode examples.
The goal is printing the variables after I call the function, then check the new values.
def my_sum(x, y, z):
z = x + y
return x, y, z
A = 1
B = 2
C = 0
my_sum(A, B, C)
my_sum(B, C, A)
my_sum(C, A, B)
my_sum(A, B, C)
my_sum(B, C, A)
print(A, B, C)
My first instinct was to write this procedural approach, but when I do the calling the program won't give the right answer, because A, B and C aren't saving whatever is happening inside the function. So A is always 1, B is 2 and so forth
It turns out when I assign the calling with the arguments, the variables A, B and C receive the new values and they're now keeping it. Finally it prints 21, 8, 13, which is the answer.
A, B, C = my_sum(A, B, C)
B, C, A = my_sum(B, C, A)
C, A, B = my_sum(C, A, B)
A, B, C = my_sum(A, B, C)
B, C, A = my_sum(B, C, A)
How would you implement it or what are the other ways of writing this algorithm?
The thing is I can't wrap my head around why this works at all! It was just a random guess that happened to solve my problem.
python don't have pass by reference option, only pass by value, so your construction is correct, because you returning NEW values (in tuple form), not changing value of variables, that you are passing in.
In Python, an assignment made to a parameter name never affects the value of the name that the caller uses. They are separate names that initially reference the same object, but once the parameter name is assigned something else (like a sum), it references a different object.
Your second attempt works because the function returns a tuple with the values of the three paramater names and your main program unpacks that tuple back into its own names.
However, since the function doesn't need the original value of the third argument, and it doesn't touch the first two arguments, the caller doesn't really need to pass the third argument, and doesn't need to update its own names for the first two arguments... So the function could be designed to only take two arguments and return the new value:
def my_sum(x, y):
return x + y
A = 1
B = 2
C = my_sum(A, B)
A = my_sum(B, C)
B = my_sum(C, A)
C = my_sum(A, B)
A = my_sum(B, C)
Lets start with your function definition and one call.
def my_sum(x, y, z):
z = x + y
return x, y, z
A = 1
B = 2
C = 0
my_sum(A, B, C)
Without the function, this is functionally the same as:
A = 1
B = 2
C = 0
x = A
y = B
z = C
z = x + y
_ = x, y, z
# x, y, and z are discarded since you don't do anything with the return value
You shouldn't expect this to change A, B, or C or if you do you have a misconception about how python variables or names work.
Python variables or names are just a dict with a name pointing to a value.
A = 1
B = 2
C = 0
my_sum(A, B, C)
# this is a very condensed version of what python does in the background
dict_of_globals = dict()
dict_of_globals['A'] = 1
dict_of_globals['B'] = 2
dict_of_globals['C'] = 3
my_sum_local_dict = dict()
my_sum_local_dict['x'] = dict_of_globals['A']
my_sum_local_dict['y'] = dict_of_globals['B']
my_sum_local_dict['z'] = dict_of_globals['C']
# and so on..
Since you only ever assign 1 to dict_of_globals['A'], it would be unreasonable to expect it to be anything other than 1.
The reason this works:
A, B, C = my_sum(A, B, C)
is because you are assigning the return value back to A.
A = x # etc..
# or:
dict_of_globals['A'] = my_sum_local_dict['x']

Can you hold pointers in a python list?

For example
b = 4
c = []
c.append(b)
print(c)
b += 2
print(c)
I was hoping I would get
4
6
but I got
4
4
Any chance I could add the element as a pointer. And then if I reference that element with c[0] I'd be referencing the b?
here c and b are different variables where c is list and b is int so if you add some on b it doesn't mean and c will be updated but if you add some number on b and append it again on c
there will be a change
b = 4
c = []
c.append(b)
print(c)
b += 2
c.append(c)
print(c)
and what you will get is
[4, 6]
and I think is clear that a c didn't change in your question
You can do that with a class:
class Number:
def __init__(self, number):
self.number = int(number)
def __str__(self):
return str(self.number)
def __repr__(self):
return self.__str__()
def __add__(self, other):
self.number = self.number + other
b = Number(4)
c = []
c.append(b)
print(c)
b += 2
print(c)
You will get:
4
6
Refer this below link to understand how the reference works in python:
How do I pass a variable by reference?
So, in short,
python objects i.e. booleans, integers, floats, strings, and tuples are immutable, which means that after you create the object and assign some value to it, you can't modify that value.
Hence, when you do b += 2, here, b will point to a new memory reference.
Proof:
>>> b=10
>>> id(b)
1734146112
>>> b+=2
>>> id(b)
1734146144
>>>
However, as #yoav mentioned above,
you can also do this by tweaking the default behaviour of Number class but beware; you should use it very carefully as you might not need this behaviour for every class.

Is there a way in python to assign a variable such that it always points to the memory where its assigned right hand side points to?

I got this issue when trying to improve a clustering algorithm.
I need the labels to form a chain and be assigned a value when the chain terminates.
I simpler version of the problem is explained below.
A = []
B = []
C = []
C = B
B = A
A.append(0)
This gives:
A = [0], B = [0], C = []
I want something which will instantly update all the elements when an end is reached and edited.
Like I want all A,B and C to be linked together and get updated when A is changed.
Expected result:
A = [0], B = [0], C = [0] ...
(This chain can be of any length. It may even develop branches.)
How do I go about achieving this?
I put the title that way because I felt it could be done if C pointed to where A points when B = A assignment is done.
Note:
I cannot keep track of the head of the whole chain at a time. This linking variables part is done based on some other order.
Note:
This connection forms part by part. So A = B = C = [0] is not helpful.
You can do it this way:
>>> A = B = C = []
>>> A.append(0)
>>> A
[0]
>>> B
[0]
>>> C
[0]
In Python, a variable acts as a pointer to a value. When you run A = B = C = [] you are basically saying that A, B and C are pointing to the same list in memory.
Alternatively, you can do the following:
>>> A = B = []
>>> C = A
>>> C.append(0)
>>> A
[0]
>>> B
[0]
>>> C
[0]
>>> B.append(1)
>>> A
[0, 1]
>>> B
[0, 1]
>>> C
[0, 1]
References:
Thank you so much to Mad Physicist, cdrake and Rafael for your suggestions which steered me in the direction I needed to be in to reach the answer.
Answer:
The trick is to never make assignments such as C = B; B = A;, as this will cause loss of information when variables start referring to new objects and the old objects are abandoned and left for some variables to uselessly refer to.
Instead we must make each of these already declared objects to store information as to how to reach the end of the chain. This can be done by:
# Initial Declaration
A = []; B = []; C = []; D = []
# Chain Formation
C.append(B)
B.append(A)
D.append(C)
# Data Addition at Chain head
A.append("DATA")
This gives:
>>> A
['DATA']
>>> B
[['DATA']]
>>> C
[[['DATA']]]
>>> D
[[[['DATA']]]]
Now each of the variables has access to the data added at Chain Head. This data can be obtained by repeatedly entering the into the index 0 of the list till we reach an object which is not of type <class 'list'>. The implementation given below will make it clear:
def GetData(Chain):
C = Chain.copy()
while len(C) > 0 and type(C[0]) == type([]):
C = C[0]
if len(C):
return C[0]
else:
return None
>>> ( GetData(A), GetData(B), GetData(C), GetData(D) )
('DATA', 'DATA', 'DATA', 'DATA')
This way of storing information so as to direct the preceding members to the same source of information as the head of the Chain is very helpful as it can instantly relay the change of final information to the members at the back. An example which builds over the previous code is shown below:
# Initial Declaration for New Chain
P = []; Q = []
# New Chain Formation
Q.append(P)
# Old Chain Redirection
C.remove(C[0])
C.append(Q)
# Attempted Data Recovery
>>> ( GetData(A), GetData(B), GetData(C), GetData(D), GetData(P), GetData(Q) )
('DATA', 'DATA', None, None, None, None)
# Data Addition at New Chain Head
P.append((0,0))
# Attempted Data Recovery
>>> ( GetData(A), GetData(B), GetData(C), GetData(D), GetData(P), GetData(Q) )
('DATA', 'DATA', (0, 0), (0, 0), (0, 0), (0, 0))
This is my solution to the problem I was facing. Please feel free to suggest changes if needed.
Once again, Thank you to all those who directed me to this solution.
Everything in Python is object. Variables are are just names, no relation with locations.
Names refer to objects. Names are introduced by name binding operations.
Execution model: naming and binding — Python 3.7.3 documentation
Every variable in Python is just a name, which is bound to one object.
For variable in Python, nothing is constant except for the name itself.
However, variable in C is indeed a memory location.
// c
// variable a has one location
// variable b has one location, too
// they are of course different
int a, b;
// value of location of variable a will become 4
a = 4;
// location of variable b don't change
// what changed is
// value of location of variable b
// will become value of location of variable a
b = a;
# python
# variable a(just a name) is bound to object 4
a = 4
# variable b(just a name) is bound to the object which variable a is bound
b = a
# variable b(just a name) is bound to another object 6
# nothing to with variable a(just a name)
b = 6
So:
Is there a way in python to assign a variable such that it always points to the memory where its assigned right hand side points to?
Not in Python. Variables in Python just don't point to memory directly in fact. Variables are just names.

Python syntax clarification

Scrolling through the python 2.7 docs I came across this snippet
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while b < n:
print a,
a, b = b, a+b
But I don't understand the last line, and unsure of how I would google for it.
How should I read a, b = b, a+b, or, what does it mean ?
Python evaluates the right-hand side of assignments first. It evaluates
b, a+b
from left to right. It then assigns the values to the variables a and b respectively.
So a, b = b, a+b is equivalent to
c = b
d = a+b
a = c
b = d
except that it achieves the result without explicit temporary variables.
See the docs on Python's evaluation order.
There is a subtle point here worth examining with an example. Suppose a = 1, b = 2.
a, b = b, a+b
is equivalent to
a, b = 2, 1+2
a, b = 2, 3
So a gets assign to 2, b is assigned to 3.
Notice that this is not equivalent to
a = b
b = a + b
Since the first line would assign
a = 2
b = 2 + 2 = 4
Notice that done this (wrong) way, b ends up equal to 4, not 3. That's why it is important to know that Python evaluates the right-hand side of assignments first (before any assignments are made).
It is setting a to b, and b to a + b, without needing an intermediate variable. It could also be accomplished with:
temp = a
a = b
b = temp + b

How to access a variable defined inside a function from out side? [duplicate]

This question already has answers here:
How to get/set local variables of a function (from outside) in Python? [duplicate]
(5 answers)
Closed 9 years ago.
Let us consider the following program
def fib(n):
result = []
a, b = 0, 1
while b < n:
result.append(b)
a, b = b, a+b
c = result
print c
return result
f100 = fib(100)
print result
#print c
How can I access the variable 'c' from out side the function? Is it possible? I know
print result
will give the same, but i want to know is there any method to access 'c' outside the function?
You could declare c as global, although that's not generally a pattern you'd want to encourage. You'd do that like this:
c = None
def fib(n):
global c
result = []
a, b = 0, 1
while b < n:
result.append(b)
a, b = b, a+b
c = result
return result
f100 = fib(100)
print result
print c
You could also restructure your function as a class with a __call__ method which would let you expose internal values as attributes, such as:
class fibber(object):
def __init__(self):
self.c = None
def __call__(self, n):
result = []
a, b = 0, 1
while b < n:
result.append(b)
a, b = b, a+b
self.c = result
return result
fib = fibber()
f100 = fib(100)
print result
print fib.c
Local variables only exist in the context of the function they are defined in. That's what makes them local. So the whole variable c does not exist anymore once the function terminates and returns its result value.
You can of course save the value of that variable in a different one, e. g. a field of the function itself:
fib.c = c
Since the function itself will exist also after it terminated, so will its fields, and so will fib.c.
But I must stress that this is just a hack. Normally if you want to access a value outside of a function it is a good idea to make the variable holding that value not local.
You can declare c a global variable:
def fib(n):
global c
result = []
a, b = 0, 1
while b < n:
result.append(b)
a, b = b, a+b
c = result
print c
return result
result = fib(10)
print result
print c

Categories