Python, Grabbing information from a class object not working - python

So I have no idea what's causing this error. I don't know how to describe it without showing you, so here's the relevant part of my code:
class Node(object):
def __init__(self, contents, children):
self.contents = contents
self.children = children
def makeNode(district, parent):
new_contents = parent.contents
new_contents.append(district)
new = Node(new_contents, [])
parent.children.append(new)
return new
root = Node([], [])
data = [[1,1,'r'],[1,2,'d'],[1,2,'r'],[1,4,'d']]
makeNode(data, root)
Here's the problem: new.contents is changed as planned, but so is parent.contents. What happened?

As you've mentioned it in your comment, you've got to copy the contents pf 'parent.contents' into 'new_contents'. Otherwise, you're accessing the list by reference, which is obviously not what is intended.
So, your 'makeNode' function could start as follows:
def makeNode(district, parent):
new_content = copy.deepcopy(parent.contents)
...
I hope, I could clear things up for later readers... ;)

Related

kivy: How can I remove highlighting from all items in FileChooserListView

I'd like to be able to remove highlighting from all items in a kivy FileChooserListView. I see that I can remove the actual selection by setting my FileChooserListView().selection to an empty list []. But this does not remove highlighting of previously selected items. Thanks for the help.
There does not appear to be any way to do that directly, but I think this ugly hack will work:
class FakeEntry():
def __init__(self, **kwargs):
self.path = kwargs.pop('path', None)
class FakeEvent():
def __init__(self):
self.profile = []
self.button = None
self.is_double_tap = False
'''
Clear all selections in the specified FileChooser
'''
def clear_selection(file_chooser, *args):
layout = file_chooser.layout
if layout.VIEWNAME == 'list':
layout.ids.treeview.deselect_node()
fakeTouch = FakeEvent()
for path in file_chooser.selection[:]:
file_chooser.entry_touched(FakeEntry(path=path), fakeTouch)

Python - Assigning attributes to a class instance using a for loop and a list

Hi folks I am experimenting with Python (I found pygame.org and wanted to play around) and I am trying to read some settings from a configuration file. I want to be able to change stats on the fly. (So if I wanted to change how hard a fighter hits or how fast a wizard runs then I'd be able to do that.) I was hoping to be able to read from a list and create an attribute for each instance in the list basically this:
for stat in Character.stats:
self.stat = parser.get(self.char_class, stat)
What ends up happening is there is an object with an attribute names 'stat' that contains the last value assigned. What I would LIKE to happen is to have an attribute created for each item in the list, and then get assigned the related value from the config file.
here is more code for context:
class Character(object):
stats = ["level_mod",
"power",
"speed",
"hit",
"evade",
"magic",
"stamina",
"magic_defense",
"intelligence"]
def __init__(self, name, rpg_id):
self.name = name
self.rpg_id = rpg_id
self.__setStats()
def __setStats(self):
parser = SafeConfigParser()
parser.read('char_config.cfg')
for stat in Character.stats:
self.stat = parser.get(self.char_class, stat)
Thanks for your time!
You can use, setattr:
for stat in Character.stats:
setattr(self, stat, parser.get(self.char_class, stat))
Or manually access dict
for stat in Character.stats:
self.__dict__[stat] = parser.get(self.char_class, stat))
You want setattr(obj, attrname, value)
You better re-design that part of the game by adding a Stats class.
class Stats:
STATS = ["level_mod",
"power",
"speed",
"hit",
"evade",
"magic",
"stamina",
"magic_defense",
"intelligence"]
def __init__(self, conf_file=None):
self.__stats = {}
if conf_file is not None:
self.loads_stats_from_file(conf_file)
def load_stats_from_file(self, conf_file):
"""
Here add the pairs <stat_name>:<value>
to the self.__stats dict. For that just parse the config
file like before.
"""
pass
def get_stat(self, stat_name):
return self.__stats[stat_name]
def set_stat(self, stat_name, value):
self.__stats[stat_name] = value
Then you can add a Stats instance to your Character.
class Character(object):
def __init__(self, name, rpg_id):
self.stats = Stats("char_config.cfg")
self.name = name
self.rpg_id = rpg_id
This way you improve usability and decouple the Stats and Character logics. And besides, your problem is reduced from "Adding attributes to an object" to "Adding items to a dictionary".

Python: Preventing duplication of data when using dictionaries and lists

Hello Stack Overflow!
I am executing a simple command in a program that compiles a report of all the books contained in a library. The library contains a list of shelves, each shelves contains a dictionary of books. However, despite my best efforts, I am always duplicating all my books and placing them on every shelf, instead of the shelf I've instructed the program to place the book on.
I expect I have missed out on some kind of fundamental rule with object creation and organization.
I believe the culprits are the enshelf and unshelf methods in the book class.
Thank you so much for your time,
Jake
Code below:
class book():
shelf_number = None
def __init__(self, title, author):
super(book, self).__init__()
self.title = title
self.author = author
def enshelf(self, shelf_number):
self.shelf_number = shelf_number
SPL.shelves[self.shelf_number].books[hash(self)] = self
def unshelf(self):
del SPL.shelves[self.shelf_number].books[hash(self)]
return self
def get_title(self):
return self.title
def get_author(self):
return self.author
class shelf():
books = {}
def __init__(self):
super(shelf, self).__init__()
def get_books(self):
temp_list = []
for k in self.books.keys():
temp_list.append(self.books[k].get_title())
return temp_list
class library():
shelves = []
def __init__(self, name):
super(library, self).__init__()
self.name = name
def make_shelf(self):
temp = shelf()
self.shelves.append(temp)
def remove_shelf(shelf_number):
del shelves[shelf_number]
def report_all_books(self):
temp_list = []
for x in range(0,len(self.shelves)):
temp_list.append(self.shelves[x].get_books())
print(temp_list)
#---------------------------------------------------------------------------------------
#----------------------SEATTLE PUBLIC LIBARARY -----------------------------------------
#---------------------------------------------------------------------------------------
SPL = library("Seattle Public Library")
for x in range(0,3):
SPL.make_shelf()
b1 = book("matterhorn","karl marlantes")
b2 = book("my life","bill clinton")
b3 = book("decision points","george bush")
b1.enshelf(0)
b2.enshelf(1)
b3.enshelf(2)
print(SPL.report_all_books())
b1.unshelf()
b2.unshelf()
b3.unshelf()
OUTPUT:
[['decision points', 'my life', 'matterhorn'], ['decision points', 'my life', 'matterhorn'], ['decision points', 'my life', 'matterhorn']]
None
[Finished in 0.1s]
..instead of [["decision points"],["my life"],["matterhorn"]]
Use dict.pop() instead of del.
Add self.books = {} to shelf's __init__. Don't declare books outside of the __init__, because if you do so, all of the instances of that class are going to refer to the same thing. Instead, this makes each instance have its own dictionary, which is of course what you want since a book can't be in two shelves at once.
Do the same for library and its shelves and book and its shelf_number.
Pass a library instance as an argument to enshelf and unshelf. When you refer to SPL from within your objects' methods, Python finds that there is no local SPL defined, so it searches for one outside of the local scope; but if you were to try to assign something to SPL or do some other sort of mutative business, you would get an UnboundLocalError.
Bonuses:
class book(object), class shelf(object), and class library(object). (Won't fix your problem, but you should do that anyway.)
You don't need to hash the keys before using them, they will be hashed (if they are hashable, but if you're hashing them, then they are).
There is no need to call super() unless you are inheriting from something, in which case you can delegate a method call to a parent or sibling using it - but you aren't doing that.
get_books() can be implemented as nothing more than return [self.books[k].get_title() for k in self.books.iterkeys()]
Likewise for report_all_books(): return [shlf.get_books() for shlf in self.shelves]. Note that I am not iterating over the indices, but rather over the elements themselves. Try for c in "foobar": print(c) in the interactive shell if you want to see for yourself.

Binding checkbox to string in IronPython

How can I bind a checkbox to a string such that when the checkbox is checked/unchecked, the value of the string changes? I have this (with CheckAll as my checkbox):
class MyWindow(Window):
def __init__(self):
wpf.LoadComponent(self, 'BioApp1.xaml')
openDialog = SequenceFileOperations()
self.Sequences = openDialog.Open()
object = MyObjects(self.Sequences)
self.CheckAll.DataContext = object
self.IDLabel.DataContext = object
class MyObjects(object):
def __init__(self, Sequences):
self.CurrentSeq = Sequences[0]
self.ID = self.CurrentSeq.ID
and
<Label Height="28" HorizontalAlignment="Left" Margin="152,221,0,0" VerticalAlignment="Top" Width="98" Name="IDLabel" Content="{Binding Path=ID}"/>
I want that when the checkbox is unchecked, the label should display the sequence ID, but when it is checked, it should simply display “All”. For this I need to change the ID property of CurrentSeq to “All”. How do I do that by data binding? Is there any other way I can do this?
EDIT: I feel really stupid but I just can’t get this to work. I have been trying to follow the suggestion about using getter/setter but I guess I don’t know enough. Before doing anything more complicated, I simply want to make a button disabled when I tick the checkbox and enable it when I uncheck it. This is what I wrote:
class MyWindow(Window):
def __init__(self):
wpf.LoadComponent(self, 'App1.xaml')
object = BindingClass(self.Check, self.PreviousBtn)
self.PreviousBtn.DataContext = object
class BindingClass(object):
def __init__(self, Check, PreviousBtn):
self.Check = Check
self.PreviousBtn = PreviousBtn
def GetEnabledConverter(self):
if self.CheckAll.IsChecked:
return self.PreviousBtn.IsEnabled
def SetEnabledConverter(self):
if self.CheckAll.IsChecked:
self.PreviousBtn.IsEnabled = False
else:
self.PreviousBtn.IsEnabled = True
EnabledConverter = property(GetEnabledConverter, SetEnabledConverter)
And:
<Button Content="Previous" IsEnabled="{Binding Path=EnabledConverter}" />
Unfortunately there is no error but no effect either. The code does not do anything. Would really appreciate if you could help me out with this.
EDIT2: Using the notify_property, I tried this:
class MyWindow(Window):
def __init__(self):
wpf.LoadComponent(self, 'Test.xaml')
c = Converters(self.check1, self.Button)
self.Button.DataContext = c
class Converters(NotifyPropertyChangedBase):
def __init__(self, check, button):
super(Converters, self).__init__()
self.Check = check
self.Button = button
#notify_property
def ButtonEnabled(self):
return self.Button.IsEnabled
#ButtonEnabled.setter
def ButtonEnabled(self):
if self.Check.IsChecked:
self.Button.IsEnabled = False
else:
self.Button.IsEnabled = True
Still the same result: no effect. I just cannot understand where the problem is.
I would use Converter.
Edit:
You can implement converter in Python:
class BoolToVisibilityConverter(IValueConverter):
def Convert(self, value, targetType, parameter, culture):
return Visibility.Visible if value != val else Visibility.Collapsed
Last time I worked with WPF in IronPython, you could not use it directly in .xaml. I am not sure whether it has improved in 2.7.
Another possibility is to add another property which does the conversion (converted_ID) in its setter/getter. Thinking more about it, I would do rather this, because the code is in one place.
Edit 2:
Make sure, you are using notify_property instead of classic Python property.

Python classes from a for loop

I've got a piece of code which contains a for loop to draw things from an XML file;
for evoNode in node.getElementsByTagName('evolution'):
evoName = getText(evoNode.getElementsByTagName( "type")[0].childNodes)
evoId = getText(evoNode.getElementsByTagName( "typeid")[0].childNodes)
evoLevel = getText(evoNode.getElementsByTagName( "level")[0].childNodes)
evoCost = getText(evoNode.getElementsByTagName("costperlevel")[0].childNodes)
evolutions.append("%s x %s" % (evoLevel, evoName))
Currently it outputs into a list called evolutions as it says in the last line of that code, for this and several other for functions with very similar functionality I need it to output into a class instead.
class evolutions:
def __init__(self, evoName, evoId, evoLevel, evoCost)
self.evoName = evoName
self.evoId = evoId
self.evoLevel = evoLevel
self.evoCost = evoCost
How to create a series of instances of this class, each of which is a response from that for function? Or what is a core practical solution? This one doesn't really need the class but one of the others really does.
A list comprehension might be a little cleaner. I'd also move the parsing logic to the constructor to clean up the implemenation:
class Evolution:
def __init__(self, node):
self.node = node
self.type = property("type")
self.typeid = property("typeid")
self.level = property("level")
self.costperlevel = property("costperlevel")
def property(self, prop):
return getText(self.node.getElementsByTagName(prop)[0].childNodes)
evolutionList = [Evolution(evoNode) for evoNode in node.getElementsByTagName('evolution')]
Alternatively, you could use map:
evolutionList = map(Evolution, node.getElementsByTagName('evolution'))
for evoNode in node.getElementsByTagName('evolution'):
evoName = getText(evoNode.getElementsByTagName("type")[0].childNodes)
evoId = getText(evoNode.getElementsByTagName("typeid")[0].childNodes)
evoLevel = getText(evoNode.getElementsByTagName("level")[0].childNodes)
evoCost = getText(evoNode.getElementsByTagName("costperlevel")[0].childNodes)
temporaryEvo = Evolutions(evoName, evoId, evoLevel, evoCost)
evolutionList.append(temporaryEvo)
# Or you can go with the 1 liner
evolutionList.append(Evolutions(evoName, evoId, evoLevel, evoCost))
I renamed your list because it shared the same name as your class and was confusing.

Categories

Resources