When I test/debug my Python code interactively, I'm often sidetracked by accidental mis-spellings - they make me think something is wrong with my code when there isn't.
For example, my object c has a setter for the subframe property:
c.suframe = (0,0,256,256); i = c.snap(verbose=False); print(c._last_transfer_duration); show(i*10)
I expected to get a 256x256 subframe, but because I spelled it suframe instead of subframe, I'd just created an attribute suframe and there was (unexpectedly) no effect on subframing. This was an interactive typo, not a code bug. But I had to notice the misspelling to figure that out.
Is there a simple way to get Python to complain so I notice that the misspelling, instead of silently accepting the new attribute?
(Lint won't help - this is interactive debugging, not code in a file.)
[FWIW, I'm using iPython.]
Related
I'm just starting to learn Python 3.9 as my first language. I have been fighting with this error for a while now, and I can't figure out what the issue is.
Here's what I'm working on:
def eval_express(eqstring[0], eqstring[1], eqstring[2]):
eqstring[0], eqstring[2] = float(eqstring[0]), float(eqstring[2])
return opdict[eqstring[1]](eqstring[0], eqstring[2])
I'm receiving an error that the "(" after eval_express is not closed, but as far as I can tell it is. At first, I thought it was just a glitch, but despite numerous attempts to rewrite it, increase/decrease the number of arguments, etc. it persisted. The error cropped up after I modified the arguments from variables to list items, but I don't see why that would affect it. Can anyone provide some clarification on what the program's getting hung up on?
Thank you for your help!
You are using square brackets inside the function parameters, which is not valid. Valid code would be:
def eval_express(eqstring0, eqstring1, eqstring2):
eqstring0, eqstring2 = float(eqstring0), float(eqstring2)
return opdict[eqstring1](eqstring0, eqstring2)
although you should probably use more descriptive parameter names.
You can't use parameter[] notation when entering a parameter to a function. Instead just use parameter, or you will have to do something like.
def eval_express(eqstring):
eqstring[0], eqstring[2] = float(eqstring[0]), float(eqstring[2])
return opdict[eqstring[1]](eqstring[0], eqstring[2])
Now you have to pass an array as the function parameter.
I've been trying to sort an array of number using the sort function but I forgot to write parentheses.
arr.sort
instead of
arr.sort()
My question is why can't python detect this error and inform me like Java can?
The program kept compiling fine but because I was inputting the numbers in ascending order, the problem wouldn't show up.
arr.sort is syntactically valid. It's just not the syntax you wanted. Syntactically, arr.sort is an attribute access expression for the sort attribute of whatever arr evaluates to; semantically, when arr is a list, arr.sort evaluates to a method object for arr's sort method, so it's perfectly fine at runtime too.
It's kind of like method references in Java, but since Python is dynamically typed and has method objects, it doesn't need to go through all the functional interface and poly expression stuff Java 8 had to add to support list::sort syntax.
Syntax errors are only for outright invalid syntax.
Because it is not an error.
When you do not include () the function (or method) is not called. Instead it returns the function.
Example:
>>> str.encode
<method 'encode' of 'str' objects>
In actual practice:
import tkinter as tk
def hello():
print('hello')
tk.Frame()
a = tk.button(text="Press", command=hello)
a.pack()
tk.mainloop()
Now if you try it with command=hello() then it calls the function without you actually pressing the button.
The reason why Python can't detect this type of error is because Python is dynamically typed, whereas Java is statically typed.
When you say a = arr.sort, python assigns the function to a. Now you can do a() and it will run arr.sort. This is a totally valid thing to do in Python, and since we don't tell it ahead of time what a should be, it can't know whether you meant a to be a function or a sorted list... it just trusts you know what you're doing.
Java, on the other hand, is statically typed: You tell it ahead of time what a should be. Therefore, when you accidentally leave off parens, it says "that's a function, not a list like you said it would be".
If you use an IDE like PyCharm, it will tell you lots of warnings along these lines:
self.function shows:
Statement seems to have no effect and can be replaced with function call to have an effect
but the moment we assign it:
a = self.function it has an effect and this cannot be detected.
I just realized there is something mysterious (at least for me) in the way you can add vertex instructions in Kivy with the with Python statement. For example, the way with is used goes something like this:
... some code
class MyWidget(Widget)
... some code
def some_method (self):
with self.canvas:
Rectangle(pos=self.pos, size=self.size)
At the beginning I thought that it was just the with Python statement that I have used occasionally. But suddenly I realize it is not. Usually it looks more like this (example taken from here):
with open('output.txt', 'w') as f:
f.write('Hi there!')
There is usually an as after the instance and something like and alias to the object. In the Kivy example we don't define and alias which is still ok. But the part that puzzles me is that instruction Rectangle is still associated to the self.canvas. After reading about the with statement, I am quite convinced that the Kivy code should be written like:
class MyWidget(Widget)
... some code
def some_method (self):
with self.canvas as c:
c.add (Rectangle(pos=self.pos, size=self.size))
I am assuming that internally the method add is the one being called. The assumption is based that we can simply add the rectangles with self.add (Rectangle(pos=self.pos, size=self.size))
Am I missing something about the with Python statement? or is this somehow something Kivy implements?
I don't know Kivy, but I think I can guess how this specific construction work.
Instead of keeping a handle to the object you are interacting with (the canvas?), the with statement is programmed to store it in some global variable, hidden to you. Then, the statements you use inside with use that global variable to retrieve the object. At the end of the block, the global variable is cleared as part of cleanup.
The result is a trade-off: code is less explicit (which is usually a desired feature in Python). However, the code is shorter, which might lead to easier understanding (with the assumption that the reader knows how Kivy works). This is actually one of the techniques of making embedded DSLs in Python.
There are some technicalities involved. For example, if you want to be able to nest such constructions (put one with inside another), instead of a simple global variable you would want to use a global variable that keeps a stack of such objects. Also, if you need to deal with threading, you would use a thread-local variable instead of a global one. But the generic mechanism is still the same—Kivy uses some state which is kept in a place outside your direct control.
There is nothing extra magical with the with statement, but perhaps you are unaware of how it works?
In order for any object to be used in a with statement it must implement two methods: __enter__ and __exit__. __enter__ is called when the with block is entered, and __exit__ is called when the block is exited for any reason.
What the object does in its __enter__ method is, of course, up to it. Since I don't have the Kivy code I can only guess that its canvas.__enter__ method sets a global variable somewhere, and that Rectangle checks that global to see where it should be drawing.
This emerged from my related question. I currently have the following binding:
myBinding = Binding("[foo]")
myBinding.Mode = System.Windows.Data.BindingMode.TwoWay
myBinding.Source = obj
acheckbox.SetBinding(CheckBox.IsCheckedProperty, myBinding)
acheckbox.DataContext = obj
This will look at obj[foo]. The UI will update the source just fine - I can check the checkbox and obj[foo] is changed. However, the reverse is not working. Changing obj[foo] in code does not update the UI, even with this code manually calling OnPropertyChanged:
obj[foo] = False
obj._OnPropertyChanged(obj, System.ComponentModel.PropertyChangedEventArgs("[foo]"))
The problem likely lies with the arguments to OnPropertyChanged. Some digging (and help from H.B.) revealed this post:
http://10rem.net/blog/2010/03/08/wpf---silverlight-quick-tip-inotifypropertychanged-for-indexer
If you're creating the data source for
those (for example, you are building
your own ObservableDictionary), you
may wonder how on earth you fire the
appropriate
INotifyPropertyChanged.PropertyChanged
event to let the binding system know
that the item with that field name or
index has changed.
The binding system
is looking for a property named
"Item[]", defined by the constant
string Binding.IndexerName.
In other words, Binding.IndexerName is a constant, "Item[]", that tells the binding engine to rescan the whole source dictionary.
obj._OnPropertyChanged(obj, System.ComponentModel.PropertyChangedEventArgs(Binding.IndexerName))
# equivalent to:
obj._OnPropertyChanged(obj, System.ComponentModel.PropertyChangedEventArgs("Item[]"))
Unfortunately, scanning the entire source dictionary happens to be an expensive operation in my code; so that post also talks about using "Item[foo]" as the argument. This is exactly what I need - and it doesn't work! Only Item[] works. Why?
According to mamadero2 in this thread Item[index] only works in Silverlight 4.
(I never would have imagined that Silverlight supports something that WPF does not)
So I'm learning python, and I seem to be having a consistent problem with calling setText() methods on Text objects. The process works fine when I'm in the interactive IDLE GUI, but when I save modules and then try to run them, I get:
nonetype object has no attribute setText
Do I need to assign some sort of return type to the text assignment? Why would there be different behavior from IDLE to saved modules? I've searched the site and Python documentation and was unable to turn up anything. Any help would be much appreciated.
message1 = Text(Point(50,50), "Click).draw(win)
message1.setText("")
Edited to add…
Thanks Geo, your suggestion fixed things.
Now my question is, what's the difference between...
message = Text(Point(50,50), "Click").draw(win)
… and …
message = Text(Point(50,50), "Click")
message.draw(win)
… with regards to returning something, or ensuring that the message object has a type that supports certain functions?
Perhaps the draw method is not returning anything. Try changing your code to this:
message1 = Text(Point(50,50), "Click")
message1.draw(win)
message1.setText("")
I'm not sure how to answer your second question properly..so I'll just do it as an answer here.
The reason the first does not work is because you are assigning the return value of Text.draw to message. Since it returns nothing, then message is None.
In the working code, you assign message with the type Text and initialize the object. You then call the draw method of this object, and the setText method.
In the non-working code, you are calling the draw method on a new Text object, then assigning the return of that - that is, NoneType - to message. And since None has no setText method, you get an error.
(Sorry if I have mixed up NoneType and None there)