PYTHON - Unhashable List - python

I am trying to display some information in a GUI list-box. I have written a test method in a model only portion of my MVC which outputs the information I want; however, when I transfer that code to my full GUI, it throws me an error.
Here are the two pieces of code:
Model: (note that this method is written for a class Products())
def test(self):
for key in self._items_list:
print self.get_item(key) #this refers to the get_item function of the Products class:
def get_item(self, key):
return self._items_list[key] # items_list is a dictionary
So, this returns the output I would like to put in my list-box.
Here is how I transfer the code to my GUI (this is in a class i defined which inherits from Listbox):
def refreshData(self):
for keys in self._productslist: #this productslist is equivalent to items_list
disp = self._products.get_item(keys) #so i can call the method from the Product class
self.insert(END, dips)
This throws me the following error when I try to open and display the file:
...in get_item
return self._items_list[key]
TypeError: unhashable type: 'list'
Sorry, this is long and probably very confusing, but essentially I want to know why I get the error for the method in the full version of the code and not in the isolated model.
All the relevant code is identical as far as I know.
Any ideas would be greatly appreciated!

You can't hash lists, only immutable things. Although you could define a __hash__ method for some extension of the list object, the reason behind this logic is that if you were to look something up in a dictionary, you would expect the entries' names not to change. Similarly, in python, the keys must be immutable. As another answer said, use a tuple instead.

Use tuples instead:
http://wiki.python.org/moin/DictionaryKeys

Related

How to dynamically return Object attributes in python, including attributes of objects that are attributes

I am trying to write a testing program for a python program that takes data, does calculations on it, then puts the output in a class instance object. This object contains several other objects, each with their own attributes. I'm trying to access all the attributes and sub-attributes dynamically with a one size fits all solution, corresponding to elements in a dictionary I wrote to cycle through and get all those attributes for printing onto a test output file.
Edit: this may not be clear from the above but I have a list of the attributes I want, so using something to actually get those attributes is not a problem, although I'm aware python has methods that accomplish this. What I need to do is to be able to get all of those attributes with the same function call, regardless of whether they are top level object attributes or attributes of object attributes.
Python is having some trouble with this - first I tried doing something like this:
for string in attr_dictionary:
...
outputFile.print(outputclass.string)
...
But Python did not like this, and returned an AttributeError
After checking SE, I learned that this is a supposed solution:
for string in attr_dictionary:
...
outputFile.print(getattr(outputclass, string))
...
The only problem is - I want to dynamically access the attributes of objects that are attributes of outputclass. So ideally it would be something like outputclass.objectAttribute.attribute, but this does not work in python. When I use getattr(outputclass, objectAttribute.string), python returns an AttributeError
Any good solution here?
One thing I have thought of trying is creating methods to return those sub-attributes, something like:
class outputObject:
...
def attributeIWant(self,...):
return self.subObject.attributeIWant
...
Even then, it seems like getattr() will return an error because attributeIWant() is supposed to be a function call, it's not actually an attribute. I'm not certain that this is even within the capabilities of Python to make this happen.
Thank you in advance for reading and/or responding, if anyone is familiar with a way to do this it would save me a bunch of refactoring or additional code.
edit: Additional Clarification
The class for example is outputData, and inside that class you could have and instance of the class furtherData, which has the attribute dataIWant:
class outputData:
example: furtherData
example = furtherData()
example.dataIWant = someData
...
with the python getattr I can't access both attributes directly in outputData and attributes of example unless I use separate calls, the attribute of example needs two calls to getattr.
Edit2: I have found a solution I think works for this, see below
I was able to figure this out - I just wrote a quick function that splits the attribute string (for example outputObj.subObj.propertyIWant) then proceeds down the resultant array, calling getattr on each subobject until it reaches the end of the array and returns the actual attribute.
Code:
def obtainAttribute(sample, attributeString: str):
baseObj = sample
attrArray = attributeString.split(".")
for string in attrArray:
if(attrArray.index(string) == (len(attrArray) - 1)):
return getattr(baseObj,string)
else:
baseObj = getattr(baseObj,string)
return "failed"
sample is the object and attributeString is, for example object.subObject.attributeYouWant

python dictionaries and items()

My understanding is that .items() is only avaliable for python dictionaries.
However in the following bit of code, which runs perfectly, it appears that the .items() function is avaliable for a string. (This code is for the preprocessing stage of doc2vec )
I have looked at this for a while and I can't figure out why the .items() seems to work in this piece of code.
In the code, 'sources' is just an attribute of an instance. Yet it is able to call .items().
What am I missing here?
class LabeledLineSentence(object):
def __init__(self, sources):
self.sources = sources
flipped = {}
# make sure that keys are unique
for key, value in sources.items():
if value not in flipped:
flipped[value] = [key]
else:
raise Exception('Non-unique prefix encountered')
The given code only specifies that sources is an attribute of an instance. It doesn't specify its type. In fact it can be any type that is specified at the time of creating an instance of LabeledLineSentence.
i1 = LabeledLineSentence('sample text') # sources is now a string. Throws error!
i2 = LabeledLineSentence({}) # source is a now a dictionary. No error!
Note that LabeledLineSentence implementation expects the sources parameter to be a dictionary.
.items() is available for any class with an items method. For instance, I can define
class MyClass:
def items(self):
return [1,2,3,4]
and then run
mc = MyClass()
for i in mc.items(): print(i)
Presumably your sources object is of a class that has such an attribute. But we don't know what, since it's an argument to the constructor of LabeledLineSentence.
Can you point us to the full source code? Then we might be able to see what is being passed in.

tab complete key for __getitem__ in Python class

I'm implementing a python class that contains a 2d numpy array (self.data) that I have set up for column access with a string key.
The keys are contained in a dict that maps names to column indices (e.g., self.coldict={'col0':0,...,'colN':N}), and I've defined
def __getitem__(self,key):
if isinstance(key,str):
return self.data[:,self.coldict[key]]
elif isinstance(key,int):
return self.data[:,key]
This works as intended for column retrieval.
I'd like to be able to use tab complete for the key so that I can type
myObject['c+TAB during an iPython session to get completion options.
I think a solution should rely on readline or prompt_toolkit, but it's not clear to me how to implement a completer function without overriding the already-active functionality in iPython.
Any help is much appreciated.
Thanks!
I'm not sure if you can tab complete a string for __getitem__. Tab completion is usually for object attribtues. Tab completion uses the items defined in the __dict__ instance dictionary and the __dir__(self) method.
If you want tab completion for the accessing an attribute you can.
class MyArray:
...
def __dir__(self):
return super().__dir__() + list(self.coldict.keys())
def __getattr__(self, name):
if name in self.coldict:
return self.data[:,self.coldict[name]]
return super().__getattr__(name)
You would then access your column with
arr = MyArray() # My numpy array
print(arr.col0) # col0 should allow for tab complete.
It was hard to track down, but this is how it's done (reference 1 and 2):
You can also customize key completions for your objects, e.g. pressing tab after obj["a. To do so, define a method _ipython_key_completions_(), which returns a list of objects which are possible keys in a subscript expression obj[key].
I got this working by simply adding a method called _ipython_key_completions_ to a custom class that returns all the possible string keys that can be used when calling __getitem__. What I didn't realize is that Python dicts already do this as well as Pandas DataFrames.

what's the right way to put *arg in a tuple that can be sorted?

I want a dict or tuple I can sort based on attributes of the objects I'm using as arguments for *arg. The way I've been trying to do it just gives me AttributeErrors, which leads me to believe I'm doing it weird.
def function(*arg):
items = {}
for thing in arg:
items.update({thing.name:thing})
while True:
for thing in items:
## lots of other code here, basically just a game loop.
## Problem is that the 'turn order' is based on whatever
## Python decides the order of arguments is inside "items".
## I'd like to be able to sort the dict based on each object's
## attributes (ie, highest 'thing.speed' goes first in the while loop)
The problem is when I try to sort "items" based on an attribute of the objects I put into function(), it gives me "AttributeError: 'str' object has no attribute 'attribute'". Which leads me to believe I'm either unpacking *arg in a lousy way, or I'm trying to do something the wrong way.
while True:
for thing in sorted(items, key=attrgetter('attribute')):
...doesn't work either, keeps telling me I'm trying to manipulate a 'str' object. What am I not doing here?
arg already is a tuple you can sort by an attribute of each item:
def function(*args):
for thing in sorted(args, key=attrgetter('attribute')):
When you iterate over a dict, as sorted is doing, you just get the keys, not the values. So, if you want to use a dict, you need to do:
def function(*args):
# or use a dict comprehension on 2.7+
items = dict((thing.name, thing) for thing in args)
# or just items.values on 3+
for thing in sorted(items.itervalues(), key=attrgetter('attribute')):
to actually sort the args by an attribute. If you want the keys of the dict available as well (not necessary here because the key is also an attribute of the item), use something like:
for name, thing in sorted(items.iteritems(), key=lambda item: item[1].attribute):
Your items is a dict, you can't properly sort a dict. When you try to use it as an iterable, it silently returns its keys list, which is a list of strings. And you don't use your arg after creating a dict.
If you don't need dict lookup, as you just iterate through it, you can replace dict with list of 2-tuples (thing.name, thing), sort it by any attribute and iterate through it. You can also use collections.OrderedDict from Python 2.7 (it exists as a separate ordereddict package for earlier versions) if you really want both dict lookup and ordering.
{edit} Thanks to agf, I understood the problem. So, what I wrote below is a good answer in itself, but not when related to the question above... I let it here for the trace.
Looking to the answers, I may have not understood the question. But here's my understanding: as args is a tuple of arguments you give to your function, it's likely that none of these arguments is an object with a name attribute. But, looking to the errors you report, you're giving string arguments.
Maybe some illustration will help my description:
>>> # defining a function using name attribute
>>> def f(*args):
... for arg in args:
... print arg.name
>>> # defining an object with a name attribute
>>> class o(object):
... def __init__(self, name):
... self.name = name
>>> # now applying the function on the previous object, and on a string
>>> f( o('arg 1'), 'arg 2' )
arg 1
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
f(o('arg 1'), 'ets')
File "<pyshell#3>", line 3, in f
print arg.name
AttributeError: 'str' object has no attribute 'name'
This is failing as strings have no such attribute.
For me, in your code, there is a mistake: you're trying to use attribute name on your inputs, without ever verifying that they have such an attribute. Maybe you should test with hasattr first:
>>> if hasattr(arg, 'name'):
... print arg.name
... else:
... print arg
or with some inspection on the input, to verify if it's an instance of a given class, known to have the requested attribute.

How do I tell what type of data is inside python variable?

I have a list of variables.. inside the list are strings, numbers, and class objects. I need to perform logic based on each different type of data. I am having trouble detecting class objects and branching my logic at that point.
if(type(lists[listname][0]).__name__ == 'str'): # <--- this works for strings
elif(type(lists[listname][0]).__name__ == 'object'): <--- this does not work for classes
in the second line of code above, the name variable contains "Address" as the class name. I was hoping it would contain "class" or "object" so I could branch my program. I will have many different types of objects in the future, so it's a bit impractical to perform logic on every different class name, "Address" "Person" etc
please let me know if my question needs clarification.
thanks!!
FYI: it also makes a difference if its a new-style class or not:
# python
type(1).__name__
'int'
type('1').__name__
'str'
class foo(object):
pass
type(foo()).__name__
'foo'
class bar:
pass
type(bar()).__name__
'instance'
If you can make sure they're all new-style classes, your method will determine the real type. If you make them old-style, it'll show up as 'instance'. Not that I'm recommending making everything all old-style just for this.
However, you can take it one step further:
type(bar().__class__).__name__
'classobj'
type(foo().__class__).__name__
'type'
And always look for 'classobj' or 'type'. (Or the name of the metaclass, if it has one.)
I think you want the isinstance function.
if isinstance(o, ClassName):
However, you'll need to first verify that o is an object, you can use type for that.
It's common in Python to use exception handling to decide which code path to take; inspecting the exact type of an object (with isinstance()) to decide what to do with it is discouraged.
For example, say that what you want to do is, if it's a string, print it in "title case", and if it's an object, you want to call a particular method on it. So:
try:
# is it an object with a particular method?
lists[listname][0].particularMethod()
except AttributeError:
# no, it doesn't have particularMethod(),
# so we expect it to be a string; print it in title case
print lists[listname][0].title()
If you are only interested in handling two types specifically, you could test for them explicitly using isinstance and then handle the leftovers:
import numbers
for item in list:
if isinstance(item, basestring): # (str, unicode)
do_string_thing(item)
elif isinstance(item, numbers.Real): # (int, float, long)
do_number_thing(item)
else:
do_object_thing(item)

Categories

Resources