How to update variables passed between classes? - python

I'm trying to pass variables between different classes. In order to accompish this task, I have created an info class (here called 'declaration') so that the code reads:
class declaration():
def __init__(self):
self.info1 = 999
self.info2 = 'something_else'
print ('At declaration ')
class controller():
def __init__(self):
instance = declaration()
print ('Initial number ',instance.info1, instance.info2)
modifier(declaration)
print ('MIDDLE ',instance.info1,declaration.info1)
instance = declaration()
print ('Final number ',instance.info1)
class modifier():
def __init__(self,aux):
print ('MODIFIER')
self.info=aux
self.info.info1=55555
controller()
The output is:
At declaration
Initial number 999
something else
MODIFIER
MIDDLE 999 55555
At declaration
Final number 999
However, I'm not really sure about some of the inners of the code. I have one major question and a minor one. My main question is that when the class 'modifier' is modified according to:
class modifier():
def __init__(self,aux):
self.info=aux
print ('MODIFIER',self.info.info1)
self.info.info1=55555
it produces the error AttributeError: type object 'declaration' has no attribute 'info1' [Flipping the last 2 lines fixes the error]. It's confusing (at least to me) whether the class attributes are not passed or they have to be reinitialized.
The second question is how to update instance once its class has been updated. The second call to instance = declaration() seems to accomplish nothing.

Quick side note: Yes I do realise, I just want to say please try to follow the PEP8 python guide as it makes your code look cooler (and easier to read) and all the cool kids use it.
There are a few things wrong with your code, calling modifier(declaration) actually makes the aux parameter an uninitilized class, you want to call modifier(instance) as the init function has already been ran.
Also it would be easier to drop the self.info = aux as you can just call aux.info1 and it looks cleaner and is actually faster (Because you are calling one less Fast Store command in bytecode).
Lastly at print ('MIDDLE ',instance.info1,declaration.info1) you again parse declaration uninitilized therefore you get the error AttributeError: type object 'declaration' has no attribute 'info1', to fix this simply put declaration().info1 as that calls the init function (it is the same as saying declaration.__init__().info1).
So finally you get:
class declaration():
def __init__(self):
self.info1 = 999
self.info2 = 'something_else'
print ('At declaration ')
class controller():
def __init__(self):
instance = declaration()
print ('Initial number ', instance.info1, instance.info2)
modifier(instance)
print ('MIDDLE ', instance.info1, declaration().info1)
instance = declaration()
print ('Final number ',instance.info1)
class modifier():
def __init__(self, aux):
print ('MODIFIER')
aux.info1 = 55555
controller()
Hope this helped.

Related

print the value of a NumericProperty() kivy

If I have a Numeric Property in two of my screens that count how many times a person clicked the correct icon and I want to print it in a separate class how would I do this? I have tried using the print() function and using print(StringProperty(str())) but I dont get a number value printed. When I print the correct_counter in VerifyAA() and VerifyBB() the correct value is printed.
class A(Screen):
correct_counter1 = NumericProperty(0)
def verifyAA(self, *args):
if self.AA == V.Check1 or self.AA == V.Check2 or self.AA == V.Check3:
print("You got it!!!")
self.correct_counter1 = self.correct_counter1 + 1
print(self.correct_counter1)
self.ids.aa.disabled = True
class B(Screen):
correct_counter2 = NumericProperty(0)
def verifyBB(self, *args):
if self.BB == VV.Check1 or self.BB == VV.Check2 or self.BB == VV.Check3:
print("You got it!!!")
self.correct_counter2 = self.correct_counter2 + 1
print(self.correct_counter2)
self.ids.bb.disabled = True
class Answers(Screen):
print(A.correct_counter1)
print(StringProperty(str(B.correct_counter2)))
This is what gets printed respectively:
<NumericProperty name=correct_counter>
<StringProperty name=>
You need to understand the distinction between the definition of a class and an instance of a class. When you print A.correct_counter1 you print the NumericProperty object itself, defined at class level. That's the only sensible result - it wouldn't make sense for it to print the value of the property, because it doesn't have a value. For instance, if you wrote instance1 = A(correct_counter1=1); instance2 = A(correct_counter1=20) what value would you have expected print(A.correct_counter1) to print? The answer has to be neither, the value of the property is defined in each case for the class instance, not the class itself.
The correct solution is that you must print the value of the property via an instance of your class. For instance, if you write instance = A(); print(instance.correct_counter1) you will print a number like you expect. The best way to do this depends on the structure of your program and the relationship between the classes. Your example isn't a runnable program so it isn't possible to make a specific suggestion. If you have an actual example where you want to do this but can't work out how, post that as a new question.

why does python obj.atribute return adress location and obj.atribute.atribute return the value?

To get the value of an attribute I need to call method.attribute.attribute instead of method.attribute, why is this? Calling method.attribute results in a memory address. How should/can I change my code to make method.attribute work?
Most issues regarding this center around calling print(f) instead of print(f())
class MyList:
"""stores a list and does other stuff eventualy"""
this_list = []
def __init__(self, *args):
for arg in args:
self.this_list.append(arg)
def print_list(self):
"""prints the atribute:"description" from the stored objects in the list"""
for x in range(len(self.this_list)):
print(MyClassObj(self.this_list[x]).description, sep="\n")
This is the code that is supposed to print the value of the attribute description
class MyClassObj:
"""test object to be stores in the "MyList" object."""
def __init__(self, description):
self.description = description
This is the object that contains the attribute I want to get.
class CallList:
"""creates the objects, lists and calls the print method"""
#staticmethod
def main():
test1, test2 = MyClassObj("Test1"), MyClassObj("Test2")
list1 = MyList(test1, test2)
list1.print_list()
Main() is called outside the above classes.
The output I get is
<__main__.MyClassObj object at 0x007908F0>
<__main__.MyClassObj object at 0x00790910>
Process finished with exit code 0
If i change line:
print(MyClassObj(self.this_list[x]).description.description, sep="\n")
I get the expected result:
Test1
Test2
Process finished with exit code 0
So the question is why and how should I alter my code?
in print_list self.this_list[x] is already a MyClassObj so MyClassObj(self.this_list[x]) creates a new MyClassObj having a MyClassObj as its description.
Because there is no way defined to convert a MyClassObj to a string for print Python uses a default conversion showing the memory address.

Access dynamically created class instance variable, Kivy framework

Imagine following structure (I've cut most imho relevant parts):
class mymodificatorclass:
def callback(self,object):
print object
class generator(BoxLayout):
#(...)
def add(self, *l):
for i,t in enumerate(self.texts):
self.mytext.append(TextInput(hint_text=t, on_text_validate=modify.callback(self)))
self.add_widget(self.mytext[i])
#(...)
modify = mymodificatorclass() #global scope variable
prints for example <main.generator object at 0x433eef0>. Which is fine.
But, how would one access this class instance variables?
meaning, desired output would be:
print XXXXX
$ <__main__.mytext object at 0x433eef0>
print XXXXX.text, XXXXX
$ "text inside" <__main__.mytext object at 0x433eef0>
I've checked:
print object.__class__.__dict__.items() #no mytext here
print object.mytext #no mytext here
print getattr(object,object.mytext) # object generator has no attribute mytext
I know i can assign for example additional variable storing each TextInput object, but i'd rather not, since i know that if I modified example like this:
class generator(BoxLayout):
def add(self, *l):
for i,t in enumerate(self.texts):
self.mytext.append(TextInput(hint_text=t, on_text_validate=self.callback))
self.add_widget(self.mytext[i])
def callback(self,object):
print object
i would get desired result (i had that like this, but decided i need to move closer to mvc )
self.mytext.append(TextInput(hint_text=t,
on_text_validate=modify.callback(self)))
You are calling the function instead of passing it. Use functools.partial.
self.mytext.append(TextInput(hint_text=t,
on_text_validate=partial(modify.callback, self)))

Get the return value from a function in a class in Python

I am trying to simply get the value out of my class using a simple function with a return value, I'm sure its a trivial error, but im pretty new to python
I have a simply class set up like this:
class score():
#initialize the score info
def __init__(self):
self.score = 0
self.num_enemies = 5
self.num_lives = 3
# Score Info
def setScore(num):
self.score = num
# Enemy Info
def getEnemies():
return self.num_enemies
# Lives Info
def getLives():
return self.getLives
etc.....
Than I create an instance of the class as such:
scoreObj = score()
for enemies in range(0, scoreObj.getEnemies):
enemy_sprite.add(enemy())
I get the error saying that an integer is expected, but it got an instancemethod
What is the correct way to get this information?
Thanks!
scoreObj.getEnemies is a reference to the method. If you want to call it you need parentheses: scoreObj.getEnemies().
You should think about why you are using a method for this instead of just reading self.num_enemies directly. There is no need for trivial getter/setter methods like this in Python.
The first parameter for a member function in python is a reference back to the Object.
Traditionally you call it "self", but no matter what you call the first parameter, it refers back to the "self" object:
Anytime I get weird errors about the type of a parameter in python, I check to see if I forgot the self param. Been bit by this bug a few times.
class score():
#initialize the score info
def __init__(self):
self.score = 0
self.num_enemies = 5
self.num_lives = 3
# Score Info
def setScore(self, num):
self.score = num
# Enemy Info
def getEnemies(self):
return self.num_enemies
# Lives Info
def getLives(foo): #foo is still the same object as self!!
return foo.num_lives
#Works but don't do this because it is confusing
This code works:
class score():
def __init__(self):
self.score = 0
self.num_enemies = 5
self.num_lives = 3
def setScore(self, num):
self.score = num
def getEnemies(self):
return self.num_enemies
def getLives(self):
return self.getLives
scoreObj = score()
for enemy_num in range(0, scoreObj.getEnemies()):
print enemy_num
# I don't know what enemy_sprite is, but
# I commented it out and just print the enemy_num result.
# enemy_sprite.add(enemy())
Lesson Learned:
Class functions must always take one parameter, self.
That's because when you call a function within the class, you always call it with the class name as the calling object, such as:
scoreObj = score()
scoreObj.getEnemies()
Where x is the class object, which will be passed to getEnemies() as the root object, meaning the first parameter sent to the class.
Secondly, when calling functions within a class (or at all), always end with () since that's the definition of calling something in Python.
Then, ask yourself, "Why am I not fetching 'scoreObj.num_lives' just like so instead? Am I saving processing power?" Do as you choose, but it would go faster if you get the values directly from the class object, unless you want to calculate stuff at the same time. Then your logic makes perfect sense!
You made a simple mistake:
scoreObj.getEnemies()
getEnemies is a function, so call it like any other function scoreObj.getEnemies()

Instantiating a unique object every time when using object composition?

As an example, just a couple of dummy objects that will be used together. FWIW this is using Python 2.7.2.
class Student(object):
def __init__(self, tool):
self.tool = tool
def draw(self):
if self.tool.broken != True:
print "I used my tool. Sweet."
else:
print "My tool is broken. Wah."
class Tool(object):
def __init__(self, name):
self.name = name
self.broken = False
def break(self):
print "The %s busted." % self.name
self.broken = True
Hammer = Tool(hammer)
Billy = Student(Hammer)
Tommy = Student(Hammer)
That's probably enough code, you see where I'm going with this. If I call Hammer.break(), I'm calling it on the same instance of the object; if Billy's hammer is broken, so is Tommy's (it's really the same Hammer after all).
Now obviously if the program were limited to just Billy and Tommy as instances of Students, the fix would be obvious - instantiate more Hammers. But clearly I'm asking because it isn't that simple, heh. I would like to know if it's possible to create objects which show up as unique instances of themselves for every time they're called into being.
EDIT: The kind of answers I'm getting lead me to believe that I have a gaping hole in my understanding of instantiation. If I have something like this:
class Foo(object):
pass
class Moo(Foo):
pass
class Guy(object):
def __init__(self, thing):
self.thing = thing
Bill = Guy(Moo())
Steve = Guy(Moo())
Each time I use Moo(), is that a separate instance, or do they both reference the same object? If they're separate, then my whole question can be withdrawn, because it'll ahve to make way for my mind getting blown.
You have to create new instances of the Tool for each Student.
class Student(object):
def __init__(self, tool):
self.tool = tool
def draw(self):
if self.tool.broken != True:
print "I used my tool. Sweet."
else:
print "My tool is broken. Wah."
class Tool(object):
def __init__(self, name):
self.name = name
self.broken = False
def break(self):
print "The %s busted." % self.name
self.broken = True
# Instead of instance, make it a callable that returns a new one
def Hammer():
return Tool('hammer')
# Pass a new object, instead of the type
Billy = Student(Hammer())
Tommy = Student(Hammer())
I'll try to be brief. Well.. I always try to be brief, but my level of success is pretty much random.randint(0, never). So yeah.
Lol. You even failed to be brief about announcing that you will try to be brief.
First, we need to be clear about what "called into being" means. Presumably you want a new hammer every time self.tool = object happens. You don't want a new instance every time, for example, you access the tool attribute, or you'd always a get a new, presumably unbroken, hammer every time you check self.tool.broken.
A couple approaches.
One, give Tool a copy method that produces a new object that should equal the original object, but be a different instance. For example:
class Tool:
def __init__(self, kind):
self.kind = kind
self.broken = False
def copy(self):
result = Tool(self.kind)
result.broken = self.broken
return result
Then in Student's init you say
self.tool = tool.copy()
Option two, use a factory function.
def makehammer():
return Tool(hammer)
class Student:
def __init__(self, factory):
self.tool = factory()
Billy = Student(makehammer)
I can't think any way in Python that you can write the line self.tool = object and have object automagically make a copy, and I don't think you want to. One thing I like about Python is WYSIWYG. If you want magic use C++. I think it makes code hard to understand when you not only can't tell what a line of code is doing, you can't even tell it's doing anything special.
Note you can get even fancier with a factory object. For example:
class RealisticFactory:
def __init__(self, kind, failurerate):
self.kind = kind
self.failurerate = failurerate
def make(self):
result = Tool(self.kind)
if random.random() < self.failurerate:
result.broken = True
if (self.failurerate < 0.01):
self.failurerate += 0.0001
return result
factory = RealisticFactory(hammer, 0.0007)
Billy = Student(factory.make)
Tommy = Student(factory.make) # Tommy's tool is slightly more likely to be broken
You could change your lines like this:
Billy = Student(Tool('hammer'))
Tommy = Student(Tool('hammer'))
That'll produce a distinct instance of your Tool class for each instance of the Student class. the trouble with your posted example code is that you haven't "called the Tool into being" (to use your words) more than once.
Just call Tool('hammer') every time you want to create a new tool.
h1 = Tool('hammer')
h2 = Tool('hammer')
Billy = Student(h1)
Tommy = Student(h2)
Oh wait, I forgot, Python does have magic.
class Student:
def __setattr__(self, attr, value):
if attr == 'tool':
self.__dict__[attr] = value.copy()
else:
self.__dict__[attr] = value
But I still say you should use magic sparingly.
After seeing the tenor of the answers here and remembering the Zen of Python, I'm going to answer my own dang question by saying, "I probably should have just thought harder about it."
I will restate my own question as the answer. Suppose I have this tiny program:
class Item(object):
def __init__(self):
self.broken = False
def smash(self):
print "This object broke."
self.broken = True
class Person(object):
def __init__(self, holding):
self.holding = holding
def using(self):
if self.holding.broken != True:
print "Pass."
else:
print "Fail."
Foo = Person(Item())
Bar = Person(Item())
Foo.holding.smash()
Foo.using()
Bar.using()
The program will return "Fail" for Foo.using() and "Pass" for Bar.using(). Upon actually thinking about what I'm doing, "Foo.holding = Item()" and "Bar.holding = Item()" are clearly different instances. I even ran this dumpy program to prove it worked as I surmised it did, and no surprises to you pros, it does. So I withdraw my question on the basis that I wasn't actually using my brain when I asked it. The funny thing is, with the program I've been working on, I was already doing it this way but assuming it was the wrong way to do it. So thanks for humoring me.

Categories

Resources