Βρείτε το λάθος!!!

Ξεκίνησε από evry, 09 Φεβ 2017, 08:22:08 ΜΜ

« προηγούμενο - επόμενο »

evry

Προσπαθώντας να λύσω μια άσκηση του τετραδίου μαθητή στην οποία ζητείται να διαχωριστεί μια λίστα αριθμών σε δυο λίστες θετικών και αρνητικών υλοποίησα την παρακάτω "αφελή" λύση:
Κώδικας: python
def splitbySign(L):
    positives = negatives = []
    for number in L:
        if number > 0 :
            positives.append(number)
        elif number < 0 :
            negatives.append(number)
    print positives
    print negatives

Αν εκτελέσουμε τον παρακάτω κώδικα η απάντηση που θα πάρουμε δεν είναι σωστή.
Που είναι το λάθος? Γιατί συμβαίνει αυτό? Πως θα το διορθώσουμε χωρίς να πειράξουμε τον κώδικα μέσα στην επανάληψη?

Στο βιβλίο υπάρχει αντίστοιχο παράδειγμα το οποίο όμως είναι υλοποιημένο ως εξής και το οποίο δουλεύει σωστά!
Κώδικας: python
def splitbySign2(L):
    positives = negatives = []
    for number in L:
        if number > 0 :
            positives = positives + [number]
        elif number < 0 :
            negatives = negatives + [number]
    print positives
    print negatives

Αυτό γιατί δουλεύει?

Αναφέρω το παραπάνω πρόβλημα γιατί το θεωρώ ενδιαφέρον.
Κάτι τέτοια παραδείγματα δείχνουν ότι πρέπει να επικεντρωνόμαστε στις βασικές έννοιες και όχι στην ασκησεολογία.
What I cannot create I do not understand -- Richard Feynman
http://evripides.mysch.gr

taxata

#1
Ενδιαφέρoυσα σπαζοκεφαλιά για επίδειξη στο μάθημα :D

Αρχικά το λάθος βρίσκεται στο positives = negatives = [] διότι δείχνουν στην ίδια θέση μνήμης οπότε κάθε εισαγωγή ενός νέου στοιχείου αφορά και στις δύο λίστες.
---
Στη συνέχεια δεν προκύπτει λάθος γιατί η εντολή  positives = positives + [number] ξαναορίζει νέα λίστα positives & negatives αντίστοιχα

μπορούν να εξηγηθούν στους μαθητές  με τη βοήθεια της εντολής id, id(positives).

Να ακόμα ένα λάθος
Κώδικας: python
# Δημιουργία αντιγράφου λίστας
first = [1, 2, 3]
second = first
first.append(4)
print first, second

οπότε θα προκύψει και το  εύλογο ερώτημα: Πως κάνουμε αντίγραφο μίας λίστας οέο  >:(
Τάσος_Χατζηπαπαδόπουλος
Κύριε δεν έχω internet
http://users.sch.gr/chatzipap/

itt

Παράθεση από: evry στις 09 Φεβ 2017, 08:22:08 ΜΜ
Προσπαθώντας να λύσω μια άσκηση του τετραδίου μαθητή στην οποία ζητείται να διαχωριστεί μια λίστα αριθμών σε δυο λίστες θετικών και αρνητικών υλοποίησα την παρακάτω "αφελή" λύση:
Κώδικας: python
def splitbySign(L):
    positives = negatives = []
    for number in L:
        if number > 0 :
            positives.append(number)
        elif number < 0 :
            negatives.append(number)
    print positives
    print negatives

Αν εκτελέσουμε τον παρακάτω κώδικα η απάντηση που θα πάρουμε δεν είναι σωστή.
Που είναι το λάθος? Γιατί συμβαίνει αυτό? Πως θα το διορθώσουμε χωρίς να πειράξουμε τον κώδικα μέσα στην επανάληψη?

Στο βιβλίο υπάρχει αντίστοιχο παράδειγμα το οποίο όμως είναι υλοποιημένο ως εξής και το οποίο δουλεύει σωστά!
Κώδικας: python
def splitbySign2(L):
    positives = negatives = []
    for number in L:
        if number > 0 :
            positives = positives + [number]
        elif number < 0 :
            negatives = negatives + [number]
    print positives
    print negatives

Αυτό γιατί δουλεύει?

Αναφέρω το παραπάνω πρόβλημα γιατί το θεωρώ ενδιαφέρον.
Κάτι τέτοια παραδείγματα δείχνουν ότι πρέπει να επικεντρωνόμαστε στις βασικές έννοιες και όχι στην ασκησεολογία.

Τέτοια παραδείγματα (που σημειωτέον η υλοποίηση του βιβλίου ειναι βλακώδης) δείχνουν πόσο δύσκολο (και σημαντικό) είναι να καταλάβει κανείς την διαφορά μεταξύ αντικειμένου και reference σε αντικείμενο.

Δηλαδή ότι το second = first στο παράδειγμα του taxata είναι pointer assignment και όχι object copy.

taxata

Ο δρόμος προς την τελειότητα είναι στρωμένος με λάθη ...
Κώδικας: python
a = 1
b = a
b = 2
print a, b
# ---------------
a = [1]
b = a
b[0] = 2
print a, b

τι έγινε εδώ βρε παιδιά :o
Τάσος_Χατζηπαπαδόπουλος
Κύριε δεν έχω internet
http://users.sch.gr/chatzipap/

evry

και αυτό έχει ενδιαφέρον:
Κώδικας: python
A = [1, 2, 3, 4]
L = [A, A, A]
L[1][1] = 100
print L
print A
What I cannot create I do not understand -- Richard Feynman
http://evripides.mysch.gr

pgrontas

Επεμβαίνω, αν και δεν διδάσκω, το μάθημα, αλλά έχω τις εξής παρατηρήσεις:

Στο αρχικό 'λάθος' του Ευριπίδη για ποιον λόγο να χρησιμοποιήσεις το ιδίωμα της διπλής ανάθεσης στο positives = negatives = []. Προσφέρει κάτι (αλγοριθμικά / εννοιολογικά) στον τρόπο σκέψης των μαθητών;

Παράθεση από: itt στις 09 Φεβ 2017, 09:39:22 ΜΜ
Τέτοια παραδείγματα (που σημειωτέον η υλοποίηση του βιβλίου ειναι βλακώδης) δείχνουν πόσο δύσκολο (και σημαντικό) είναι να καταλάβει κανείς την διαφορά μεταξύ αντικειμένου και reference σε αντικείμενο.
Επιπλέον δείχνουν και την αποτυχία πολλών σύγχρονων γλωσσών προγραμματισμούν να το κάνουν σαφές στον προγραμματιστή  ;)
Programs must be written for people to read, and only incidentally for machines to execute - Harold Abelson

evry

Η χρήση του τελεστή + για συνένωση λιστών νομίζω ότι είναι μια καλή στρατηγική για να ξεκινήσεις στις λίστες, αφού ήδη οι μαθητές έχουν δει τον ίδιο τελεστή συνένωσης στα αλφαριθμητικά. Άρα μειώνεις τον διδακτικό θόρυβο και εισάγεις κάποιες βασικές έννοιες πιο γρήγορα και εύκολα. Αφού δεις ότι έχουν καταλάβει την έννοια της λίστας τότε μπορείς να μιλήσεις για την append και να εξηγήσεις γιατί πρέπει να χρησιμοποιούν αυτήν.
Δεν χρειάζεται να δείχνουμε πάντα την καλύτερη υλοποίηση. Το σκεπτικό είναι να διευκολύνουμε τους μαθητές επειδή υπεισέρχονται πολλές νέες έννοιες.

Τώρα όσον αφορά την εντολή
Κώδικας: python
positives = negatives = [ ]

πράγματι δεν υπάρχει κάποιο σκεπτικό. Μας ξέφυγε. :-[
Ωστόσο τώρα που το βλέπω είναι μια αφορμή να δώσεις στους μαθητές το τμήμα του προβληματικού κώδικα και να γίνει μια συζήτηση μέσα στην τάξη
What I cannot create I do not understand -- Richard Feynman
http://evripides.mysch.gr

zsdregas

Για να σιγουρευτώ, στην πρώτη περίπτωση έχουμε object copy και στη δεύτερη pointer assignment;

Παράθεση από: taxata στις 09 Φεβ 2017, 10:04:49 ΜΜ
Κώδικας: python
a = 1
b = a
b = 2
print a, b
# ---------------
a = [1]
b = a
b[0] = 2
print a, b


itt

Κοιτά για να το θέσουμε σωστά (δηλαδή pythonικά) το a και b, είναι 2 bindings σε ένα object.

Τα πάντα στην python είναι object (ακόμα και οι ακέραιοι στην περίπτωσή μας). Κάποια object είναι immutable όμως (όπως οι ακέραιοι).

Το a = 2, σημαίνει ότι κάνεις bind το a σε ένα int object με την τιμή 2.

To b = a σημαίνει ότι το b κάνει bind στο object που έχει γίνει bind το a.

Δεν υπάρχει κανένα copy. Μπορείς και εσύ να κάνεις verify ότι το b = a, αφού ισχύει id(b) == id(a), εαν το τρέξεις σε έναν interpreter.

Ομοίως και το δεύτερο, απλά στο δεύτερο το object είναι μία λίστα.


aprekates

#9
Συνοπτικά από τα παραδείγματα των συναδέλφων προκύπτει υπάρχει πρόβλημα ορθής κατανόησης:
1) Της σημασιολογίας της χρήσης των μεταβλητών στην python (variable semantics)
2) Της σημασιολογίας και τον μηχανισμός υλοποιήσης του περάσματος ορισμάτων σε μια συνάρτηση.
Στη wikipedia αναφέρεται και σαν Evaluation strategy
Ως προς την σημασιολογία των μεταβλητών κατατοπιστικό μου φάνηκε και το: Understanding python variables


Όπως γράφει και ο itt στην python μια εντολή ανάθεσης τιμής (assignment statement)
συσχετίζει (binds) ένα όνομα με ένα αντικείμενο.
Ένα όνομα δεν μπορεί να συσχετιστεί με άλλο όνομα παρά μόνο με αντικέιμενο.
>> a = 0   # ok
>> a = b   
NameError: name 'c' is not defined


Αν αντιπαραβάλεις από την μια των κώδικα του διαχωρισμού λίστας και της υλοποίησης της διεπαφής της στοιβας (την διορθωμένη)  ή χρήση ή όχι της append δεν είναι εύκολη για καθηγητή πόσο μάλλον για μαθητή.

Υλοποίηση Στοίβας
Κώδικας: python
def push(stack, item) :
  stack.append( item )

def pop(stack) :
  return stack.pop( )

def isEmpty(stack) :
 return len(stack) == 0

def createStack( ) :
 return [ ]




Κώδικας: python
positives = negatives = [ ]
for number in numbers : 	
 # για κάθε αριθμό της λίστας
   if number > 0 :
        # αν είναι θετικός
        positives = positives + [ number ]
       # πρόσθεσέ τον στη λίστα με τους θετικούς
   else :
       negatives = negatives + [ number ]
# αλλιώς στη λίστα με τους αρνητικούς
print positives
print negatives


Διαχωρισμός λίστας σε pythontutor

Ο Διαχωρισμός λίστας  με την append που δεν λειτουργεί στο pythontutor


Ενδιαφέρον και κατατοπιστικό στο θέμα είναι και το Is Python pass-by-reference or pass-by-value?

Λίγο αργά βρήκα και τη σχετική συζήτηση σε άλλο νήμα : Διορθώσεις Βιβλίου Προγραμματισμός Υπολογιστών Γ ΕΠΑΛ

Κώδικας: python
  def test(mylist):
        mylist[0] = mylist[1] = 100
     
  >>> a = [2, 4, 5]
  >>> test( a ) 
  >>> print a
  [100,100,5]


Αυτό το παράδειγμα του evry δείχνει ότι δεν εχουμε call by value .

Για το παράδειγμα του taxata (πως δημιουργούμε αντίγραφο λίστας;

Κώδικας: python
>> # Δημιουργία αντιγράφου λίστας
>>first = [1, 2, 3]
>> second = first
>> first.append(4)
>> print first, second
[1,2,3,4],[1,2,3,4]


η απάντηση είναι στην δραστηριότητα 5.3.4 του βιβλίου της Β :
Κώδικας: python
>>> a = [5,8,13,21,34]
>>> b = a[:]
>>> d = a
>>> a.pop()
34
>>> d.pop()
21
>>> a[0]=a[1]=6
>>> print a,b,d
[6, 6, 13] [5, 8, 13, 21, 34] [6, 6, 13]
>>> # η λίστα b δεν άλλαξε


Διαδραστική αποσφαλμάτωση του παραπάνω κώδικα στο pythontutor.com

Local variable referenced before assignment in Python? Μια ακόμη εξήγηση για το παράδειγμα του msoukara :

Κώδικας: python
x = 50
def func():
     print('Το x είναι', x)          
     x = 2
     print('Το τοπικό x άλλαξε σε', x)
func()
print('Το x είναι ακόμα', x)
# UnboundLocalError: local variable 'x' referenced before assignment


ΥΓ:  μεταφέρω-αντιγραφω σκόρπια παραδειγματα προκειμένου ισως να φανεί καλύτερα το ζητούμενο

evry

#10
Επειδή ειδικά τα τελευταία μηνύματα δεν είχαν απολύτως καμία σχέση με το θέμα του thread.
Στο παρακάτω thread μεταφέρθηκαν τα μηνύματα σχετικά με το πόσο ακατάλληλη είναι η Python για την εκπαίδευση:
Είναι η Python Εκπαιδευτική γλώσσα?

και στο παρακάτω μπορείτε να γράψετε ότι θέλετε περί φιλοσοφίας, μαθηματικών, πληροφορικής κλπ
Δείκτες, Αριθμητική Peano, Φιλοσοφία κλπ

Υπάρχει πάντως και η απόδειξη του Godel για την ύπαρξη του Θεού που ταιριάζει αρκετά θα έλεγα στο παραπάνω thread!
Gödel's ontological proof

αφού συνδυάζει μαθηματικά, φιλοσοφία και ... πληροφορική
Automating Godel's Ontological Proof of God's Existence with Higher-order Automated Theorem Provers

Παρακαλώ στο thread αυτό μόνο μηνύματα σχετικά με το αρχικό πρόβλημα που έθεσα και είναι πολύ σημαντικό στην διδακτική πράξη.  :police:
What I cannot create I do not understand -- Richard Feynman
http://evripides.mysch.gr