list() method on tkinter object(s) fails - python

When it comes to wrapping a tkinter object (or multiple) in a list, there seems to be a descrepency between using the square bracket operators [] vs. the list() constructor:
In 1:
>>> import tkinter as tk
>>> list(tk.Entry())
Out 1:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Program Files\Python36\lib\tkinter\__init__.py", line 1486, in cget
return self.tk.call(self._w, 'cget', '-' + key)
TypeError: must be str, not int
In 2:
>>> [tk.Entry()]
Out 2:
[<tkinter.Entry object .!entry2>]
This is quite confusing considering that type(tk.Entry()) yields <class 'tkinter.Entry'> as expected, not int. Thanks in advance.

As you have been told in the comments, list(x) and [x] are not the same.
The nature of the reported error is more interesting. When you attempt to convert an Entry to a list, list() calls the method __getitem__ from the Entry. For whatever reason, this method is implemented as an alias to Entry.cget():
x = tk.Entry()
x.cget == x.__getitem__
#True
So, list(x) calls x.__getitem__(0) to obtain the first element of the anticipated iterable. This, in turn, calls x.cget(0); this, in turn, attempts to obtain the value of the widget configuration option '-' + 0. The latter operation is invalid and results in the error message that you observed.

Related

Sorting a list with int and str elements

So in my class the professor gave us this insertion-based sorting code, but I need it to sort lists that have numbers and text.
I've already tried using if isinstance conditions, but it seems the problem is in the while loop
def insertion_sort(vector):
print(vector)
for i in range(1,len(vector)):
actual=vector[i]
j=i
while j>0 and actual<vector[j-1]: #This is where the problem seems
vector[j]=vector[j-1] #to be.
j=j-1
vector[j]=actual
return vector
This is the output error message:
Traceback (most recent call last):
File "F:\Python\sortactivity.py", line 53, in <module>
print(insertion_sort(text))
File "F:\Python\sort.py", line 9, in insertion_sort
while j>0 and actual<vector[j-1]:
TypeError: '<' not supported between instances of 'int' and 'str'
The testing list that I have is:
lst=['s9','d5',9,5,1,24,12,'test',21]

Extending peewee expressions throws 'Expression' object is not iterable

I want to dynamically create where-clauses in peewee. I learned I need to use expressions, but cannot get this to run. Here my code:
clauses = [
(Docs.language_frst == 0),
(Docs.body_len <= max_body_len),
(Docs.body_len >= min_body_len)
]
if len(aValid_ids_used):
clauses.extend( (Docs.id.not_in(aValid_ids_used)) )
docids = Docs.select(Docs.id).where(reduce(operator.and_, clauses))
As long as aValid_ids_used is empty the code runs fine. Once aValid_ids_used is not empty any longer and I am asking the clauses to be extended I get an error:
Traceback (most recent call last): File "xyz.py", line 170, in <module>
clauses.extend( (Docs.id.not_in(aValid_ids_used)) )
TypeError: 'Expression' object is not iterable
You need to pass a list to extend with. You're currently passing an Expression
clauses.extend( (Docs.id.not_in(aValid_ids_used), ) )
e.g.
>>> c = []
>>> c.extend((2))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>> c.extend((2,))
>>> c
[2]
You probably want to use list.append rather than list.extend. extend takes a list as an argument, while append takes a single item.

I'm unable to print my list using the format I specified beforehand

This is what I'm trying to do:
LAYOUT = "{!s:4} {!s:11} {!s:10} {!s:10} {!s:15} {!s:10} {!s:10} {!s:15} {!s:10} {!s:10}"
Item_1 = [002,"Cucharas",12.3,12.5,"4/5/16",200,12.5,"4/6/16",150,140]
print LAYOUT.format("UPC", "Item", "Cost", "Price", "F_Comp", "QTY", "Profit", "F_Venta", "QTY_Sold", "QTY_Alm")
print LAYOUT.format[Item_1]
I want to print several lists using LAYOUT. I actually took this method of formatting from another answer here, but I keep getting the following error:
Traceback (most recent call last):
File "main.py", line 6, in <module>
print LAYOUT.format[Item_1]
TypeError: 'builtin_function_or_method' object has no attribute '__getitem__'
Square brackets, [], are generally used for indexing and slicing, which calls the object's __getitem__ method, which the str.format function does not have. Use parentheses like you did in the previous line, and unpack the iterable with *:
print LAYOUT.format(*Item_1)

Why can't I add <some list>.append to a python set?

Why is it that I can add normal callables and methods to a set, but not <some list>.append (for instance)?
For Example:
>>> l = []
>>> s = set()
>>> s.add(l.append)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> type(l.append)
<type 'builtin_function_or_method'>
>>> type(map)
<type 'builtin_function_or_method'>
>>> s.add(map)
>>> def func(): print 'func'
...
>>> s.add(func)
>>> print s
set([<built-in function map>, <function func at 0x10a659758>])
Edit: I noticed that l.append.__hash__() also gives this error
You cannot add lists to a set because lists are mutable. Only immutable objects can be added to sets.
l.append is an instance method. You can think of it as if it were the tuple (l, list.append) — that is, it's the list.append() method tied to the particular list l. The list.append() method is immutable but l is not. So while you can add list.append to the set you can't add l.append.
This works:
>>> s.add(list.append)
This does not work:
>>> s.add((l, list.append))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
You're not trying to add list.append. You're trying to add l.append which is an instance method, not a class method. list instances aren't hashable, and apparently their methods aren't hashable either.
Think of it this way. You have 2 lists:
lfoo = []
lbar = []
Now you want to add their respective appends to your set:
s = set()
s.add(lfoo.append)
s.add(lbar.append)
Now when you do the hash lookup for the set, you can't just rely on the function portion of the instance method. Indeed, lfoo and lbar ultimately use the same function (list.append). So that isn't a unique hash. The way you make it unique is by attaching it to an instance. However, the instance doesn't support hashing, so the set has no way of telling the difference between lfoo.append and lbar.append.
In Python, list objects aren't hashable. I suspect that when you hash an instance method, it incorporates the hash of the instance its bound to. As such, you get the TypeError.

Cases where use of tuple is a must

In Python, the only difference between a list and a tuple that I know of is "lists are mutable but tuples are not". But as far as I believe, it depends on whether the coder wants to risk mutability or not.
So I was wondering whether there are any cases where the use of a tuple over a list is a must. Things that can not be done with a list but can be done with a tuple?
You can use tuples as keys in dictionaries and insert tuples into sets:
>>> {}[tuple()] = 1
>>> {}[list()] = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Which is basically a result of a tuple being hashable while a list isn't:
>>> hash(list())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash(tuple())
3527539
The answer by #Otto is very good. The only thing I have to add to it is that when you open things up to 3rd party extensions, you really need to consult the documentation. Some functions/methods may expect one or the other data-type (or have different results depending on which one you use). One example is using tuples/lists to index a numpy array:
import numpy as np
a=np.arange(50)
a[[1,4,8]] #array([1, 4, 8])
a[(1,4,8)] #IndexError
EDIT
Also, a quick timing test shows that tuple creation is MUCH FASTER than list creation:
import timeit
t=timeit.timeit('[1,2,3]',number=10000000)
print (t)
t=timeit.timeit('(1,2,3)',number=10000000)
print (t)
which is good to keep in mind. In other words, do:
for num in (8, 15, 200):
pass
instead of:
for num in [8, 15, 200]:
pass
Also, the now obsolete string formatting using the % operator requires the argument list to be a tuple. A list would be treated as single argument:
>>> "%s + %s" % [1, 2]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string
>>> "%s + %s" % (1, 2)
'1 + 2'

Categories

Resources