Początkujący ocena i sprawdzenie kodu.

0

Cześć.
Uczę się od niedawana pythona i skończyłem rozdział na funkcjach. Chciałem się trochę sprawdzić i wymyśliłem sobie program, podzieliłem na moduły, a teraz staram się go napisać krok po kroku.
Pierwszy moduł zakłada utworzeni pustej listy, do której będą dodawane odcinki uciętego profila oraz ilość występowania tego odcinka. Czyli jak mamy 5 odcinków o długości 500 mm to powinno dodać do lisy [500, 500, 500, 500, 500]. Całość ma być zapętlona tak żeby dodać dowolną liczbę elementów do listy.

Napisałem kod i działa.
Proszę kogoś doświadczonego o ocenę i czy może jest jakaś inna opcja, która sprawi że kod będzie bardziej prosty(krótszy). Czy można to napisać lepiej ?

profile_dim = []

#Wpisanie długość odcinka oraz ile razy ma wystąpić na liście
active = True

while active:
	profile = []
	print('\nWpisanie "quit" spowoduje wyłączenie programu')
	lenght = input('Podaj długość uciętego profila: ')
	if lenght == 'quit':
		break
	else:
		lenght = int(lenght)


	multiply = int(input(f'Ile sztuk {lenght} wykonać?: '))
	if multiply == 'quit':
		break
	else:
		multiply = int(multiply)

	#Dodanie do listy oraz zwielokratniania elementów listy 
	profile.append(lenght)
	profile = profile*multiply
	print(profile)

	#Dodawanie elementów listy do głownej listy
	profile_dim.extend(profile)


	#Pytanie czy zakończyć dodawanie elementów do listy 

	ending = input('Czy zakończyć dodawanie elementó do listy ("tak"/"nie")')
	if ending == 'tak':
		active = False
	else:
		active = True

print(profile_dim)
1

Ten twój quit nie działa jak powinien, bo jak spróbujesz rzutować tekst nie będący liczbą na int, to wybuchnie wyjątkiem:

>>> int(input(f'Ile sztuk {lenght} wykonać?: '))
Ile sztuk 0 wykonać?: f
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'f'

Powinieneś rzutować raz i to w bloku try-catch by się bronić przed wyjątkami w razie gdyby użyszkodnik wprowadził niesprawdzone dane.

Po drugie, wrzuć wszystko do jakiejś funkcji, działa wtedy szybciej, poza tym znika chociażby problem stosowania zmiennych globalnych (antywzorzec).

Komentarze tłumaczące oczywistości w stylu

    #Dodawanie elementów listy do głownej listy
    profile_dim.extend(profile)

Nie są potrzebne. To wynika wprost z kodu. Komentarze służą do znaczenia rzeczy nieoczywistych i nie powinny być nadużywane. No ale do wyczucia dochodzi się z czasem.

Można by odpowiedzi przemielić dodatkowo lower() żeby zarówno wpisanie "Tak" jak i "tak" działało.

0

@Spearhead:
Co do tego quit mam świadomość, że jak ktoś wpisze coś innego poza liczbą albo quit to program się wywali. Googlowałem try-catch i z tego co widzę to jeszcze nie ten etap mojej nauki. Pewnie w między czasie dojdę do tego. Ale odnotuję to sobie i wrócę jeżeli nie spotkam się z tym później.
Zacznę od tej strony: 8.Errors and Exceptions.

Ten kod będzie upakowany w funkcji teraz tylko wkleiłem tak, żeby poddać do oceny jego działanie.

Z komentarzami przyznaję rację.

Zaraz wrzucę linijkę z lower().
Czyli pomijając problem z quit, za który wezmę się później całość może wyglądać tak po uwzględnieniu Twoich uwag?:
Teraz zauważyłem, że jak wywołuję funkcję to mogę podać jakiekolwiek argumenty bo nie mają one znaczenia dla działania funkcji.

def section_dec(lenght, multiply):
	'''Funkcja mająca na celu utworzenie listy z odcinkami pociętego profilu'''	
	#Wpisanie długość odcinka oraz ile razy ma wystąpić na liście
	profile_dim = []
	active = True

	while active:
		profile = []
		print('\nWpisanie "quit" spowoduje wyłączenie programu')
		lenght = input('Podaj długość uciętego profila: ')
		if lenght == 'quit':
			break
		else:
			lenght = int(lenght)


		multiply = int(input(f'Ile sztuk {lenght} wykonać?: '))
		if multiply == 'quit':
			break
		else:
			multiply = int(multiply)

		#Dodanie do listy oraz zwielokratniania elementów listy 
		profile.append(lenght)
		profile = profile*multiply
		print(profile)

		
		profile_dim.extend(profile)



		ending = input('Czy zakończyć dodawanie elementó do listy ("tak"/"nie")').lower()
		
		if ending == 'tak':
			active = False
		else:
			active = True

	return profile_dim

section = section_dec(0,0)
print(f'lista wszystkich przyciętych prfili: \n\t{section}')
1

Nie ma sensu aby funkcja section_dec przyjmowała argumenty, ponieważ i tak natychmiast je nadpisujesz wartościami wprowadzanymi przez użytkownika. Starczy

def section_dec():
    # ...

Wywołanie głównej funkcji zwykle dodatkowo obtacza się w if __name_ == '__main__', jakbyś kiedyś chciał importować coś z tego modułu

if __name__ == "__main__":
    section = section_dec()
    print(f'lista wszystkich przyciętych prfili: \n\t{section}')

Zmienna active jest w sumie zbędna. Zamiast tego możesz na końcu wychodzić tak samo jak wcześniej - breakiem lub returnem

while True:
    # ...
    ending = input('Czy zakończyć dodawanie elementó do listy ("tak"/"nie")').lower()
    if ending == 'tak':
        break

Komunikat w sumie też można by przeformułować bo można wpisać również cokolwiek innego i będzie miało taki sam efekt jak "nie".

Dla spójności komentarze też można by pisać po angielsku.

Czy zgodnie z deklinacją nie powinno być czasem Podaj długość uciętego profilu zamiast Podaj długość uciętego profila?

Brak wyjątków dalej razi, podstawy możesz już sobie przeczytać, potem dojdziesz do szczegółów.

Reszta wydaje się w porządku jak na tak prosty program.

0

@Spearhead:

Brak wyjątków dalej razi, podstawy możesz już sobie przeczytać, potem dojdziesz do szczegółów.>

A mógłbyś mi wstawić przykładowy kod ? Próbuję to ogarnąć ale albo coś mi nie wychodzi. Jeżeli podaję liczbę to zapętla się cały czas do jednej linii kodu abym podał długość uciętego profilu, albo wychodzi mi z programu.

while True:
		profile = []
		print('\nWpisanie "quit" spowoduje wyłączenie programu')
		try:
			lenght = int(input('Podaj długość uciętego profilu w [mm]: '))
			break
		except ValueError:
			print("Opps! To nie jest liczba. Spróbój jeszcze raz...") 
1

Najprościej będzie wstawić continue i zresetować całą iterację pętli. Alternatywnie musisz w obu przypadkach wczytywania danych zawrzeć je w dodatkowej, wewnętrznej pętli while, która będzie się kręcić, dopóki nie wyjdziesz lub podasz wartości, która ma sens, w rodzaju:

def section_dec():
    # ...
    while True:
        # ...
        while True:
            input_line = input('...')
            if input_line == 'quit':
                return
            try:
                length = int(input_line)
            except ValueError as e:
                continue
            break
        print(length)
        # ...

To obsługuje 3 przypadki

  • wpiszesz quit - wychodzi
  • wpiszesz liczbę - przechodzi dalej z nią
  • wpiszesz cokolwiek innego - pyta ponownie
0

Spójrz na wskazówki od Spearhead. Piszesz, że skończyłeś rozdział na funkcjach, a w Twoim kodzie nie ma ani jednej.

0

@Spearhead: bardzo Ci dziękuję za poświęcony czas :) z całą pewnością te kilka postów nieoczekiwanie zaowocowało nabyciem nowej wiedzy.
Dla zainteresowanych try - exception jest fajnie wytłumaczone pod tym linkiem link.

Co do samego programu wklejam wersję finalną, pozwoliłem sobie dodać komentarze do bloku try-excep z opisem co robi poszczególna linijka:

def section_dec():
	'''Funkcja mająca na celu utworzenie listy z odcinkami pociętego profilu'''	
	#Wpisanie długość odcinka oraz ile razy ma wystąpić na liście
	profile_dim = []

	while True:
		profile = []
		print('\nWpisanie "quit" spowoduje wyłączenie programu')

		while True:

			length =input('Podaj długość uciętego profilu w [mm]: ')
			if length == 'quit':
				return #Jeżeli jest quit zamyka funkcję section_dec() i wstawia wartość None
			try: 
				length = int(length) #Jeżeli zdaje test przechodzi do break i zamyka pętle. 
			except ValueError as e:
				print(f'Upss.. Podana wartość nie jest liczbą. Spróbuj jeszcze raz \n{e}')
				continue #Jeżeli jest błąd wyświetla komunikat i continue pomija pozostałą część kodu i rozpoczyna nową iterację wewnątrz pętli. 
			break
			
		while True:
			
			multiply = input(f'Ile sztuk {length} wykonać?: ')
			if multiply == 'quit':
				return
			try: 
				multiply = int(multiply)
			except ValueError as e:
				print(f'Upss.. Podana wartość nie jest liczbą. Spróbuj jeszcze raz \n{e}')
				continue
			break
		
		#Dodanie do listy oraz zwielokratniania elementów listy 
		profile.append(length)
		profile = profile*multiply
		print(profile)

			profile_dim.extend(profile)

		ending = input('Czy zakończyć dodawanie elementó do listy (wpisz "tak")').lower()
		
		if ending == 'tak':
			break
		
	return profile_dim

section = section_dec()
print(f'lista wszystkich przyciętych prfili: \n\t{section}')
0

Zauważ, że masz powtórzony fragment kodu, który możesz wynieść do osobnej funkcji:

        while True:

            length =input('Podaj długość uciętego profilu w [mm]: ')
            if length == 'quit':
                return #Jeżeli jest quit zamyka funkcję section_dec() i wstawia wartość None
            try: 
                length = int(length) #Jeżeli zdaje test przechodzi do break i zamyka pętle. 
            except ValueError as e:
                print(f'Upss.. Podana wartość nie jest liczbą. Spróbuj jeszcze raz \n{e}')
                continue #Jeżeli jest błąd wyświetla komunikat i continue pomija pozostałą część kodu i rozpoczyna nową iterację wewnątrz pętli. 
            break

        while True:

            multiply = input(f'Ile sztuk {length} wykonać?: ')
            if multiply == 'quit':
                return
            try: 
                multiply = int(multiply)
            except ValueError as e:
                print(f'Upss.. Podana wartość nie jest liczbą. Spróbuj jeszcze raz \n{e}')
                continue
            break

Deklarując:

def get_number(msg):
        while True:
            number =input(msg)
            if length == 'quit':
                return
            try: 
                number = int(length)
            except ValueError as e:
                print(f'Upss.. Podana wartość nie jest liczbą. Spróbuj jeszcze raz \n{e}')
                continue
            return number

Możesz jej użyć zamiast poprzednich 2 fragmentów:

length = get_number('Podaj długość uciętego profilu w [mm]: ')
multiply = get_number(f'Ile sztuk {length} wykonać?: ')

Dodatkowo jeżeli get_number zwróci None (po wpisaniu 'quit') powiniśmy wyjść z programu - a obecnie przechodzimy do kolejnych operacji. Np. jak wpiszę quit przy poberaniu length, to następnie będziemy mieli 'Ile sztuk None wykonać?:'.

Tutaj deklarujesz pustą listę:

profile = []

Następuje to zaraz po while True. Zauważ, że następnie robisz:

profile.append(length)
profile = profile*multiply

Możesz pominąć deklarację listy na początku i zrobić:

profile = [length] * multiply

Tutaj nie musisz używać zmiennej:

        ending = input('Czy zakończyć dodawanie elementó do listy (wpisz "tak")').lower()

        if ending == 'tak':
            break

vs

if input('Czy zakończyć dodawanie elementó do listy (wpisz "tak")').lower() == 'tak':
    break
0

I ogólna uwaga co do kodu. Wolę trzymać się tego by funkcja miała jedną odpowiedzialność. W tym przypadku section_dec powinna pobierać odcinki, do tego dodałbym funkcję pobierającą 1 odcinek:

def section_dec():
    '''Funkcja mająca na celu utworzenie listy z odcinkami pociętego profilu''' 
    #Wpisanie długość odcinka oraz ile razy ma wystąpić na liście
    profile_dim = []

    while True:
        profile_dim.append(get_section())
        if input('Czy zakończyć dodawanie elementó do listy (wpisz "tak")').lower() == 'tak':
            break
    return profile_dim

def get_section():
    length = get_number('Podaj długość uciętego profilu w [mm]: ')
    multiply = get_number(f'Ile sztuk {length} wykonać?: ')
    return [length] * multiply

Plus oczywiście obsługa 'quit'.

1 użytkowników online, w tym zalogowanych: 0, gości: 1