Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.
  • Στο παρακάτω πρόγραμμα καλείται η συνάρτηση ypol και στην ουσία προσθέτει στη λίστα α το 5. Παρότι δεν έγραψα return a στην εκτύπωση με την print θα εκτυπώσει την νέα λίστα a και όχι την τιμή 1 που είναι η παλιά .

def ypol(a):
    a+=[5]
    

a=[1]
ypol(a)
print(a)

  • Αν όμως έχω απλή μεταβλητή  τότε θα εκτυπωθεί η τιμή που έχει η μεταβλητή από το κυρίως πρόγραμμα ακόμη και αν βάλω return a στο τέλος της συνάρτησης.

def ypol(a):
    a+=5
    return a

a=1
ypol(a)
print(a)

Για να γίνει εκτύπωση της τιμής της μεταβλητής a όπως αλλάζει μέσα από την συνάρτηση θα πρέπει να διορθώσω ως εξής :

def ypol(a):
    a+=5
    return a

a=1
a=ypol(a)
print(a)

 

Και η ερώτηση είναι η εξής: η Συνάρτηση γυρίζει μια λίστα ακόμα και χωρίς την return , ενώ αν πρόκειται  για απλή μεταβλητή θέλει return και αποθήκευση σε νέα μεταβλητή (δηλ a=ypol(a) ) ;

Συγνώμη για το μακροσκελές μήνυμα αλλά ήθελα να είμαι όσο το δυνατόν περισσότερο κατανοητός.

Δημοσ. (επεξεργασμένο)

Η συνάρτηση δεν επιστρέφει λίστα χωρίς return. Όποια συνάρτηση δεν έχει return επιστρέφει implicitly None.

Για να καταλάβεις γιατί τυπώνεται η τιμή που τυπώνεται σε κάθε call πρέπει να καταλάβεις τι είναι global/local scope. Αν θέλεις να αλλάξεις την τιμή μιας global μεταβλητής μέσα από ένα function μπορείς να κάνεις bind σε global scope μέσα από ένα function (γενικά κακή πρακτική που πρέπει να αποφεύγεται).

 

Επεξ/σία από iceblade
Δημοσ.

Στο πρώτο παράδειγμα έχεις λίστα, και επίσης να μη χρησιμοποιείς το ίδιο όνομα μεταβλητής με τη μεταβλητή της συνάρτησης. Και το σωστό είναι να κλείνεις με return.

Με λίγα λόγια το πρώτο παράδειγμα σου καλύτερα γράφεται έτσι

def ypol(x):
    x+=[5]
    return x
    

a=[1]
ypol(a)
print(a)

Δηλαδή εσύ αρχικοποιείς το a με μια τιμή και με αυτή την τιμή πας στη συνάρτηση ypol και βάζεις όπου x το a. Αν βάζεις παντού το a θα μπερδευτείς και εσύ και το πρόγραμμα.

Δημοσ. (επεξεργασμένο)

@likourgos όπως σου είπε ο @iceblade έχει να κάνει με τα scopes της Python. Ψάξε στο google και θα βρεις και αρκετά και καλά tutorials επί του θέματος.

Μέχρι να τα καταλάβεις καλύτερα, η συμβουλή μου είναι να περνάς όλες τις μεταβλητές που χρειάζεται η κάθε συνάρτηση και να επιστρέφεις explicitly και να μη βασίζεσαι στο global scope. Πχ

def append_5(lst):
    lst.append(5)
    return lst

a = [1]
print(a)
a = append_5(a)
print(a)

 

Επεξ/σία από pmav99
  • Like 1
Δημοσ. (επεξεργασμένο)

Έχει επίσης να κάνει με mutable, immutable, by value, by reference και όλες αυτές τις έννοιες.

Ένας άλλος τρόπος για να αλλάξεις immutable object είναι να το βάλεις μεσ στη συνάρτηση ως global

>>> a=1
>>> def ypol():
	global a
	a+=5

>>> ypol()
>>> print(a)
6

Ένας καλός οδηγός είναι εδώ https://www.python-course.eu/python3_passing_arguments.php

Σε γενικές γραμμές άλλο αριθμός άλλο λίστα (άλλο immutable άλλο mutable)

Ή ακολουθείς τους κανόνες που σου είπαν παραπάνω και έχεις λιγότερα μπερδέματα

Το διάβασα και εγώ άλλη μία και εδώ είναι η ουσία

Correctly speaking, Python uses a mechanism, which is known as "Call-by-Object", sometimes also called "Call by Object Reference" or "Call by Sharing".

If you pass immutable arguments like integers, strings or tuples to a function, the passing acts like call-by-value. The object reference is passed to the function parameters. They can't be changed within the function, because they can't be changed at all, i.e. they are immutable. It's different, if we pass mutable arguments. They are also passed by object reference, but they can be changed in place in the function. If we pass a list to a function, we have to consider two cases: Elements of a list can be changed in place, i.e. the list will be changed even in the caller's scope. If a new list is assigned to the name, the old list will not be affected, i.e. the list in the caller's scope will remain untouched.

 

Επεξ/σία από k33theod
  • Like 2
Δημοσ.
6 ώρες πριν, becoming_I είπε

Στο πρώτο παράδειγμα έχεις λίστα, και ..

 

Ευχαριστώ για τις απαντήσεις όλους.Τα περί global τα γνωρίζω. Απλά επειδή είμαι ακόμη μαθητευόμενος (σκράπας :-) )κάνοντας διάφορα παραδείγματα "έπεσα"  στο προαναφερόμενο.

Άρα λοιπόν σε περίπτωση λίστας μπορώ να μην βάλω return? (Άσχετα αν είναι πρέπον να κλείνω με return) .

Δημοσ.
57 minutes ago, likoyrgos said:

Άρα λοιπόν σε περίπτωση λίστας επειδή είμαι ακόμα μαθητευόμενος μπορώ να μην βάλω θα βάζω πάντα return.

Fixed

Τώρα αφού ψάχνεσαι και θες να πας ένα βήμα παραπέρα, διάβασε αυτό το thread και πιο συγκεκριμένα τις απαντήσεις των Alex Hudson και Alex Martelli (το thread είναι και εδώ με καλύτερο format). Διάβασε το όσες φορές χρειαστεί μέχρι να το καταλάβεις. Αν εξακολουθείς να έχεις απορίες, εδώ είμαστε.

 

 

  • Like 1
Δημοσ. (επεξεργασμένο)
1 ώρα πριν, likoyrgos είπε

Ευχαριστώ για τις απαντήσεις όλους.Τα περί global τα γνωρίζω. Απλά επειδή είμαι ακόμη μαθητευόμενος (σκράπας :-) )κάνοντας διάφορα παραδείγματα "έπεσα"  στο προαναφερόμενο.

Άρα λοιπόν σε περίπτωση λίστας μπορώ να μην βάλω return? (Άσχετα αν είναι πρέπον να κλείνω με return) .

Σωστά γίνεται όμως κατά κάποιο τρόπο implicit. Δεν είναι ξεκάθαρο ότι θες να αλλάξει η λίστα σου και αυτό δεν είναι τόσο καλό.  Explicit is better than implicit.

Εγώ θα το έκανα έτσι

>>> def change_a_list(a_list):
	changed_list=a_list[:]
	changed_list+=[5]
	#kai allos kodikas poz kanei oti thelei tin alli lista
	return changed_list

και μόνο όταν γραφτεί κώδικας

my_precious = change_list(my_precious) 

που είναι explicit  θα αλάξει η my_precious

11 λεπτά πριν, pmav99 είπε

Fixed

Τώρα αφού ψάχνεσαι και θες να πας ένα βήμα παραπέρα, διάβασε αυτό το thread και πιο συγκεκριμένα τις απαντήσεις των Alex Hudson και Alex Martelli (το thread είναι και εδώ με καλύτερο format). Διάβασε το όσες φορές χρειαστεί μέχρι να το καταλάβεις. Αν εξακολουθείς να έχεις απορίες, εδώ είμαστε.

pmav

Αυτά που έχει ο κώδικας από μια ματιά που έριξα δεν ισχύουν πλέον.

>>> dict1 = {'a':1,'b':2}
>>> list1 = dict1.values()
>>> dict1['a']=3
>>> list1
dict_values([3, 2])
σε 3.6 είναι

 

Επεξ/σία από k33theod
Δημοσ.

@k33theod Έχεις δίκιο. Η αλλαγή είναι ότι στην Python 3 η μέθοδος dict.values() δεν επιστρέφει list όπως στην Python 2 αλλά dict Views:

https://stackoverflow.com/questions/8957750/what-are-dictionary-view-objects

https://docs.python.org/3/library/stdtypes.html#dictionary-view-objects

Το παράδειγμα στην Python 3 πρέπει να είναι έτσι:

>>> dict1 = {'a':1,'b':2}
>>> list1 = list(dict1.values())
>>> dict1['a']=3
>>> list1

Πάλι βγαίνει άκρη, αλλά αυξάνει το επίπεδο δυσκολίας λόγω των views... Κρίμα γιατί είναι πολύ καλό tutorial.

Δημοσ. (επεξεργασμένο)
7 ώρες πριν, likoyrgos είπε

Ευχαριστώ για τις απαντήσεις όλους.Τα περί global τα γνωρίζω. Απλά επειδή είμαι ακόμη μαθητευόμενος (σκράπας :-) )κάνοντας διάφορα παραδείγματα "έπεσα"  στο προαναφερόμενο.

Άρα λοιπόν σε περίπτωση λίστας μπορώ να μην βάλω return? (Άσχετα αν είναι πρέπον να κλείνω με return) .

Δεν είναι η λίστα το θέμα, αλλά εάν η μεταβλητή είναι mutable ή immutable object. Αυτό που παρέθεσε ο k33theod μπορείς να το δεις να δουλεύει εδώ:

def foo(b):
  b.extend([4])

def bar(b):
  b = [3, 4, 5]

a = [1, 2]

foo(a)
print(a)

bar(a)
print(a)

Τα mutable objects μπορούν να αλλάξουν τιμή σε άλλο scope, αρκεί να παραμείνει ανέπαφος ο pointer που δείχνει στην αρχή τους.  Εάν αλλάξει ο pointer που δείχνει στην αρχή τους, τότε η μεταβλητή ξαναδείχνει εκεί που έδειχνε (με αποτέλεσμα να γυρνάει στην παλιά τιμή). Φαντάζομαι ότι θα έχουν κάτι πιο advanced από το να ζητάνε από το λειτουργικό συνέχεια παραπάνω μνήμη για μία λίστα, αλλά κάπως έτσι το αντιλαμβάνομαι σαν αναλογία. 

Το να επιστρέφει κάτι η συνάρτηση είναι καλή πρακτική. Σε μικρά κομμάτια κώδικα (π.χ., όπως το παραπάνω, δηλαδή 10-20 γραμμές) δεν έχει ιδιαίτερη σημασία εάν γυρνάει ή όχι κάτι η συνάρτηση. Όταν όμως αρχίσεις να έχεις πολλές συναρτήσεις, μεγάλα scripts, κλάσεις, και να συνεργάζεσαι με άλλους, τότε θα θες κάτι που να είναι safe. 

 

Επεξ/σία από Fortistis

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...