Order of classes matters when using variables from each other - python

I am new to Python and didn't find an answer to the following problem:
I have two classes and want them to use variables from each other. Is there a simple way to do this because if I do it like this class a does not know that class b exists.
class a:
y=1
print(b.x)
class b:
x=1
print(a.y)
And how do I use overwrite the variables, the following code does not work:
class a:
y=b.x
class b:
x=1

You are executing print as part of the class definition. It executes as soon as python sees that line of code, before it's read the part about class b.
Instead, use functions inside the classes to execute code after the classes have been defined:
class a:
y=1
def go():
print(b.x)
class b:
x=1
def go():
print(a.y)
a.go()
b.go()

As I said in a comment, your code isn't making effective use of classes. Here's what I think would be better approach that offers more flexibility in working around the circular reference issue.
First the class definitions (which follow the PEP 8 naming convention guidelines):
class A:
def __init__(self, value, linked_value=None):
self.y = value
if isinstance(linked_value, B):
self.linked_value = linked_value.x
def print_linked_value(self):
print(self.linked_value)
class B:
def __init__(self, value, linked_value=None):
self.x = value
if isinstance(linked_value, A):
self.linked_value = linked_value.y
def print_linked_value(self):
print(self.linked_value)
Definitions like that provide two ways to set up the circular references:
By creating them separately, then explicitly linking them:
# First create instances of each class.
a = A(1)
b = B(42)
# Then link them.
a.linked_value = b.x
b.linked_value = a.y
a.print_linked_value() # -> 42
b.print_linked_value() # -> 1
*OR* by creating the first one without a linked value and leaving only the second needing to be linked manually.
# First create instances of each class, but link the second to the first
# when it's created.
a = A(1)
b = B(42, a) # Create and link to first.
# Then link the first to the second to complete the circular references.
a.linked_value = b.x
# Same result.
a.print_linked_value() # -> 42
b.print_linked_value() # -> 1
Final note: Another, more advanced alternative that can also be applied in situations like this by using the built-in property() function as a decorator to create "descriptors". Here's an answer to a somewhat related question that illustrating its use.

class A:
y = 1
def foo(self):
print B.x
class B:
x = 1
def bar(self):
print A.y
>>> A().foo()
2
>>> B().bar()
1
Use 'print' in some function definition.

Related

Copy assignment for class member functions

I have a class A with some member functions that all do the same thing.
class A:
def a():
... boilerplate code ...
b = c = d = a
For debugging reasons, I would like to know the name of each member function at runtime. But since they all point to the same memory address, they will have the same __name__ attribute and I cannot figure out a way to distinguish between A.a and A.b just by looking at the object.
a = A.a
b = A.b
a.__name__ == b.__name__ # this is true
# how do I tell the difference between a and b?
Is there a way to achieve this without manually creating the functions b, c and d with the same boilerplate code?
No. Objects and names in Python live in separate spaces. There's only one function object there, and the function object doesn't know through what name it was conjured.
If you were a masochist, I suppose it would be possible to get a traceback and look at the line of code that called you, but that's just not practical.
You could do something like:
def reala(self,me=None):
pass
def a(self):
return reala('a')
def b(self):
return reala('b')
...

self in Python classes

I know first argument in Python methods will be an instance of this class. So we need use "self" as first argument in methods. But should we also specify attribures (variables) in method starting with "self."?
My method work even if i don't specify self in his attributes:
class Test:
def y(self, x):
c = x + 3
print(c)
t = Test()
t.y(2)
5
and
class Test:
def y(self, x):
self.c = x + 3
print(self.c)
t = Test()
t.y(2)
5
For what i would need specify an attribute in methods like "self.a" instead of just "a"?
In which cases first example will not work but second will? Want to see situation which shows really differences between two of them, because now they behave the same from my point of view.
The reason you do self.attribute_name in a class method is to perform computation on that instances attribute as opposed to using a random variable.For Example
class Car:
def __init__(self,size):
self.size = size
def can_accomodate(self,number_of_people):
return self.size> number_of_people
def change_size(self,new_size):
self.size=new_size
#works but bad practice
def can_accomodate_v2(self,size,number_of_people):
return size> number_of_people
c = Car(5)
print(c.can_accomodate(2))
print(c.can_accomodate_v2(4,2))
In the above example you can see that the can_accomodate use's self.size while can_accomodate_v2 passes the size variable which is bad practice.Both will work but the v2 is a bad practice and should not be used.You can pass argument into a class method not related to the instance/class for example "number_of_people" in can_accomodate funtion.
Hope this helps.

Python reverse introspection

Lets suppose this example: Two siblings classes where one loads the other class as a new attribute and then i wish to use this attribute from the main class inside the sibling.
a = 2
class AN(object):
def __init__(self,a):
self.aplus = a + 2
self.BECls = BE(a)
class BE(object):
def __init__(self,a):
print a
def get_aplus(self):
????
c = AN(a)
and i'd like to do:
c.BECls.get_aplus()
and this shall return something like self.self.aplus (metaphorically), that would be 4
Resuming: get aplus attribute from AN inside BE class, without declaring as arguments, but doing a "Reverse introspection", if it possible, considering the 'a' variable must be already loaded trough AN.
Sorry if I not made myself clear but I've tried to simplify what is happening with my real code.
I guess the problem may be the technique i'm using on the classes. But not sure what or how make it better.
Thanks
OP's question:
get aplus attribute from AN inside BE class, without declaring as
arguments, but doing a "Reverse introspection", if it possible,
considering the 'a' variable must be already loaded trough AN.
The closest thing we have to "reverse introspection" is a search through gc.getreferrers().
That said, it would be better to simply make the relationship explicit
class AN(object):
def __init__(self,a):
self.aplus = a + 2
self.BECls = BE(self, a)
class BE(object):
def __init__(self, an_obj, a):
self.an_obj = an_obj
print a
def get_aplus(self):
return self.an_obj.aplus
if __name__ == '__main__':
a = 2
c = AN(a)
print c.BECls.get_aplus() # this returns 4

Add to custom class in Python

I would like to be able to add to a custom class in the style of:
x=myclass("Something", 7)
x + 3
7, of course, corresponds with an inner property that I'd like to increment by adding to it.
The class holds a number that refers to a location in a list. This might seem like something that can be done by a normal integer, but I need it to act as a separate type. This is all done to emulate an old game language. The class is its 'variable' class, and the value of the variable is stored in the aforementioned list. Apparently, on older version of the game, arrays were faked by doing math on the variable object instance to grab a different variable. So I'm trying to emulate that.
If you want to support addition for class instances, you need to define an __add__() method on your class:
class MyClass(object):
def __init__(self, x):
self.x = x
def __add__(self, other):
return self.x + other
Example:
>>> a = MyClass(7)
>>> a + 3
10
To also support 3 + a, define the __radd__() method.
If you want to be able to update the x attribute of MyClass instances using
a += 3
you can define __iadd__().
If you want class instances to behave like integers with some additional methods and attributes, you should simply derive from int.
What you're looking to do is operator overloading. You can do this in python new style classes by overloading the __add__ method like so:
>>> class Test(object):
... def __init__(self): self.prop = 3
... def __add__(self, x):
... return self.prop + x
...
>>> Test() + 4
7
>>>

python self-less

this works in the desired way:
class d:
def __init__(self,arg):
self.a = arg
def p(self):
print "a= ",self.a
x = d(1)
y = d(2)
x.p()
y.p()
yielding
a= 1
a= 2
i've tried eliminating the "self"s and using a global statement in __init__
class d:
def __init__(self,arg):
global a
a = arg
def p(self):
print "a= ",a
x = d(1)
y = d(2)
x.p()
y.p()
yielding, undesirably:
a= 2
a= 2
is there a way to write it without having to use "self"?
"self" is the way how Python works. So the answer is: No! If you want to cut hair: You don't have to use "self". Any other name will do also. ;-)
Python methods are just functions that are bound to the class or instance of a class. The only difference is that a method (aka bound function) expects the instance object as the first argument. Additionally when you invoke a method from an instance, it automatically passes the instance as the first argument. So by defining self in a method, you're telling it the namespace to work with.
This way when you specify self.a the method knows you're modifying the instance variable a that is part of the instance namespace.
Python scoping works from the inside out, so each function (or method) has its own namespace. If you create a variable a locally from within the method p (these names suck BTW), it is distinct from that of self.a. Example using your code:
class d:
def __init__(self,arg):
self.a = arg
def p(self):
a = self.a - 99
print "my a= ", a
print "instance a= ",self.a
x = d(1)
y = d(2)
x.p()
y.p()
Which yields:
my a= -98
instance a= 1
my a= -97
instance a= 2
Lastly, you don't have to call the first variable self. You could call it whatever you want, although you really shouldn't. It's convention to define and reference self from within methods, so if you care at all about other people reading your code without wanting to kill you, stick to the convention!
Further reading:
Python Classes tutorial
When you remove the self's, you end up having only one variable called a that will be shared not only amongst all your d objects but also in your entire execution environment.
You can't just eliminate the self's for this reason.

Categories