Efficient way of code reuse for finding the largest prime factor I was doing timing with variations of function largest_prime_factor. I was able to write a better one largest_prime_factor2. There were some repetitions in the new function so I wrote another function largest_prime_factor3. 

I thought the 3rd one has to be faster than the 2nd because I broke it up into more functions but it wasn't faster but slower. 


I wanted to know whether my method of code reuse is good or not? 
Is there a better way of reusing code in Python? 
Did I miss something due to which the new function became slower?


My functions alongwith the testing() function used to test all three.

def largest_prime_factor(num):
    '''returns the largest prime factor of a number'''
    ans = 0
    if num % 2 == 0:
        ans = 2
        num /= 2
        while num % 2 == 0:
            num /= 2

    i = 3
    while i &lt;= num:
        if num % i == 0:
            ans = i
            num /= i
            while num % i == 0:
                num /= i

        i += 2

    return ans

def largest_prime_factor2(num):
    '''returns the largest prime factor of a number'''    
    ans = 0
    if num % 2:
        pass
    else:
        ans = 2
        while True:
            num //= 2
            if num % 2:
                break

    i = 3
    while i &lt;= num:
        if num % i:
            pass
        else:
            ans = i
            while True:
                num //= i
                if num % i:
                    break

        i += 2

    return ans

def largest_prime_factor3(num):
    '''returns the largest prime factor of a number'''
    def check(j):
        nonlocal ans
        nonlocal num
        if num % j:
            return
        ans = j
        while True:
            num //= j
            if num % j:
                return
    ans = 0
    check(2)
    i = 3
    while i &lt;= num:
        check(i)
        i += 2

    return ans

def testing():
    from timeit import Timer
    import random

    def tests(f, times):
        def test1(f):
            f(random.randint(1, 1000))
        def test2(f):
            f(random.randint(100000, 1000000))

        print(f.__name__)
        print(Timer(lambda: test1(f)).timeit(number = times))
        print(Timer(lambda: test2(f)).timeit(number = times//10))
        print()


    tests(largest_prime_factor, 10000)
    tests(largest_prime_factor2, 10000)
    tests(largest_prime_factor3, 10000)

if __name__ == "__main__":
    testing()


The timing results that I found:


largest_prime_factor
0.338549207387318
16.599112750324068

largest_prime_factor2
0.21575289594063918
12.086949738861868

largest_prime_factor3
0.36032199674939847
18.893444539398857



This format of results is produced by the testing function. See that for details.
Usually, splitting your code into different smaller functions is a good idea as it makes things easier to read, to reuse and to test.

However, this comes at a (cheap) price as far as performances are concerned because functions calls are not for free (nor are function definitions). 

Now, for additional advices, whenever you want to compare performances of functions, it might also be a good idea to return what they compare. It's not good having a fast function if it doesn't return the right thing. By using assert, you could ensure you get notified quickly whenever something goes wrong.

This being said, I'd like to run and comment your code but I don't have a python3 handy and it seems that it is the version you are using so I'll try to do this later :-)