Jak bardzo Pythonowy jest mój kod

Jak bardzo Pythonowy jest mój kod
0

Proszę o ocenę mego kodu, wcześniej kodziłem trochę w C++:

Kopiuj
import random
import getpass

rock = "rock"
paper = "paper"
scissors = "scissors"

single_player = "single player"
multiplayer = "multiplayer"

synonyms = {"rock": rock,
            "paper": paper,
            "scissors": scissors,
            "stone": rock,
            "vellum": paper,
            "shears": scissors,
            "kamien": rock,
            "papier": paper,
            "nozyce": scissors,
            "r": rock,
            "p": paper,
            "s": scissors
            }

modes = {"single": single_player,
         "multi": multiplayer,
         "singleplayer": single_player,
         "multiplayer": multiplayer,
         "single player": single_player,
         "s": single_player,
         "m": multiplayer
         }


chosen_single_player = "You Chosen The Game With a Computer" 

chosen_multi_player = "You Chosen The Game With An Another Player"


game_is_draw = "Game is a Draw"

playerA_wins = "Player A Wins"

playerB_wins = "Player B Wins"


transitions = {(null, null): both_players_must_choose,
               (null, rock): playerA_must_choose,
               (null, paper): playerA_must_choose,
               (null, scissors): playerA_must_choose,
               (rock, null): playerB_must_choose,
               (rock, rock): game_is_draw,
               (rock, paper): playerB_wins,
               (rock, scissors): playerA_wins,
               (paper, null): playerB_must_choose,
               (paper, rock): playerA_wins,
               (paper, paper): game_is_draw,
               (paper, scissors): playerB_wins,
               (scissors, null): playerB_must_choose,
               (scissors, rock): playerB_wins,
               (scissors, paper): playerA_wins,
               (scissors, scissors): game_is_draw
               }
               

playerA_choice = ' '
playerB_choice = ' '
mode_choice = ' '

# Main 
print("You are playing Rock Paper Scisscors")
print("Choose a mode: single player or mutliplayer?" )
while mode_choice not in modes:
    mode_choice = input("Enter The Game Mode: ")

if modes[mode_choice] == single_player:
    while playerA_choice not in synonyms:
        playerA_choice = input("Enter Your Choice: ")
            
    playerB_choice = random.choice(list(synonyms.keys()))
    #print(playerB_choice)

    print(transitions[synonyms[playerA_choice], synonyms[playerB_choice]])

elif modes[mode_choice] == multiplayer:
    while playerA_choice not in synonyms:
        playerA_choice = getpass.getpass("Player A: Enter Your Choice: ")

    while playerB_choice not in synonyms: 
        playerB_choice = getpass.getpass("Player B: Enter Your Choice: ")
   
    print("The Player A Choose '{}' And The Player B Choose '{}'".format(playerA_choice, playerB_choice)) 
    print(transitions[synonyms[playerA_choice], synonyms[playerB_choice]])
LukeJL
"playerA_must_choose" --- gdzie deklarujesz te zmienne? Odpala ci się ten kod i nie rzuca błędem?
Maciej Cąderek
Maciej Cąderek
Przecie to nie działa...
FU
przyłączam się do przedmówcy - brakuje wielu zmiennych więc nie można tego uruchomić
JS
fakt, przepraszam bardzo. Po prostu przed wrzuceniem tego na forum usunąłem parę opcji (czyt. koncept początkowy zakładał, że można niczego nie wpisać) i nie sprawdziłem tego. Musiałem założyć konto aby tutaj odpowiedzieć. Wystarczy usunąc te zmienne w transitions
Maciej Cąderek
Maciej Cąderek
@jaSwiezak to popraw
0

"playerA_must_choose" --- gdzie deklarujesz te zmienne? Odpala ci się ten kod i nie rzuca błędem?

Pozostałość po starym koncepcie. Ta opcja nie występuje, nie ma szans jej wywołać.

FU
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 3 lata
  • Postów:34
0

Pomijając fakt, że się nie uruchamia bo brak wielu zmiennych:

Z pythonowych rzeczy to bym nazwał dużymi literami stałe,
czyli elementy, którym nie jest zmieniana wartość
np.

Kopiuj
ROCK = "rock"
PAPER = "paper"
SCISSORS = "scissors"

Z rzeczy już niepythonowych to zamiast wartości tekstowych
przypisał bym im wartości liczbowe - i tak ich nie wypisujesz
a liczby szybciej komputerowi porównać
choć przy tak małej grze to nie ma takiego znaczenia

Kopiuj
ROCK = 1
PAPER = 2
SCISSORS = 3

Przy wyborze trybu gry i symbolu wolałbym jednak wybierać cyfrę 1, 2 lub pojedynczyą literę
niż pisać całe słowo więc taka możliwość wydaje mi się zbyteczna.

Spine
  • Rejestracja:około 22 lata
  • Ostatnio:2 minuty
  • Postów:6656
0

Może pisz bardziej obiektowo niż strukturalnie?


🕹️⌨️🖥️🖱️🎮
MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:2 minuty
1

nie widzę ani jednego słowa kluczowego def co dla mnie jest oznaką, że jest bardzo źle (jak używałeś C++ to też musiało być jeszcze bardziej nieczytelnie).


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 2x, ostatnio: MarekR22
Wizzie
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 7 lat
6

Wyobraź sobie, że ktoś chciałby użyć np. jakiejś stałej z twojego kodu. Importuje sobie więc: from nazwa_modulu import transitions. Chyba ostatnie, czego w tym momencie się spodziewa, to wyświetlenie dwóch tekstów w konsoli i czekanie na input użytkownika, a tak niestety się dzieje po zaimportowaniu twojego modułu. Żeby się przed tym uchronić otaczamy wykonywalny kod w takiego ifa:

Kopiuj
if __name__ == '__main__':
    pass  # wykonywalny kod tutaj

Generalnie robimy tak zawsze, gdy wiemy, że kod może być odpalany bezpośrednio, a nie tylko importowany. Więcej o tym tutaj.

Jak najbardziej zgadzam się z @MarekR22, musisz wydzielić z tego czytelne funkcje. Linijek będzie więcej, ale wracając do tego po kilku miesiącach skumasz znacznie szybciej o co chodzi. Może to nie jest widoczne przy dosyć prostym kodzie, ale kilkanaście linijek więcej i nie wiedziałbyś co się tu dzieje. Staraj się, żeby funkcje miały maksymalnie jeden stopień zagłębienia i były krótkie, a nazwy sensowne. Wtedy taki kod się czyta jak książkę ;)

Natomiast nie zgadzam się ze @Spine, nie widzę tutaj potrzeby wsadzania żadnych klas. Python to nie Java i nie chodzi o to, że nie piszę się w nim obiektowo, tylko, że nie zawsze konieczne jest opakowywanie wszystkiego w to słowo kluczowe, a kod nadal może zostać "obiektowy". W Pythonie moduły są obiektami, więc przestrzeń nazw mamy. Dalej - jako, że instancja gry byłaby i tak singletonem, to na jedno wychodzi, dodalibyśmy po prostu kolejny niepotrzebny poziom pseudo-abstrakcji. W Pythonie nie ma nacisku na enkapsulację, dodanie klasy nic w tym nie zmienia. Wniosek: jest okej. Inna rzecz przy bardziej rozbudowanej grze, gdzie takich obiektów byłoby znacznie więcej, ale nawet wtedy stawiałbym głównie na takie rzeczy jak namedtuple czy słowniki, gdzie tylko się da.

edytowany 1x, ostatnio: Wizzie
LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:minuta
  • Postów:8420
1

Powtarzająca się logika. Najpierw masz tutaj coś takiego:

Kopiuj
 while playerA_choice not in synonyms:
        playerA_choice = getpass.getpass("Player A: Enter Your Choice: ")

a potem prawie to samo, tylko dla gracza B:

Kopiuj
    while playerB_choice not in synonyms: 
        playerB_choice = getpass.getpass("Player B: Enter Your Choice: ")

To przeciez można włożyć funkcję (czyli zgadza się to, o czym @MarekR22 mówił, że nie ma żadnej funkcji zdefiniowanej) nazwać np. get_player_choice i wywoływać tak:

Kopiuj


get_player_choice(playerB)

nie prościej?

Poza tym... po co playerA, playerB? To nie jest skalowalne, bo 3 gracz już nie dojdzie. Lepiej już zrobić listę graczy, np.

Kopiuj
[
{'name': 'Marcin', 'last_choice': None},
{'name': 'Genowefa', 'last_choice': None},
]

(używam literału obiektu dla prostoty, chociaż zapewne taką listę będziesz tworzył inaczej, bardziej dynamicznie, wczytując najpierw od usera liczbę graczy i ich imiona)

Dalej mamy niepotrzebne w tym przypadku rozróżnienie na singleplayer i multiplayer. Są gry, gdzie rozgrywka na jedną osobę i drugą jest zupełnie inna, i takie rozróżnienie miałoby sens. Ale tutaj rozgrywka jest dokładnie taka sama. Ludzie po kolei dokonują wyborów i potem nastąpi przeliczenie punktów.

Więc to zrobiłeś:

Kopiuj
if modes[mode_choice] == single_player:
....
elif modes[mode_choice] == multiplayer:

Jest słabe. Z powodu nieumiejętności wydzielenia abstrakcji poszedłeś na łatwiznę i zrobiłeś kopiuj-wklej.

A przecież zobacz. Czym się różni tryb single i multiplayer?
Tylko tym:

Kopiuj
 playerB_choice = random.choice(list(synonyms.keys())

A wystarczy, żebyś w danych gracza dodał flagę czy dany gracz jest człowiekiem czy komputerem:

Kopiuj
[
{'name': 'Marcin', 'last_choice': None, 'is_human': True }
{'name': 'Genowefa', 'last_choice': None, 'is_human': False},
]

a potem sprawdzać coś w rodzaju tego:

Kopiuj
if player['is_human']:
    player['choice'] = get_player_choice(player)
else: 
    player['choice'] = random.choice(list(synonyms.keys())

Podsumując - twój kod jest bardzo imperatywny, brak większych abstrakcji, dużo powtórzeń tych samych idiomów etc.
Bardziej jakbyś w assemblerze pisał, niż w pythonie... ;)

Tym niemniej wydaje mi się, że pytanie jest źle zadane. Nie jest kwestia tego, czy kod jest pythonowy czy nie, tylko raczej czy umiesz dostrzec i zaimplementować odpowiednie abstrakcje. Ale to można ćwiczyć. Tylko trzeba zwracać uwagę na

  • elastyczność programu (twój program nie jest elastyczny, bo 3 gracz nie dojdzie)

  • prostotę kodu (twój program nie jest prosty, bo powtarzasz to samo dla trybu single i multi, zamiast mieć w jednym miejscu tę logikę)

  • czytelność (twój kod przez to, że nie ma żadnych abstrakcji tylko ciurkiem wszystko leci zbyt czytelny nie jest).

  • strukturę danych / model (Tutaj o ile częściowo o tym myślałeś (transitions) to np. o tym, żeby wsadzić dane gracza w jakiś słownik, obiekt czy jakąkolwiek inną strukturę danych (ew. nadać mu ID i rozpoznawac go po identyfikatorze, tak jak jest to w bazach danych), już kompletnie nie pomyślałeś tylko piszesz zmienne luzem playerA_choice, playerB_wins etc. Czyli koncepcja Gracz w ogóle nie istnieje w twoim programie. Robisz grę bez graczy, jedynie z "wyborami graczy" czy z "wygranymi graczy".)

Oczywiście z abstrakcjami też można przesadzić. Jakiś programista Javy do tego co robisz pewnie porobiłby 15 różnych klas, implementując 30 różnych interfejsów i 10 różnych wzorców projektowych - co byłoby mocno przekombinowane ;)


edytowany 6x, ostatnio: LukeJL
Wizzie
twój kod jest bardzo imperatywny no to akurat nic złego, chyba szukałeś innego słowa :D
LukeJL
Kluczem jest słowo "bardzo" ;) Ale w sumie faktycznie to o co mi chodzi można wyrazić raczej zdaniem, że cała logika jest wpisana na sztywno i że co prawda są pewne abstrakcje (tabela tranzycji), to jednak poza tym kod gry nie daje się w żaden sposób sparametryzować (np. nie da się dodać 3 gracza, bo fakt, że graczy jest tylko 2 jest wpisany na sztywno w logikę gry).
LukeJL
btw. ta tabela tranzycji, która tam wisi też dobra nie jest, bo też ma wpisane na sztywno liczbę graczy. Ale autor tematu i ta napisał, że to "Pozostałość po starym koncepcie. " więc zapewne w jego przypadku i implementacji to nie wyszło, mimo że taka tabela tranzycji gdzie indziej mogłaby być dobra...
LukeJL
(chociaz w sumie... jakby przelecieć przez każdą parę graczy, to nawet by można było ją zastosować).
pyholic
  • Rejestracja:ponad 9 lat
  • Ostatnio:około 9 lat
  • Lokalizacja:Kraków
  • Postów:14
0

Powołując się na python zen:

Simple is better than complex

Myślę, że tutaj trafiono w samo sedno. Kod jest nadal prosty i zrozumiały. Co prawda można sugerować Ci sztuczki z pythona bądź podział na funkcje, klasy czy też inne praktyki (testy, wzorce), ale przy tak prostych zadaniach to nie jest konieczne. W każdym razie jeśli na tym etapie zaczniesz przejmować się samą formą niż treścią to w niedługim czasie zobaczymy tutaj Twoje metaprogramowanie :-)

edytowany 1x, ostatnio: pyholic
Wizzie
nie uważasz, że czytelny kod jest prostszy od nieczytelnego? ;)
pyholic
Odpowiedź zawierasz w pytaniu. Ja natomiast chciałem podkreślić, że kod prosty również może być czytelny.
JS
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 9 lat
  • Postów:3
0

Hej, dzięki za liczne odpowiedzi ;) Można na was liczyć. Spróbuje się odnieść do niektórych zarzutów, zaprezentuję nowy kod i przedstawię listę pytań.
@Wizzie: przyznam, że pierwszego i ostatniego akapitu twego postu po prostu nie zrozumiałem. Ale też nie poświecałem zbytnio czasu na to. Po prostu nie miałem kiedy. Ale dzięki, szczególnie za to o zasadności stosowania funkcji

@LukeJL: bardzo fajnie i zwięźle wypunktowałeś co jest źle. Dzięki.

Wrzucam nowy kod. Troszkę go rozbudowałem o dodatkowe funkcje (dodawanie graczy, zarządzanie dodanymi już graczmi, generowanie imion graczy według potrzeby, kamień, papier, nożyce, jaszczurka i Spock :), rundy).

Kopiuj
import random
import time
import getpass

players_list = []

def generate_player_name():
    names = ['Plaska Dziewica', 'Zbutwialy Piernik', 'Mistrz Wegorza', 'Zjadacz Sedesow',
             'Stanikowy Deszcz', 'Smetny Pierd', 'Sprzedam Seata', 'Zimna Warka',
             'Jacek Maly Wacek', 'Waleczny Mlot', 'Szalony Ziemniak', 'Sheldon'
             'Waz Rzeczny', 'Tururu Tururu', 'Jest Niebezpieczny' ]
    
    decision = ' '
    possible_decision = ('Y', 'N')
    while decision not in possible_decision:
        player_name = random.choice(names)
        decision = input('>> Do The Name ' + player_name + " Is OK With You? If Not I Will Draw Again [Y/N] ").upper()

        if(decision == 'Y'):
            print('>> Great then!', player_name)
            return player_name
        elif decision == 'N':
            decision = ' '


def create_player(decision, possible_decisions):
    flag = ' '
    possible_flags = {'C': 'is_computer', 'H': 'is_human'}
    while(flag not in possible_flags):
        flag = input('>> Will The Player Be Controlled By [H]uman or [C]omputer? ').upper()

    if(decision == 'M'):
        player_name = input('>> Type The Name:')  
    elif(decision == 'A'):
        player_name = generate_player_name()

    players_list.append( {'player_name': player_name,
                         'player_flag': possible_flags[flag],
                         'player_decision': None,
                         'player_points': 0}
                        )


def add_player():
    list_status = len(players_list)
    decision = ' '

    while decision != 'B':
        decision = input(">> Do You Want To Create New Player [M]anualy Or Should I Do It [A]utomaticly (I'll Generate The Name)?\n   [B]ack To Main Menu ").upper()

        possible_decisions = ['A', 'M']
        if(decision in possible_decisions):
            create_player(decision, possible_decisions)

            decision = ' '
            possible_decisions = ['Y', 'N']
            while decision not in possible_decisions:
                decision = input('>> You Just Added The Player! Do You Want To Add Another One? [Y/N] ' ).upper()

                if(decision == 'N'):
                    decision = 'B'
                    break

        if(decision == 'B'):
            print('>> You Just Added:',  len(players_list) - list_status, 'Players')


def play():
    print(">> We Will Play In That Order:", end = ': ')
    for player in players_list:
        print(player['player_name'], end = ', ')
    print() # newline

    number = 99
    while not number <= 5 or number <= 0:
        number = int(input('>> Before You Start Type How Many Rounds Do You Want To Play?\n   The Maximum Number Of Rounds Is Five '))

        if number > 5:
            print('As I Said You Cannot Play More Rounds Than Five')
        elif number == 0:
            print('In This Case I Predict The Score. NOBODY WON AND NOBODY LOST')
        elif number < 0:
            print("I Won't Comment On That. Just Type Once Again")

        for rounds in range(0, number):
            print('\n>> Round', rounds + 1)
            make_choice()
            give_points()

    decide_winner()
    clean_points()


def make_choice():
    options = {1: 'rock', 2: 'paper', 3: 'scissors', 4: 'lizard', 5: 'Spock'}

    for player in players_list:
        if(player['player_flag'] == 'is_computer'):
            print('>> It Is {player_name} Turn! The Player Is Controled By The Computer'.format(player_name = player['player_name']))
            for i in range(1, 4):
                print('>> {i}... '.format(i = i))
                time.sleep(1)

            player_decision = random.randint(1, 5)

        elif(player['player_flag'] == 'is_human'):
            player_decision = 2
            while player_decision < 1 and player_decision > 5: 
                player_decision = int(getpass.getpass(">> It Is {player_name} Turn! The possible choices:\n   1: 'rock', 2: 'paper', 3: 'scissors', 4: 'lizard', 5: 'Spock' ".format(player_name = player['player_name'])))
        
        print('>> {player_name} Made a Choice!\n'.format(player_name = player['player_name']));    
        player['player_decision'] = options[player_decision]


def give_points():
    results = {('rock', 'rock'): 'game_is_draw',
               ('rock', 'paper'): 'playerB_wins',
               ('rock', 'scissors'): 'playerA_wins',
               ('rock', 'lizard'): 'playerA_wins',
               ('rock', 'Spock'): 'playerB_wins',
               ('paper', 'rock'): 'playerA_wins',
               ('paper', 'paper'): 'game_is_draw',
               ('paper', 'scissors'): 'playerB_wins',
               ('paper', 'lizard'): 'playerB_wins',
               ('paper', 'Spock'): 'playerA_wins',
               ('scissors', 'rock'): 'playerB_wins',
               ('scissors', 'paper'): 'playerA_wins',
               ('scissors', 'scissors'): 'game_is_draw',
               ('scissors', 'lizard'): 'playerA_wins',     
               ('scissors', 'Spock'): 'playerB_wins',
               ('lizard', 'rock'): 'playerB_wins',
               ('lizard', 'paper'): 'playerA_wins',
               ('lizard', 'scissors'): 'playerB_wins',
               ('lizard', 'lizard'): 'game_is_draw',
               ('lizard', 'Spock'): 'playerA_wins',
               ('Spock', 'rock'): 'playerA_wins',
               ('Spock', 'paper'): 'playerB_wins',
               ('Spock', 'scissors'): 'playerA_wins',
               ('Spock', 'lizard'): 'playerB_wins',
               ('Spock', 'Spock'): 'game_is_draw'
              }

    print('Results:')
    i = 1
    for playerA in players_list:
        for playerB in players_list[i:]:
            result = results[playerA['player_decision'], playerB['player_decision']]

            if result == 'game_is_draw':
                playerA['player_points'] += 0.5
                playerB['player_points'] += 0.5
                print('  - Players {playerA_name} And {playerB_name} Has Drawn. Each Of Them Got 0.5 Point'
                      .format(playerA_name = playerA['player_name'], playerB_name = playerB['player_name']))

            elif result == 'playerA_wins':
                playerA['player_points'] += 1
                print('  - Player {playerA_name} Won With {playerB_name}. Players {playerA_name} Got 1 Point'
                      .format(playerA_name = playerA['player_name'], playerB_name = playerB['player_name']))

            elif result == 'playerB_wins':
                playerB['player_points'] += 1
                print('  - Player {playerB_name} Won With {playerA_name}. Players {playerB_name} Got 1 Point'
                      .format(playerA_name = playerA['player_name'], playerB_name = playerB['player_name']))

        i += 1


def decide_winner():
    sorted_list = sorted(players_list, key=lambda k: k['player_points'], reverse=True)

    i = 0
    while sorted_list[i]['player_points'] == sorted_list[i + 1]['player_points']:
        i += 1

    print('\n>> The Winner Is...', end = ' ')
    time.sleep(2)
    if i == 0:
        print(sorted_list[0]['player_name'].upper(), '!!!')
    elif i > 0:
        print('There Is a Draw Between ', end = '')
        for j in range (0, i + 1):
            print(sorted_list[j]['player_name'], end = ', ')

        print() #newline

    print('>> Congratulations! You Have Got', sorted_list[0]['player_points'], 'Points')

    print('>> Results:')
    for player in sorted_list:
        print('  ', player['player_name'], player['player_points'])

    print() #newline


def managment_players():
    print('>> The List Of Players: ')
    for player in players_list:
        print('   - {player_name} is controled by {player_flag}'. format(player_name = player['player_name'], player_flag = player['player_flag'][3:]))
    
    possible_decision = ('D', 'B')
    decision = ' '
    while decision not in possible_decision:
        decision = input('>> Do You Want To [D]elete a Player? [B]ack To Main Menu ').upper()

        if decision == 'D':
            number = 99
            while not number < len(players_list) + 1:
                number = int(input(">> What Player Do You Want To Delete? Give Me a Number "))

                if number > len(players_list) + 1:
                    print('>> The Player With {number} Number Does Not Exist'.format(number = number)) 

                else:
                    possible_decision = ('Y', 'N')
                    while decision not in possible_decision:
                        decision = input('>> Are You Sure You Want To Delete {player_name} Player? [Y/N] '.format(player_name = players_list[number - 1]['player_name'])).upper()

                        if decision == 'Y':
                            del players_list[number - 1]
                            print('>> You Just Removed The Player!')
                            break
                    
                    possible_decision = ('D', 'B')
                            

def clean_points():
    for player in players_list:
        player['player_points'] = 0
         
    sorted_list = []                       


''' for tests
players_list.append( {'player_name': 'Marek',
                        'player_flag': 'is_human',
                        'player_decision': None,
                        'player_points': 0}
                    )

players_list.append( {'player_name': 'Karolinka',
                        'player_flag': 'is_computer',
                        'player_decision': None,
                        'player_points': 0}
                    )

players_list.append( {'player_name': 'Sraromir',
                        'player_flag': 'is_computer',
                        'player_decision': None,
                        'player_points': 0}
                    )

players_list.append( {'player_name': 'Smutna Julka',
                        'player_flag': 'is_computer',
                        'player_decision': None,
                        'player_points': 0}
                    )
'''

print(">> Welcome To Rock-Paper-Scissors-Lizard-Spock Game. All Rights Reserved. Enjoy! ")
decision = input('>> Before You [P]lay, Remeber To [A]dd Players. You Can [M]anage The List Of Participants At Any Time.\n   When You Get Tired Of The Game, Just [E]xit ').upper()

while(decision != 'E'):
    if(decision == 'E'):
       print('>> Have a Nice Day! ')

    elif(decision == 'P'):
        if not players_list:
            print('>> At First You Need To Add Players. Do It And I Will Let You Play')
        else:
            play()

    elif(decision == 'A'):
        add_player()

    elif(decision == 'M'):
       if not players_list:
            print(">> You Moron! You Didn't Add Any Players Yet!")
       else:
            managment_players()

    decision = input('>> So What Do You Want To Do Now? [P]lay, [A]dd a New Player, [M]anage Already Added Players, Or Just [E]xit? ').upper()

A teraz pytania ode mnie dla was:

  1. Jak powinien wyglądać główny blok kodu? Jaka jest konwencja? Czy powinienem go zamknąć w main() i po prostu go wywołać czy tak jak zrobiłem też jess OK?
  2. Jak wygląda dobrze napisany odpowiednik Switch: case w pythonie za pomocą if'ów?
  3. Czy jest jakiś lepszy sposób na wymuszeniu na użytkowniku odpowiedniego znaku przy wybiorze niż zastosowane przeze mnie:
Kopiuj
possible_decision = ['option1', 'option2']
decision = ' '
while decision not in possible_decision:
       decision = input()
  1. Jak brzmią dobrze nazwane funkcje? :)
  2. Czy nie robię bardzo źle że używam zmiennej globalnej (players_list = [])?
  3. Co dostrzegacie gdzieś powtarzającą się logikę o której wspomniał @LukeJL?
edytowany 2x, ostatnio: jaSwiezak
FU
teraz kod jest tak długi, że aż nie chce się go przeglądać ;) Dla nadawania nieokreśłonej wartości zamiast tekstu ze spacja np. flag = ' ', decision = ' ' można użyć None lub False czyli flag = None, decision = None. Wydaje mi się to bardziej czytelne.
JS
@furas: zanotowane, dzięki.
Wizzie
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 7 lat
2
jaSwiezak napisał(a):

@Wizzie: przyznam, że pierwszego i ostatniego akapitu twego postu po prostu nie zrozumiałem

  1. Jak powinien wyglądać główny blok kodu? Jaka jest konwencja? Czy powinienem go zamknąć w main() i po prostu go wywołać czy tak jak zrobiłem też jess OK?

Tego właśnie dotyczył mój pierwszy akapit. W Pythonie, w momencie gdy ktoś chce zaimportować twoją bibliotekę, cały kod w niej jest po prostu wykonywany. Na przykład weźmy taki kod w pliku o nazwie super_obliczenia.py:

Kopiuj
def area_of_rectangle(a, b):
    return a * b

area = area_of_rectangle(5, 10)
test = area == 50
print(area)
print(test)

Czyli jakaś prosta funkcja do liczenia pola prostokąta i 4 linijki prymitywnego testu. Pokazałeś ten kod swojemu szwagrowi Markowi. Marek stwierdził: ta funkcja do liczenia pola jest zajebista! Zaimportuje on sobie tą ją w taki sposób:

Kopiuj
from super_obliczenia import area_of_rectangle

Funkcja ładnie się zaimportowała, wszystko działa jak należy, Marek się cieszy. Ale nagle patrzy do konsoli, a tu dwie linijki jakiegoś tekstu. Markowi to bardzo nie pasuje, bo to może wprowadzić w zakłopotanie użytkowników jego programu. W rezultacie tego Marek popada w depresję, sięga do butelki i stacza się na niziny społeczne. W jaki sposób możemy podać rękę Markowi i wyciągnąć go z tej trudnej sytuacji?

A no okazuje się, że można w bardzo prosty sposób. Jeśli uruchamiasz swój program za pomocą komendy python super_obliczenia.py to wszystko działa jak należy, tak? Problem pojawia się, jeśli ktoś importuje twój program z innego modułu. Rozwiązanie to rozgraniczenie tych dwóch rzeczy. Robimy to wykorzystując magiczną zmienną __name__, znajdującą się w każdym module jaki napiszemy. Jeśli uruchamiamy nasz program bezpośrednio (z konsoli), to zmienna __name__ będzie miała wartość __main__. Więc przerabiamy nasz kod w taki sposób:

Kopiuj
def area_of_rectangle(a, b):
    return a * b

if __name__ == '__main__':
    area = area_of_rectangle(5, 10)
    test = area == 50
    print(area)
    print(test)

W tym momencie Marek zapisuje się do AA, powoli wychodzi z dołka i wszystko wraca do normy, a nawet jest lepiej, bo Marek jest bogatszy o naszą wspaniałą funkcję. A nasz program działa identycznie jak wcześniej.


Czy powinienem go zamknąć w main()

W twoim przypadku tak, bo jest go dużo. W powyższym przypadku niekoniecznie, bo to tylko 4 linijki.

JS
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 9 lat
  • Postów:3
0

@Wizzle: okej, już wiem o co chodzi. Rozumiem, że dodanie warunku

Kopiuj
if __name__ == '__main__':

jest po prostu dobrym nawykiem, tak? Korzystając z okazji: polecacie jakąś dobrą stronkę z dobrze napisanymi kodami w pythonie? Oczywiście na poziomie laika.

Dzięki za zobrazowanie mi tego ;) doceniam.

edytowany 1x, ostatnio: jaSwiezak
Wizzie
można uznać za dobry nawyk, ale to raczej konieczność dla kodu, który może być uruchomiony z konsoli
MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:2 minuty
1

robisz za duże funkcję. Szczególnie managment_players jest zbyt skomplikowane (za dużo funkcji sterujących), dziel to na mniejsze funkcje.
Żadna funkcja nie powinna mięcej więcej niż dwie pętle. A 3-4 instrukcje warunkowe (wliczając w to pętle) to też jest już dużo.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
JS
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 9 lat
  • Postów:3
0

W moim kodzie potrzebowałem porównać wartość elementu jednego słownika z wartością elementu zawartego w kolejnym słowniku tej samej listy. Zrobiłem to w ten sposób:

Kopiuj
i = 0
    while sorted_list[i]['player_points'] == sorted_list[i + 1]['player_points']:
        i += 1

Czy istnieje bardziej elegancki sposób na rozwiązanie tego? Dodam, że w tym przypadku potrzebuję skorzystać ze zmiennej i poza pętlą

edytowany 1x, ostatnio: jaSwiezak
IM
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 9 lat
  • Postów:46
0

Obstawiam, że masz posortowanych playerów po pointsach malejąco i że chcesz coś takiego robić, żeby wyciągnąć graczy, którzy zajmują względem punktacji (gdzie gracz z maksymalną liczbą punktów wygrywa) pierwsze miejsce. Można to pewnie zrobić też tak (uważam, że to ładniejsze):

Kopiuj
first_place_winners = [x for x in filter(lambda p: p['player_points'] == sorted_list[0]['player_points'], sorted_list)]

Ale nie wiem. Może chodzi Ci o coś innego ;-)

PS. No i odnoszę wrażenie, że Twój kod się sypnie dla listy takiej, że każdy gracz ma taką samą liczbę punktów.
PS1. Mój zaś sypnie się gdy lista będzie pusta ;-) (Mój się nie sypie, pomyłka.)

edytowany 3x, ostatnio: IForgotMyPass
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)