I have recently taught a short Python crash course to 1st-3rd year Computer Science students the majority of whom knew only C and C++, and even that not so well. My approach was quite different from what you are suggesting.
Disclaimer: The aim of my course was to introduce the language to people who are already familiar with basic ideas of programming, so this might not be appropriate if you are teaching people who have never been exposed to programming at all.
- First, I did a short introduction to the language with its strengths and weaknesses and showing some simple Python programs that even someone who does not know Python can easily get.
- Then I did a thorough run through data structures, using the REPL prompt extensively for examples. Sure, at this point they could not write a program, but writing any program (even if just a toy example) without using data structures is really not what Python is about; I would even say that attempting that suggests unpythonic habits to the students. I went in this order:
- Numbers (
int -> float
)
- Sequences (
list & tuple -> string -> bytearray
)
- Sets
- Dictionaries
- Bools, including auto-casting to bools.
- Next up was the basic syntax, in the order:
- Statements (line breaks, etc.)
- Printing
- Variables, focusing on the peculiarities of dynamic binding and the major difference between the C concept of variables and its Python counterpart.
- Conditionals
- Loops
- List comprehension
- Function/method calls, including function chaining, keyword parameters and argument lists.
- Modules, including importing and dealing with namespaces.
- Forth was a deep dive into functions. There's a surprising lot to teach about Python functions, including various ways of defining arguments (keywords, lists), multiple returns, docstrings, scoping (a large subject area by itself), and an important but oft-missed part which is using functions as objects, passing them around, using lambdas, etc.
- Fifth was a more practical overview of files including I/O and encoding issues and exceptions (concept -> catching -> raising).
- Finally an overview of OO features in Python, including instance variables, method types (instance/class/static), inheritance, method naming (private, mangled, special), etc.
For your particular questions:
For instance, my predecessor introduced lists before strings. I think the opposite is a better solution.
I disagree. Conceptually, a string is just a list that gets a lot of special treatment, so it makes sense to build upon the simpler list concept. If you start with data structures as I did, you also won't have to deal with not being able to use strings in I/O examples.
Should function definitions be introduced at the very beginning or after mastering basic structured programming ideas, such as decisions (if) and loops (while)?
Definitely after. Calling functions should be taught around the same time as basic structured programming ideas, but defining your own should be postponed.
Should sets be introduced before dictionaries?
Well, dictionaries are certainly much more used in practice, but if you've introduced sequences, explaining sets (especially to math students) shouldn't take long, and it makes sense to progress from simpler to more complex structures.
Is it better to introduce reading and writing files early in the course or should one use input and print for most of the course?
Python's IO capabilities are really simple, so it shouldn't matter much, but I'd say these are unnecessary for basic exercises, so you might as well leave them off for the second half of the course.
In my view, at each stage the students should be able to solve a non-trivial programming problem using only the tools available at that time. Each new tool should enable a simpler solution to a familiar problem.
The incremental approach is obviously very different from my more academic one, but it certainly has its advantages, not least of which is that it keeps people more interested. However, I always disliked the fact that when you're done with learning a subject this way, you are left with the feeling that there might well be an easier solution than what you've learned so far to even the simplest problems, since there always have been during the span of the course.