Python-The Collatz Sequence
po pierwsze, zwróć uwagę, jak powielasz obliczenia:
print(num//2)num = num //2
może to nie powodować problemów z tym konkretnym kodem, ale nie jest to dobra praktyka. Wykonujesz dwa razy więcej pracy, niż potrzebujesz, co może powodować problemy z wydajnością, gdy zaczniesz pisać bardziej skomplikowany kod. Wykonaj obliczenia raz i zapisz wynik. W tym przypadku wystarczy odwrócić te linie i użyć num
:
num = num // 2print(num)
upewnij się również, że masz odpowiednie odstępy wokół operatorów i bądź spójny.
Twoje if
i elif
przypadki są wyłączne od siebie, a twoja else
nigdy nie powinna się zdarzyć. Jeśli pierwszy warunek jest prawdziwy, to drugi musi być fałszywy i odwrotnie. Drugi czek nie jest potrzebny. Po przepisaniu zobaczysz, że drukowanie w każdym przypadku nie jest konieczne. Możesz wydrukować po:
while num > 1: if num % 2 == 0: num = num // 2 else: num = 3 * num + 1 print(num)
ponieważ po prostu przywracasz num
jedną z dwóch opcji opartych na warunku, wyrażenie warunkowe może być również użyte tutaj czysto:
while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) print(num)
szelki nie są konieczne, ale myślę, że są tu przydatne ze względu na liczbę zaangażowanych operatorów.
Drukowanie liczb nie jest tutaj idealne. W większości kodów musisz być w stanie korzystać z danych, które generujesz. Jeśli chcesz przeanalizować wytworzoną sekwencję, musisz zrobić coś przechwycić stdout, co jest drogie i zbyt skomplikowane. Uczyń z niej funkcję, która gromadzi i zwraca listę. W poniższych przykładach dodałem również kilka wskazówek typu, aby wyjaśnić, jaki jest typ danych:
from typing import Listdef collatz(starting_num: int) -> List: nums = num = starting_num while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) nums.append(num) return nums
lub, znacznie czystszym podejściem jest zrobienie z niego generatora, który daje liczby:
# Calling this function returns a generator that produces ints# Ignore the two Nones, as they aren't needed for this kind of generatordef collatz_gen(starting_num: int) -> Generator: yield starting_num num = starting_num while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) yield num>>> list(collatz_gen(5))
jest kilka istotnych rzeczy o getNum
:
Python używa “snake_case”, a nie”camelCase”.
Twoje użycie global num
tutaj jest niepotrzebne i mylące. Podobnie jak poprzednio, jawnie return
wszelkie dane, które funkcja generuje:
def get_num() -> int: raw_num = input("> ") try: return int(raw_num) except ValueError: print('Please enter a number') return get_num()
zauważ, że zamiast przypisywać globalny num
, po prostu zwracamy ten numer. Rozłożyłem trochę rzeczy i użyłem bardziej odpowiednich nazw. Koncepcyjnie powiedziałbym, że num = input("> ")
się myli. W momencie uruchomienia num
nie zawiera liczby (zawiera łańcuch znaków).
to nie jest dobre użycie rekurencji. Prawdopodobnie nie spowoduje to żadnych problemów, ale jeśli twój użytkownik jest naprawdę głupi i wprowadza błędne dane ~1000 razy, twój program ulegnie awarii. Wystarczy użyć pętli:
def get_num() -> int: while True: raw_num = input("> ") try: return int(raw_num) except ValueError: print('Please enter a number')
w językach takich jak Python, bądź ostrożny używając rekurencji w przypadkach, gdy nie masz gwarancji, ile razy funkcja będzie rekurencyjna.
też pewnie nazwałbym to coś bliżej ask_for_num
. “get” nie wyjaśnia, skąd pochodzą dane.
wzięte w całości, skończysz z:
from typing import Generatordef collatz_gen(starting_num: int) -> Generator: yield starting_num num = starting_num while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) yield numdef ask_for_num() -> int: while True: raw_num = input("> ") try: return int(raw_num) except ValueError: print('Please enter a number')
które można wykorzystać jak:
num = ask_for_num()for n in collatz_gen(num): print(n)