Creating classes and objects in Python - python

I have this:
class Klasse1:
variable1 = "haha"
print Klasse1.variable1
and this:
class Klasse1:
variable1 = "haha"
Object1 = Klasse1()
print Object1.variable1
Why would I use the second (too much code) instead of the first (obviously easier)? In many sites and tutorials I've seen people create objects for something they could easily get without creating them.

You create objects to hold state. If you had something like:
class Wallet(object):
balance = 0
It wouldn't make sense to share the same balance between multiple instances of the class. You'd want to create a new instance of Wallet for each bit of money you're trying to track.
Because you'd use it by doing something like:
fred.wallet = Wallet
jim.wallet = Wallet # same object!
So now when Fred spends money
fred.wallet.balance -= 3.50
Jim spends that money too.
>>> print(jim.wallet.balance)
3.50
Instead you'd want to create INSTANCES of the class Wallet and give each one its own state
class Wallet(object):
def __init__(self, balance=0):
# __init__ is called when you instantiate the class
self.balance = balance
fred.wallet = Wallet()
jim.wallet = Wallet()
Now when Fred spends money:
fred.wallet.balance -= 3.50
Jim won't be affected because his Wallet object is a different instance
>>> print(jim.wallet.balance)
0

This is a tough question to answer succinctly but it comes down to when you want to have more than one instance of Klasse1. If you know you'll only ever need the class and never instantiate it, you'll be fine. If you do instantiate it, (ie calling the class and using the returned object), you can change the variable1 member without modifying the class' variable:
class Klasse1:
variable1 = "haha"
foo = Klasse1()
print foo.variable1
>>>'haha'
foo.variable1 = 123
print Klasse1.variable1
>>>'haha'
If you made another instance of Klasse1, it's variable1 would still be 'haha' even after altering foo's variable1.
bar = Klasse1()
print bar.variable1
>>>'haha'
What's sort of tricky is that if you change Klasse1.variable1, only bar.variable1 would change, foo.variable1 would remain 123.
Klasse1.variable1 = "this isn't funny"
print foo.variable1
>>>123
print bar.variable1
>>>"this isn't funny"
print Klasse1.variable1
>>>"this isn't funny"

Related

How to update variables passed between classes?

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.

Python Accessing Dict That Has Defualt Values That Have Been Updated

So I have this class:
class hero():
def __init__(self, name="Jimmy", prof="Warrior", weapon="Sword"):
"""Constructor for hero"""
self.name = name
self.prof = prof
self.weapon = weapon
self.herodict = {
"Name": self.name,
"Class": self.prof,
"Weapon": self.weapon
}
self.herotext = {
"Welcome": "Greetings, hero. What is thine name? ",
"AskClass": "A fine name, {Name}. What is your class? ",
"AskWeapon": "A {Class}, hmm? What shalt thy weapon be? ",
}
def setHeroDicts(self, textkey, herokey):
n = raw_input(self.herotext[textkey].format(**self.herodict))
if n == "":
n = self.herodict[herokey]
self.herodict[herokey] = n
#print self.herodict[herokey]
def heroMake(self):
h = hero()
h.setHeroDicts("Welcome", "Name")
h.setHeroDicts("AskClass", "Class")
h.setHeroDicts("AskWeapon", "Weapon")
And in another class I have this executing
def Someclass(self):
h = hero()
print h.herodict["Class"]
h.heroMake()
print h.getClass()
if "Mage" in h.herodict["Class"]:
print "OMG MAGE"
elif "Warrior" in h.herodict["Class"]:
print "Warrior!"
else:
print "NONE"
So if I input nothing each time, it will result in a blank user input, and give the default values. But if I put an input, then it will change the herodict values to what I customize. My problem is, if I try and access those updated values in Someclass it only gives me the default values instead of the new ones. How do I go about accessing the updated values?
The main issue with your class is that you are creating a new object within heromake instead of using the existing one. You can fix this by replacing h with self (so that each time you are calling setHeroDicts on the object):
def heromake(self):
self.setHeroDicts("Welcome", "Name")
self.setHeroDicts("AskClass", "Class")
self.setHeroDicts("AskWeapon", "Weapon")
The first argument to a method is always set to the instance itself, so if you want to interact with the instance or mutate it, you need to use it directly. When you do h = hero() in your original code, you create a whole new hero object, manipulate it and then it disappears when control passes back to your function.
A few other notes: you should name your classes with CamelCase, so it's easier to tell they are classes (e.g., you should really have class Hero) and in python 2, you need to make your classes descend from object (so class Hero(object)). Finally, you are duplicating nearly the entire point of having classes with your herodict, you should consider accessing the attributes of the object directly, instead of having the intermediary herodict (e.g., instead of doing h.herodict["Class"] you could do h.prof directly.

Python class instances stored in a list to store seperate instances

from datetime import datetime
class sms_store:
def __init__(self):
self.store = [] #Keeps resetting / not saving data from previous instances
self.message_count = 0 #Keeps resetting / not saving data from previous instances
def add_new_arrival(self,number,time,text):
self.store.append(("From: "+number, "Recieved: "+time,"Msg: "+text))
self.message_count += 1
newsms = sms_store()
time = datetime.now().strftime('%H:%M:%S')
newsms.add_new_arrival("23456",time, "hello, how are you?")
As seen above in the comment section i want to a list to store information from VARIOUS instances. Not one instance, but SEVERAL seperate instances of information and the list being a list that is accessible and in which I can edit it and it SAVES the information from different instances. Its not doing this. It is resetting after every instance.
I have tried the global variable route but not understanding it and dont think it will work. I have set a global variable OUTSIDE the class and created an object inside the class to store in the list but it gives me an error: UnboundLocalError: local variable 'message_count' referenced before assignment.
I am working on an excercise that requires one to use classes in the interactive python site: http://openbookproject.net/thinkcs/python/english3e/classes_and_objects_I.html#term-class
Please please help me.
You should not create a new instance of sms_store each time:
newsms = sms_store()
newsms.add_new_arrival("23456", datetime.now().strftime('%H:%M:%S'), "hello, how are you?")
newsms.add_new_arrival("65432", datetime.now().strftime('%H:%M:%S'), "I'm fine, thanks")
works just fine
It looks like you want a class variable.
The code should look like this:
from datetime import datetime
class Sms_store:
store = []
message_count = 0
def __init__(self):
pass
def add_new_arrival(self,number,time,text):
Sms_store.store.append(("From: "+number, "Recieved: "+time,"Msg: "+text))
Sms_store.message_count += 1
newsms1 = Sms_store()
time = datetime.now().strftime('%H:%M:%S')
newsms1.add_new_arrival("23456",time, "hello, how are you?")
newsms2 = Sms_store()
time = datetime.now().strftime('%H:%M:%S')
newsms2.add_new_arrival("23456",time, "hello, how are you?")
print Sms_store.store
This way, the variables store and message_count will be shared by all the instances of the Sms_store class.

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.

python, dynamically implement a class onthefly

this is related to python, dynamically implement a class onthefly.
when i restarted my pc, couldnt get back to add comments to the post - below is an example to explain what meant by save the class_with_the_methods_used
class bank(object):
def __init__(self, bal=0):
self.bal = bal
def deposit(self, amount):
self.bal+=amount
print self.bal
def debit(self, amt):
self.bal-=amt
print self.bal
bank.debit = debit
myacct = bank()
myacct.deposit(1000) # prints 1000
myacct.debit(99) # print 901
dir(myacct) # print [ ....'bal', 'debit', 'deposit']
then i used pickle and saved the object myacct
after saving, restarted my python and tried the commands below
>>> import pickle
>>> obj = pickle.load(open('bank.pkl'))
>>> dir(obj) # prints [....'bal', 'deposit']
note that 'debit' is not among the attributes . So my problem is how to make methods like 'debit' persistent?
Check out the new module (http://docs.python.org/library/new.html)
It has a lot of tools for doing things dynamically. The problem you are having is debit is not a instance method, it is just a normal function. Methods defined in classes are different than functions defined outside.
This is due to the way pickle dumps custom classes.
>>> class Bank(object):
... pass
...
>>> def debit(self, amt):
... print amt
...
>>> Bank.debit = debit
>>>
>>> acct = Bank()
>>> acct.debit
<bound method Bank.debit of <__main__.Bank object at 0x023B57D0>>
>>> import pickle
Look at the following:
>>> print pickle.dumps(acct)
ccopy_reg
_reconstructor
p0
(c__main__
Bank
p1
c__builtin__
object
p2
Ntp3
Rp4
.
You'll see that in fact the entire instance isn't pickled; instead, pickle simply records that it is an instance of Bank and recreates it by re-instantiating Bank. You will have to define a custom pickle protocol if you want to do this properly, which is complicated.

Categories

Resources