[Tutor] Question regarding lists and manipulating items in lists.

Steven D'Aprano steve at pearwood.info
Wed Jan 16 14:57:49 CET 2013


On 16/01/13 11:23, Scurvy Scott wrote:

> After playing with your example I keep being told that list has no
> attribute int_to_note. I know what the problem is, I just don't know
> how to fix it.

Oops, sorry about that, that is my fault. I did warn that my code was
untested!

If you know what the problem is, the solution should be obvious. Before
reading ahead, try explaining to yourself what you think the problem
actually is. If you do that, the answer should pop right out at you.

Still need a hint? Okay, try this:


"I need to convert the Fibonacci integers to musical notes, using the
notes.int_to_note function imported from mingus.core. But inside Steven's
make_notes function, he sets a local variable `notes = []`, which means
that inside the function I cannot access the global notes.int_to_note."

Or, a shorter version:

"I have notes.int_to_note, which I need, but accessing it is blocked by
the local variable notes which is a list."

So the obvious solution is...


...rename the local variable `notes` to something else.


def make_notes(num_notes):
     it = fib()
     music = []  # start with an empty list
     for i in range(num_notes):
         n = next(it) % 12  # get the next Fibonacci number, modulo 12
         music.append(notes.int_to_note(n))
     return music



Still untested.


> Also, I believe I've fixed my email so it will no longer be in HTML or
> anything fancy, just plain text.

Many thanks!

More comments below.


> So right now my code is:
>
> import mingus.core.notes as notes
>
> #fibonacci
> def fib():
>      a, b = 0, 1
>      while True:
>          yield b
> 	a, b = b, a+b

I have now tested that, and it works fine:

py> it = fib()
py> [next(it) for i in range(15)]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]


Some people prefer to start the Fibonacci sequence with 0. That's an
easy change to make: change the line "yield b" to "yield a". But
Wolfram Mathworld and Mathematica start the Fibonacci sequence with
1, 1, 2, ... rather than 0, 1, 1, ... so that's good enough for me.

http://mathworld.wolfram.com/FibonacciNumber.html



> def make_notes(num_notes):
> 	it = fib()
> 	notes = []
> 	for i in range(num_notes):
> 		n = next(it) % 12
> 		notes.append(notes.int_to_note(n))
> 	return notes
>
> Which is pretty different from what my original code was.


Maybe so, but I'm teaching you a practice that will see you in good stead
whenever you program: each function should do *one* thing.

Think of programming as creating tools. You wouldn't try to create a single
tool for cutting wood, driving screws into it, and painting it. Instead we
have three tools: saw, screwdriver, paint brush. It's *much* easier to make
three separate tools than a single tool that tries to do all three jobs.

Likewise for your program. It is better to write separate functions to:

* create the Fibonacci numbers;

* turn them into musical notes;


than to do both jobs in one function. Now in *this* case, the labour saved
is relatively small. But it is a good habit to get into, and when you get
to large, complex programs it becomes essential.



>  The
> generator function doesn't actually do anything when called, it just
> tells me it's a generator function and where it's located.

If you look at how my code uses the generator function, you will see the
correct way to use it. Here's another example:


py> it = fib()
py> n = next(it)
py> while n < 100:
...     print n
...     n = next(it)
...
1
1
2
3
5
8
13
21
34
55
89




-- 
Steven


More information about the Tutor mailing list