Output a dict in python - python

Hi guys i'm struggling with these classes.
this is what i have to do: cours stands for course and etudiant stands for student. I have to create a class Student that will do the following and i also have to use repr. so create object with student number and add courses
>>> d = Etudiant(12456)
>>> d.addCours('csi2520')
>>> d.addCours('csi2772')
>>> d.addCours('csi2510')
>>> d
12456:[ 'csi2520', 'csi2772', 'csi2510']
>>> d.cours('csi2510')
True
>>> d.cours('csi4900')
False
This is what i did but it's not working
class Etudiant:
cours=[]
def __init__(self, numero):
self.numero=numero
self.classe={self.numero:self.cours}
repr(self.classe)
def addCours(self, cours1):
self.cours.insert(-1,cours1)
please keep it simple i'm a newbie

To alter how a Python object looks when it's printed, you need to implement a magic method called __repr__ (short for representation). You also don't need to store the student number inside the cours variable:
class Etudiant(object):
def __init__(self, numero):
self.numero = numero
self._cours = []
def addCours(self, cours):
self._cours.append(cours)
def cours(self, cours):
return cours in self._cours
def __repr__(self):
return '{}: {}'.format(self.numero, self._cours)
Testing:
>>> d = Etudiant(12456)
>>> d.addCours('csi2520')
>>> d.addCours('csi2772')
>>> d.addCours('csi2510')
>>> d
12456: ['csi2520', 'csi2772', 'csi2510']
>>> d.cours('csi2510')
True
>>> d.cours('csi4900')
False

Related

Appending to array in object appends to all instances

I'm working on a text based game. I've tried to make this as organized and professional as possible by trying to follow all conventions.
I have a Map class, shown below:
import logging
#local imports
import Npc
class Map:
def __init__(self, name, npcs = []):
self.name = name
connections = []
if all(isinstance(item, Npc) for item in npcs):
self.npcs = npcs
else:
raise Exception("An NPC was not an instance of NPC")
def addConnection(self, connection):
if(connection == self):
return
self.name = connection.name
self.connections.append(connection)
My Main class creates two instances of these maps named forest, and village.
The point of this code is to add village into the connections array of forest:
village = Map("Village")
forest = Map("Forest")
forest.addConnection(village)
It seems simple enough. But for some reason, when forest.addConnection(village) is run, or even if i do forest.connections.append(village), the Map instance "village" gets added to the connections array of both forest, and village.
According to the debugger, after forest.addConnection(village) is run,
my two objects look as shown:
village (Map)
|------> name="village"
|------> connections = [village]
forest (Map)
|------> name="forest"
|------> connections = [village]
Why is this happening? Nowhere in my code do I add anything to village's connections array. Is there something about object oriented programming in Python I'm not understanding? Should I make village and forest classes that inherit/extend the Map class?
Thanks in advance for all the help.
Try to avoid call a constructor as default argument of a function.
This is the cause of your issue.
Exemple :
>>> class Map():
... def __init__(self, a=list()): # do __init__(self, a=[]) produce same result
... print(a)
... a.append("hello")
...
>>> b = Map()
[]
>>> b = Map()
['hello']
>>> b = Map()
['hello', 'hello']
>>> b = Map()
['hello', 'hello', 'hello']
>>> b = Map()
['hello', 'hello', 'hello', 'hello']
So insead of doing :
def __init__(self, name, npcs = []):
self.name = name
...
do
def __init__(self, name, npcs = None):
if npcs is None:
npcs = []
self.name = name
...
Found the issue. #iElden got me looking in the right place.
In the constructor, I set connections = [], not self.connections = [].
Thanks for the responses!

Pythonic way to write attribute which has a random behavior

im writing a code like this
import random
class A:
def __init__(self):
self.att = self.set_att()
def set_att(self):
x = random.randint(0,10)
if x == 1:
return "att1"
elif x == 2:
return "att2"
# ... and so on
my question is: should i do it like this? or there is a better more pythonic way to do it.
i just want to call set_att in the init.
thank you
pycharm says i should use #staticmethod, but i dont understand is de difference
Here are two ideas I can think of:
import random
POSSIBLE_ATT_VALUES = [f'att{x}' for x in range(1, 11)]
class A:
def __init__(self):
# Produce a one-time random value.
self.att = random.choice(POSSIBLE_ATT_VALUES)
class B:
#property
def att(self):
# Every access returns a new random value.
return random.choice(POSSIBLE_ATT_VALUES)
>>> a = A()
>>> a.att
"att3" # Possible value.
>>> a.att
"att3" # The same value.
>>> b = B()
>>> b.att
"att5" # Possible value.
>>> b.att
"att1" # Possibly different value.

Python: Adding to dict of one object in a list changes all dicts of every other object in the list

So Python isn't my strong suit and I've encountered what I view to be a strange issue. I've narrowed the problem down to a few lines of code, simplifying it to make asking this question easier. I have a list of objects, this object:
class FinalRecord():
ruid = 0
drugs = {}
I create them in the shell like this:
finalRecords = []
fr = FinalRecord()
fr.ruid = 7
finalRecords.append(fr)
fr2 = FinalRecord()
fr2.ruid = 10
finalRecords.append(fr2)
As soon as I want to change the drugs dict on one object, it changes it for the other one too
finalRecords[0].drugs["Avonex"] = "Found"
I print out this:
finalRecords[1].drugs
and it shows:
{'Avonex':'Found'}
When I'm expecting it to actually be empty. I know I'm not completely understand how Python is working with the objects, can anyone help me out here?
The reason for this is because drugs is a class attribute. So if you change it for one object it will in fact change in others.
If you are looking to not have this behaviour, then you are looking for instance attributes. Set drugs in your __init__ like this:
class FinalRecord():
def __init__(self):
self.ruid = 0
self.drugs = {}
Take note of the use of self, which is a reference to your object.
Here is some info on class vs instance attributes
So, full demo illustrating this behaviour:
>>> class FinalRecord():
... def __init__(self):
... self.ruid = 0
... self.drugs = {}
...
>>> obj1 = FinalRecord()
>>> obj2 = FinalRecord()
>>> obj1.drugs['stuff'] = 2
>>> print(obj1.drugs)
{'stuff': 2}
>>> print(obj2.drugs)
{}
You define drugs as a class attribute, not an instance attribute. Because of that, you are always modifying the same object. You should instead define drugs in the __init__ method. I would also suggest using ruid as an argument:
class FinalRecord():
def __init__(self, ruid):
self.ruid = ruid
self.drugs = {}
It could then be used as this:
fr = FinalRecord(7)
finalRecords.append(fr)
fr2 = FinalRecord(10)
finalRecords.append(fr2)
Or more simply:
finalRecords.append(FinalRecord(7))
finalRecords.append(FinalRecord(10))

Python classes and modules

I am teaching myself Python and hit a roadblock with classes and modules.
The code below is something that you would probably never write, but I would like to just understand my error.
import random
class GetRandom:
def __init__(self):
self.data = ""
def ranNumber():
return random.random()
b = GetRandom()
bnum = b.ranNumber
print bnum
The output I am getting is:
<bound method GetRandom.ranNumber of <__main__.GetRandom instance at 0x7fe87818df38>>
I had expected a random number between 0 and 1. What am I doing wrong?
Thanks
There are two problems here:
You forgot to actually invoke GetRandom.ranNumber. Add () after it to do this:
bnum = b.ranNumber()
You need to make GetRandom.ranNumber accept the self argument that is passed implicitly when you invoke the method:
def ranNumber(self):
return random.random()
Once you address these issues, the code works as expected:
>>> import random
>>> class GetRandom:
... def __init__(self):
... self.data = ""
... def ranNumber(self):
... return random.random()
...
>>> b = GetRandom()
>>> bnum = b.ranNumber()
>>> print bnum
0.819458844177
>>>

Python object that monitors changes in objects

I want a Python object that will monitor whether other objects have changed since the last time they were checked in, probably by storing their hash and comparing. It should behave sort of like this:
>>> library = Library()
>>> library.is_changed(object1)
False
>>> object1.change_somehow()
>>> library.is_changed(object1)
True
>>> library.is_changed(object1)
False
Do you know of anything like that?
Here is an implementation for you. Note that the objects you monitor must be hashable and picklable. Note also the use of a WeakKeyDictionary which means that the Monitor won't stop the monitored objects from being deleted.
from weakref import WeakKeyDictionary
from cPickle import dumps
class Monitor():
def __init__(self):
self.objects = WeakKeyDictionary()
def is_changed(self, obj):
current_pickle = dumps(obj, -1)
changed = False
if obj in self.objects:
changed = current_pickle != self.objects[obj]
self.objects[obj] = current_pickle
return changed
class MyObject():
def __init__(self):
self.i = 1
def change_somehow(self):
self.i += 1
If you test it like this
object1 = MyObject()
monitor = Monitor()
print monitor.is_changed(object1)
object1.change_somehow()
print monitor.is_changed(object1)
print monitor.is_changed(object1)
It prints
False
True
False
It sounds like you're describing the observer pattern. Check here:
http://rudd-o.com/projects/python-observable/
Twisted observable
http://radio.weblogs.com/0124960/2004/06/15.html#a30 - includes explanation
I stole the idea from Nick Craig-Wood, and changed it to a Mix-Class. For me, this is easier to use:
from cPickle import dumps
#base class for monitoring changes
class ChangesMonitor:
_cm_last_dump = None
def is_changed(self):
prev_dump = self._cm_last_dump
self._cm_last_dump = None
cur_dump = dumps(self, -1)
self._cm_last_dump = cur_dump
return (prev_dump is not None) and (prev_dump != cur_dump)
if __name__ == '__main__':
print 'Test Example'
#mix monitoring class with your regular class
class MyGreatObject(ChangesMonitor, object):
one_val = 5
second_val = 7
def some_changes(self):
self.second_val += 5
#and testing
my_obj = MyGreatObject()
print my_obj.is_changed() #False
print my_obj.is_changed() #False
my_obj.some_changes()
print my_obj.is_changed() #True
print my_obj.is_changed() #False
I haven't heard of anything like this... but you could write it pretty easily. Use a dictionary to store a name:hash pair for each object, then use the pickle module to save the dictionary.
This is based on Oduvan's answer, but implemented as a decorator instead of a mix-in class:
from cPickle import dumps
#decorator for monitoring changes
def ChangesMonitor(cls):
def is_changed(self):
prev_dump = self._cm_last_dump
self._cm_last_dump = None
cur_dump = dumps(self, -1)
self._cm_last_dump = cur_dump
return (prev_dump is not None) and (prev_dump != cur_dump)
cls.is_changed = is_changed
cls._cm_last_dump = None
return cls
print 'Test Example'
#decorate your common class
#ChangesMonitor
class MyGreatObject(object):
one_val = 5
second_val = 7
def some_changes(self):
self.second_val += 5
#and testing
my_obj = MyGreatObject()
print my_obj.is_changed() #False
print my_obj.is_changed() #False
my_obj.some_changes()
print my_obj.is_changed() #True
print my_obj.is_changed() #False
Note that #property could be added in front of the def is_changed(self): line such that print my_obj.is_changed() would become print my_obj.is_changed. This might be considered more pythonic...

Categories

Resources