Το Στέκι των Πληροφορικών

Επαγγελματικό Λύκειο => Γενικά => Προγραμματισμός Υπολογιστών => Μήνυμα ξεκίνησε από: evry στις 09 Φεβ 2017, 08:22:08 ΜΜ

Τίτλος: Βρείτε το λάθος!!!
Αποστολή από: 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

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

Αναφέρω το παραπάνω πρόβλημα γιατί το θεωρώ ενδιαφέρον.
Κάτι τέτοια παραδείγματα δείχνουν ότι πρέπει να επικεντρωνόμαστε στις βασικές έννοιες και όχι στην ασκησεολογία.
Τίτλος: Απ: Βρείτε το λάθος!!!
Αποστολή από: taxata στις 09 Φεβ 2017, 09:07:33 ΜΜ
Ενδιαφέρ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

οπότε θα προκύψει και το  εύλογο ερώτημα: Πως κάνουμε αντίγραφο μίας λίστας οέο  >:(
Τίτλος: Απ: Βρείτε το λάθος!!!
Αποστολή από: itt στις 09 Φεβ 2017, 09:39:22 ΜΜ
Παράθεση από: 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 στις 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

τι έγινε εδώ βρε παιδιά :o
Τίτλος: Απ: Βρείτε το λάθος!!!
Αποστολή από: evry στις 09 Φεβ 2017, 10:12:47 ΜΜ
και αυτό έχει ενδιαφέρον:
Κώδικας (python) [Επιλογή]
A = [1, 2, 3, 4]
L = [A, A, A]
L[1][1] = 100
print L
print A
Τίτλος: Απ: Βρείτε το λάθος!!!
Αποστολή από: pgrontas στις 09 Φεβ 2017, 11:31:35 ΜΜ
Επεμβαίνω, αν και δεν διδάσκω, το μάθημα, αλλά έχω τις εξής παρατηρήσεις:

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

Παράθεση από: itt στις 09 Φεβ 2017, 09:39:22 ΜΜ
Τέτοια παραδείγματα (που σημειωτέον η υλοποίηση του βιβλίου ειναι βλακώδης) δείχνουν πόσο δύσκολο (και σημαντικό) είναι να καταλάβει κανείς την διαφορά μεταξύ αντικειμένου και reference σε αντικείμενο.
Επιπλέον δείχνουν και την αποτυχία πολλών σύγχρονων γλωσσών προγραμματισμούν να το κάνουν σαφές στον προγραμματιστή  ;)
Τίτλος: Απ: Βρείτε το λάθος!!!
Αποστολή από: evry στις 10 Φεβ 2017, 08:38:20 ΠΜ
Η χρήση του τελεστή + για συνένωση λιστών νομίζω ότι είναι μια καλή στρατηγική για να ξεκινήσεις στις λίστες, αφού ήδη οι μαθητές έχουν δει τον ίδιο τελεστή συνένωσης στα αλφαριθμητικά. Άρα μειώνεις τον διδακτικό θόρυβο και εισάγεις κάποιες βασικές έννοιες πιο γρήγορα και εύκολα. Αφού δεις ότι έχουν καταλάβει την έννοια της λίστας τότε μπορείς να μιλήσεις για την append και να εξηγήσεις γιατί πρέπει να χρησιμοποιούν αυτήν.
Δεν χρειάζεται να δείχνουμε πάντα την καλύτερη υλοποίηση. Το σκεπτικό είναι να διευκολύνουμε τους μαθητές επειδή υπεισέρχονται πολλές νέες έννοιες.

Τώρα όσον αφορά την εντολή
Κώδικας (python) [Επιλογή]
positives = negatives = [ ]
πράγματι δεν υπάρχει κάποιο σκεπτικό. Μας ξέφυγε. :-[
Ωστόσο τώρα που το βλέπω είναι μια αφορμή να δώσεις στους μαθητές το τμήμα του προβληματικού κώδικα και να γίνει μια συζήτηση μέσα στην τάξη
Τίτλος: Απ: Βρείτε το λάθος!!!
Αποστολή από: zsdregas στις 10 Φεβ 2017, 10:23:22 ΠΜ
Για να σιγουρευτώ, στην πρώτη περίπτωση έχουμε 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 στις 10 Φεβ 2017, 03:33:25 ΜΜ
Κοιτά για να το θέσουμε σωστά (δηλαδή 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 στις 16 Μαρ 2017, 12:29:05 ΜΜ
Συνοπτικά από τα παραδείγματα των συναδέλφων προκύπτει υπάρχει πρόβλημα ορθής κατανόησης:
1) Της σημασιολογίας της χρήσης των μεταβλητών στην python (variable semantics)
2) Της σημασιολογίας και τον μηχανισμός υλοποιήσης του περάσματος ορισμάτων σε μια συνάρτηση.
Στη wikipedia αναφέρεται και σαν Evaluation strategy (https://en.wikipedia.org/wiki/Evaluation_strategy)
Ως προς την σημασιολογία των μεταβλητών κατατοπιστικό μου φάνηκε και το: Understanding python variables (https://mathieularose.com/python-variables/)


Όπως γράφει και ο itt στην python μια εντολή ανάθεσης τιμής (assignment statement)  (https://docs.python.org/2/reference/simple_stmts.html#assignment-statements)
συσχετίζει (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 (http://pythontutor.com/visualize.html#code=numbers%20%3D%20%5B11,-22,33,-44%5D%0Apositives%20%3D%20negatives%20%3D%20%5B%20%5D%0Afor%20number%20in%20numbers%20%3A%20%20%20%20%20%20%20%20%20%0A%20%23%20%CE%B3%CE%B9%CE%B1%20%CE%BA%CE%AC%CE%B8%CE%B5%20%CE%B1%CF%81%CE%B9%CE%B8%CE%BC%CF%8C%20%CF%84%CE%B7%CF%82%20%CE%BB%CE%AF%CF%83%CF%84%CE%B1%CF%82%0A%20%20%20if%20number%20%3E%200%20%3A%0A%20%20%20%20%20%20%20%20%23%20%CE%B1%CE%BD%20%CE%B5%CE%AF%CE%BD%CE%B1%CE%B9%20%CE%B8%CE%B5%CF%84%CE%B9%CE%BA%CF%8C%CF%82%0A%20%20%20%20%20%20%20%20positives%20%3D%20positives%20%2B%20%5B%20number%20%5D%0A%20%20%20%20%20%20%20%23%20%CF%80%CF%81%CF%8C%CF%83%CE%B8%CE%B5%CF%83%CE%AD%20%CF%84%CE%BF%CE%BD%20%CF%83%CF%84%CE%B7%20%CE%BB%CE%AF%CF%83%CF%84%CE%B1%20%CE%BC%CE%B5%20%CF%84%CE%BF%CF%85%CF%82%20%CE%B8%CE%B5%CF%84%CE%B9%CE%BA%CE%BF%CF%8D%CF%82%0A%20%20%20else%20%3A%0A%20%20%20%20%20%20%20negatives%20%3D%20negatives%20%2B%20%5B%20number%20%5D%0A%23%20%CE%B1%CE%BB%CE%BB%CE%B9%CF%8E%CF%82%20%CF%83%CF%84%CE%B7%20%CE%BB%CE%AF%CF%83%CF%84%CE%B1%20%CE%BC%CE%B5%20%CF%84%CE%BF%CF%85%CF%82%20%CE%B1%CF%81%CE%BD%CE%B7%CF%84%CE%B9%CE%BA%CE%BF%CF%8D%CF%82%0Aprint%20positives%0Aprint%20negatives&cumulative=false&curInstr=0&heapPrimitives=false&mode=display&origin=opt-frontend.js&py=2&rawInputLstJSON=%5B%5D&textReferences=false)

Ο Διαχωρισμός λίστας  με την append που δεν λειτουργεί στο pythontutor (http://pythontutor.com/visualize.html#code=lista%20%3D%20%5B11,-22,33,-44%5D%0Apositives%20%3D%20negatives%20%3D%20%5B%5D%0Afor%20number%20in%20lista%3A%0A%20%20%20%20if%20number%20%3E%200%20%3A%0A%20%20%20%20%20%20%20%20positives.append%28number%29%0A%20%20%20%20elif%20number%20%3C%200%20%3A%0A%20%20%20%20%20%20%20%20negatives.append%28number%29%0Aprint%20positives%0Aprint%20negatives%0A%20&cumulative=false&curInstr=0&heapPrimitives=false&mode=display&origin=opt-frontend.js&py=2&rawInputLstJSON=%5B%5D&textReferences=false)

Ενδιαφέρον και κατατοπιστικό στο θέμα είναι και το Is Python pass-by-reference or pass-by-value? (http://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dick/)

Λίγο αργά βρήκα και τη σχετική συζήτηση σε άλλο νήμα :  Διορθώσεις Βιβλίου Προγραμματισμός Υπολογιστών Γ ΕΠΑΛ (https://alkisg.mysch.gr/steki/index.php?topic=6911.0)

Κώδικας (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 δεν άλλαξε


Διαδραστική αποσφαλμάτωση του παραπάνω κώδικα  (http://pythontutor.com/visualize.html#code=a%20%3D%20%5B5,8,13,21,43%5D%0Ab%20%3D%20a%5B%3A%5D%0Ad%20%3D%20a%0Aa.pop%28%29%0Ad.pop%28%29%0Aa%5B0%5D%3Da%5B1%5D%3D6%0Aprint%20a,b,d&cumulative=false&curInstr=0&heapPrimitives=false&mode=display&origin=opt-frontend.js&py=2&rawInputLstJSON=%5B%5D&textReferences=false)στο pythontutor.com

Local variable referenced before assignment in Python? (http://stackoverflow.com/questions/18002794/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 στις 19 Μαρ 2017, 07:25:37 ΜΜ
Επειδή ειδικά τα τελευταία μηνύματα δεν είχαν απολύτως καμία σχέση με το θέμα του thread.
Στο παρακάτω thread μεταφέρθηκαν τα μηνύματα σχετικά με το πόσο ακατάλληλη είναι η Python για την εκπαίδευση:
Είναι η Python Εκπαιδευτική γλώσσα?  (https://alkisg.mysch.gr/steki/index.php?topic=7027.msg79664#msg79664)

και στο παρακάτω μπορείτε να γράψετε ότι θέλετε περί φιλοσοφίας, μαθηματικών, πληροφορικής κλπ
Δείκτες, Αριθμητική Peano, Φιλοσοφία κλπ (https://alkisg.mysch.gr/steki/index.php?topic=7026.msg79669#msg79669)

Υπάρχει πάντως και η απόδειξη του Godel για την ύπαρξη του Θεού που ταιριάζει αρκετά θα έλεγα στο παραπάνω thread!
Gödel's ontological proof (https://en.wikipedia.org/wiki/G%C3%B6del's_ontological_proof)

αφού συνδυάζει μαθηματικά, φιλοσοφία και ... πληροφορική
Automating Godel's Ontological Proof of God's Existence with Higher-order Automated Theorem Provers (http://page.mi.fu-berlin.de/cbenzmueller/papers/C40.pdf)

Παρακαλώ στο thread αυτό μόνο μηνύματα σχετικά με το αρχικό πρόβλημα που έθεσα και είναι πολύ σημαντικό στην διδακτική πράξη.  :police: