AttributeError: 'int' object has no attribute 'items' - python

I have this piece of code and I am trying to understand it and get the output, but I get the error:
AttributeError: 'int' object has no attribute 'items'
def my_func(A: Set[int], B: List[Dict[int, C]]) -> \
List[Dict[int, C]]:
D = []
for b in B:
E = dict()
for a, m in b.items():
if a in A:
E[a] = m
D.append(E)
return D
A is a set :
A={1,2}
and C is a dictionary:
my_dic = {
1: C(
X=11.0,
Y=34.25,
a=1
),
2: C(
X=51.76,
Y=50.63,
a=2,
)
}
I call the function
X=my_func(A,my_dic)
but it gives me error. I also converted the dictionary to the list and it still gives me error but this time: 'tuple' object has no attribute 'items'. Would you please help me to understand the code better and be able to run it?

You define your func as follows:
def my_func(A: Set[int], B: List[Dict[int, C]])
You say that B will be a list of dict's. But then you call:
X=my_func(A,my_dic)
Where you pass in a single dict instead of the list defined before.
However, later in the func, you refer to .items(), which is a method callable on a dict, but not on a list or an int. When you pass in a single dict instead of a list of dicts, your code is trying to iterate over the element you passed in. Normally you would iterate over the elements of the list. But since you've passed in a dict, it will iterate over the keys of the dict. But your keys are set as int's, so then the .items() call fails.
So you just have to tighten up your call structure.
To quickly comply, you can change:
X=my_func(A,my_dic)
to:
X=my_func(A, [my_dic,])
That should help... At least now you'll be passing in a list of dicts, even if it is just a list of length one.

Because you passed a dictioanry where you were expecting a list (of dictionaries), for b in B: is now looping over the keys of that dictionary. Each key is an int, which you call items on, leading to the error you're seeing.
Try:
X = my_func(A, [my_dic])
Note that Python type signatures in this scenario are not being enforced at runtime. You have specified a list of dictionaries with ints as keys, and C as the value type. Python will not step you from calling: my_func(A, 42) but you will get a runtime error.

Related

Strange python dictionary keys

I encounter a strange dictionary. Let's call it cp_dict. When I type:
cp_dict['ZnS-Zn']
it returns:
{Element Zn: -1.159460605, Element S: -4.384479766249999}
The child key looks like a string but without quotation marks. How I can access the child keys (for example: Element Zn) and modify the values? I tried cp_dict['Zn3P2-Zn'][Element Zn], and the error is
SyntaxError: invalid syntax. Perhaps you forgot a comma?
The cp_dict['Zn3P2-Zn']['Element Zn'] leads to:
KeyError: 'Element Zn'
I checked type(cp_dict['ZnS-Zn']) . It returns <class 'dict'>.
It is quite easy to make a custom class which represents itself in that way ("looking like a string but without quotation marks"). The result returned by a __repr__ method is what gets used when representing instances inside collections such as dicts and lists:
>>> class Element:
... def __init__(self, symbol):
... self.symbol = symbol
... def __repr__(self):
... return f"Element {self.symbol}"
...
>>> d = {Element("Zn"): -1.159460605, Element("S"): -4.384479766249999}
>>> d
{Element Zn: -1.159460605, Element S: -4.384479766249999}
So, my guess is the keys of the dict are the strange items, not the dict itself. Check the type of a key, and look up it's __repr__ method. You can get the type of the first key with:
k = next(iter(cp_dict["ZnS-Zn"]))
Element = type(k)
To index the dict you will need an instance which compares equal with one of those keys. Again, look up type(k).__eq__ for that. If the __eq__ method is not customized, then you will need to use the identical key to index this dict, since the equality method will just be the default identity-based implementation which is inherited from object.

Unpack and assign a single return value from a multi-return function in one line (Python)

I'm trying to do the following, but it's not working:
agreements = getEligibleAndActiveAgreements(username).eligibleAgreements
for a function which returns 2 results. I don't want to assign a general variable first, like result = .., and then check result.eligibleAgreements, I want to quickly assign on the same line to a specific variable from just one return.
def getEligibleAndActiveAgreements(username):
...
return eligibleAgreements, activeAgreements
Error for getEligibleAndActiveAgreements(username).eligibleAgreements
AttributeError: 'tuple' object has no attribute 'eligibleAgreements'
Error for getEligibleAndActiveAgreements(username)['eligibleAgreements']
TypeError: tuple indices must be integers or slices, not str
Try either of these:
agreements, _ = getEligibleAndActiveAgreements(username)
# OR
agreements = getEligibleAndActiveAgreements(username)[0]
The function returns a tuple containing both values. In order to access the values independently you need to use index values (starting at 0) or just unpack into agreements and discard the other one.
The references of returned variables are known only locally inside function, when you call the function it doesn't know the references from the return x,y line, it's just a tuple outside function.
So you can do:
eligibleA, activeA = getEligibleAndActiveAgreements(username)
Or alternatively just return dict:
def getEligibleAndActiveAgreements(username):
...
return {"eligibleAgreements": eligibleAgreements, "activeAgreements": activeAgreements}
...
agreements = getEligibleAndActiveAgreements(username)
eligibleAgreements = agreements["eligibleAgreements"]

Python: item.method() and function(item)

What is the logic for picking some methods to be prefixed with the items they are used with, but some are functions that need items as the arguments?
For example:
L=[1,4,3]
print len(L) #function(item)
L.sort() #item.method()
I thought maybe the functions that modify the item need to be prefixed while the ones that return information about the item use it as an argument, but I'm not too sure.
Edit:
What I'm trying to ask is why does python not have L.len()? What is the difference between the nature of the two kinds of functions? Or was it randomly chosen that some operations will be methods while some will be functions?
One of the principles behind Python is There is Only One Way to Do It. In particular, to get the length of a sequence (array / tuple / xrange...), you always use len, regardless of the sequence type.
However, sorting is not supporting on all of those sequence types. This makes it more suitable to being a method.
a = [0,1,2]
b = (0,1,2)
c = xrange(3)
d = "abc"
print len(a), len(b), len(c), len(d) # Ok
a.sort() # Ok
b.sort() # AttributeError: 'tuple' object has no attribute 'sort'
c.sort() # AttributeError: 'xrange' object has no attribute 'sort'
d.sort() # AttributeError: 'str' object has no attribute 'sort'
Something that may help you understand a bit better: http://www.tutorialspoint.com/python/python_classes_objects.htm
What you describe as item.function() is actually a method, which is defined by the class that said item belongs to. You need to form a comprehensive understanding of function, class, object, method and maybe more in Python.
Just conceptually speaking, when you call L.sort(), the sort() method of type/class list actually accepts an argument usually by convention called self that represents the object/instance of the type/class list, in this case L. And sort just like a standalone sorted function but just applies the sorting logic to L itself. Comparatively, sorted function would require an iterable (a list, for example), to be its required argument in order to function.
Code example:
my_list = [2, 1, 3]
# .sort() is a list method that applies the sorting logic to a
# specific instance of list, in this case, my_list
my_list.sort()
# sorted is a built-in function that's more generic which can be
# used on any iterable of Python, including list type
sorted(my_list)
There's a bigger difference between methods and functions than just their syntax.
def foo():
print "function!"
class ExampleClass(object):
def foo(self):
print "method!"
In this example, i defined a function foo and a class ExampleClass with 1 method, foo.
Let's try to use them:
>>> foo()
function!
>>> e = ExampleClass()
>>> e.foo()
method!
>>> l = [3,4,5]
>>> l.foo()
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
l.foo()
AttributeError: 'list' object has no attribute 'foo'
>>>
Even though both have the same name, Python knows that if you do foo(), your calling a function, so it'll check if there's any function defined with that name.
And if you do a.foo(), it knows you're calling a method, so it'll check if there's a method foo defined for objects of the type a has, and if there is, it will call it. In the last example, we try that with a list and it gives us an error because lists don't have a foo method defined.

Python sort with key=lambda gets TypeError

I am trying to sort a list of objects in Python 3.4 based on the value of the data attribute of each object. If I use
db[count].sort(key=lambda a: a.data)
everything works fine. However, I want the sort to be case insensitive so I use
db[count].sort(key=lambda a: a.data.lower)
but then I get
db[count].sort(key=lambda a: a.data.lower)
TypeError: unorderable types: builtin_function_or_method() < builtin_function_or_method()
Any ideas?
key has to be a callable that returns a value to be sorted. In your case it returns another callable a.data.lower. You need to call lower in order to get the value, so the correct form is:
db[count].sort(key=lambda a: a.data.lower())
You are passing a reference to the lower method instead of calling it.
Try this:
db[count].sort(key=lambda a: a.data.lower())

Sorting a list: int object not callable

I have a long and complicated method, I'll give the important parts:
def get_itter(self, sort_by=0): #sort_by is set to 0 for debugging purposes
...
r = self.parser(self.in_file) # parse a csv file
...
if type(sort_by) == int:
r = [i for i in r]
sort = sorted(r, key=sort_by)
...
Now my problem is that when I run this code it gives me an error: TypeError: 'int' object is not callable. Why is it giving me this error?
P.S. I am relatively new to Python and am trying to add some functionality to code that I did not write.
You set:
sort_by=0
check it's an int
if type(sort_by) == int: # note: isinstance(sort_by, int) is preferred here
then use it:
sorted(r, key=sort_by)
When you pass a key to sorted, it tries to apply that key to all items in the sequence it's sorting, trying to call it with each item, something like:
sortvalues = [key(i) for i in seq]
If key is an integer, you can't call it:
0(1)
gives the TypeError you are seeing.
It's not clear exactly what you're trying to do, but if you want to sort by the sort_byth item in a sequence, you can use operator.itemgetter:
from operator import itemgetter
sorted(r, key=itemgetter(sort_by))
You set sort_by to 0 and then pass that as the key function to sorted. Python will call key as a function to define the sorting key, which isn't possible for 0.

Categories