Project Euler problem #112
Code structure

The most common and widely accepted structure found in Python scripts from a high-level point of view looks something like:

# imports
import
...

# functions and classes, aka "library code"
class Foo:
    ...

def bar(batz):
    ...

if __name__ == "__main__":
   # part that is supposed to be run as script
   ...



Your code on the other hand does not follow this structure since there is some script code at the top (start = time.time()), then come your functions, followed by another block of script code. I highly recommend to follow that structure.

Further reading: Explanation of if __name__ == "__main__": from the official Python documentation.

The code itself

bouncy

The most striking aspect of bouncy from a stylistic point is the capital N as parameter name that goes against the official Style Guide for Python Code (often just called PEP8). Usually parameter and variable names are written in snake_case, e.g. small letters, possibly separated by underscores. 

With that said, let's look at the actual algorithm: 


number = list(str(N))
n1 = list(str(N))
n2 = list(str(N))



Lots of repeated code here. An easy way out would be to do the conversion once, and copy the results afterwards. This can be done using slicing like n1 = number[:], the list constructor n1 = list(number) or the copy module. Also, sorted would create a copy indirectly, so no need to do this manually (see the next point).

The next thing you do in your code is sorting those lists. Once ascending, then descending. Since the second one should by definition be the mirror of the previous one, you can use slicing again to avoid that second sort.

sorted_number = sorted(number)  # &lt;- also does a copy


Oh, and did you know that sorted does work on strings as well and simply returns a new list? (sorted_number = sorted(N))

You could also use the result of the condition directly as return value of your function.

With some other minor changes you might end up with something like

def is_bouncy(number):
    '''Function determines whether arbitrary number N is a bouncy number.'''
    digits = list(str(number))
    sorted_digits = sorted(digits)
    return digits != sorted_digits and digits != sorted_digits[::-1]


find

find is almost as straightforward as it gets. I would advise to change the variable name bou to bouncy or n_bouncy now that the checking function is called is_bouncy. IMHO current would also likely be a better name for start. Also find_bouncy_boundary, maybe even with an optional "expected bounciness percentage" might be worth a thought.

From an optimization point of view, you could also start from 1000 if you're only looking for that 99%, since the task description tells you that there are exactly 525 bouncy numbers below 1000 ;-) But there is likely not much to gain from that. 

The rest

Now all there is left to do is to take the spread out script code, wrap it up in if __name__ == "__main__":, and collect it at the bottom of the script:

if __name__ == "__main__":
    start = time.time()
    print(find())
    print(time.time() - start)


If the script part becomes more complex, this part is often put into a separate main() method.