dönüş, dönüş Yok ve dönüş yok mu?


386

Üç işlevi göz önünde bulundurun:

def my_func1():
  print "Hello World"
  return None

def my_func2():
  print "Hello World"
  return

def my_func3():
  print "Hello World"

Hepsi Yok gibi görünüyor. Bu işlevlerin döndürülen değerinin davranışları arasında herhangi bir fark var mı? Birini diğerine tercih etmek için herhangi bir neden var mı?


40
Stilistik bir fark olduğunu unutmayın. return Nonebana göre fonksiyon bazen Nonegeri dönüşü olmayan bir değere sahiptir, fakat konumunda return Noneböyle bir dönüş değeri yoktur. Hiçbir Yazma returnhiç asla ilginç bir dönüş değeri tür bir "işlev" yerine bir "prosedür" gibi orada bana ima eder. returnönceki noktaya göre bir "prosedür" den erken var olması anlamına gelir.

Yanıtlar:


500

Gerçek davranışta, hiçbir fark yoktur. Hepsi geri döndü Noneve hepsi bu. Ancak, tüm bunlar için bir zaman ve yer var. Aşağıdaki talimatlar temel olarak farklı yöntemlerin nasıl kullanılması gerektiğidir (veya en azından bana nasıl öğretilmesi gerektiği öğretilmiştir), ancak bunlar mutlak kurallar değildir, böylece gerekli görürseniz bunları karıştırabilirsiniz.

kullanma return None

Bu, işlevin gerçekten daha sonra kullanılmak üzere bir değer döndürmeyi amaçladığını ve bu durumda geri döndüğünü belirtir None. Bu değer Nonedaha sonra başka bir yerde kullanılabilir. return Noneişlevden başka olası dönüş değerleri yoksa asla kullanılmaz.

Aşağıdaki örnekte, dönüş person's mothereğer persongibi verilen bir insandır. Bu bir insan değil, biz iade Noneberi personbir yok mother(en bir hayvan veya bir şey değil varsayalım).

def get_mother(person):
    if is_human(person):
        return person.mother
    else:
        return None

kullanma return

Bu, breakdöngülerdekiyle aynı nedenden dolayı kullanılır . Dönüş değeri önemli değildir ve yalnızca tüm işlevden çıkmak istersiniz. Bazı yerlerde, çok sık ihtiyacınız olmasa bile, son derece yararlıdır.

15 prisonerstane var ve onlardan birinin bıçağı olduğunu biliyoruz. prisonerBıçakları olup olmadığını kontrol etmek için her birini tek tek dolaşıyoruz . Kişiye bıçakla vurursak, işlevden çıkabiliriz çünkü sadece bir bıçak olduğunu ve kontrolün geri kalanının bir nedeni olmadığını biliyoruz prisoners. prisonerBıçakla bulamazsak bir uyarı yaparız. Bu birçok farklı şekilde yapılabilir ve kullanmak returnmuhtemelen en iyi yol değildir, ancak returnbir işlevden çıkmak için nasıl kullanılacağını göstermek için sadece bir örnektir .

def find_prisoner_with_knife(prisoners):
    for prisoner in prisoners:
        if "knife" in prisoner.items:
            prisoner.move_to_inquisition()
            return # no need to check rest of the prisoners nor raise an alert
    raise_alert()

Not: var = find_prisoner_with_knife()Dönüş değeri yakalanma amacı taşımadığından asla yapmamalısınız .

Hiçbir kullanma returnhiç

Bu da geri dönecektir None, ancak bu değerin kullanılması veya yakalanması amaçlanmamıştır. Bu, işlevin başarıyla sona erdiği anlamına gelir. Temelde aynı şey returnde voidböyle C ++ veya Java gibi dillerdeki işlevlere.

Aşağıdaki örnekte, kişinin annesinin adını belirledik ve daha sonra başarıyla tamamlandıktan sonra işlevden çıkılıyor.

def set_mother(person, mother):
    if is_human(person):
        person.mother = mother

Not: var = set_mother(my_person, my_mother)Dönüş değeri yakalanma amacı taşımadığından asla yapmamalısınız .


5
var = get_mother()Eğer geçen eğer Tamam varkabul eden diğer fonksiyonlara None- "asla" biraz aşırıdır
joelb

Kullanılamazsa dönüş değeri nasıl kabul edilmelidir var = get_mother()? IMHO bunu yapmak tamamen iyi. Kullanmadan önce Nonedeğeri olmayan bir değerle kontrol ettiğinizden emin olmanız yeterlidir if var.
winklerrr

Bunun sadece iyi bir sözleşme olmadığını, PEP8 için gerekli olduğunu belirtmenin önemli olduğunu düşündüm. Sizinkine iltifat etmek için bir cevap gönderirim ve bunun üzerine PEP8 alıntısı yaparım
Fabiano

29

Evet, hepsi aynı.

Yorumlanan makine kodunu gözden geçirerek hepsinin aynı şeyi yaptığını doğrulayabiliriz.

import dis

def f1():
  print "Hello World"
  return None

def f2():
  print "Hello World"
  return

def f3():
  print "Hello World"

dis.dis(f1)
    4   0 LOAD_CONST    1 ('Hello World')
        3 PRINT_ITEM
        4 PRINT_NEWLINE

    5   5 LOAD_CONST    0 (None)
        8 RETURN_VALUE

dis.dis(f2)
    9   0 LOAD_CONST    1 ('Hello World')
        3 PRINT_ITEM
        4 PRINT_NEWLINE

    10  5 LOAD_CONST    0 (None)
        8 RETURN_VALUE

dis.dis(f3)
    14  0 LOAD_CONST    1 ('Hello World')
        3 PRINT_ITEM
        4 PRINT_NEWLINE            
        5 LOAD_CONST    0 (None)
        8 RETURN_VALUE      

4
Burada dikkatli ol ... dis.disdöner None: -X
mgilson

Dis çıktısını dize olarak almanın tek yolu stdout'u bir çeşit IO tamponuna (örn. StringIO) yönlendirmektir. O zaman bile, doğrudan böyle karşılaştırmak, dis.disbazı satır numaralarını da rapor ettiğine inandığım gibi çalışmayabilir ...
mgilson

Yine de aynı kayıtları kullanıyor olup olmamaları önemsizdir, bu yüzden kodumu değiştirdim, bu yüzden aptal dize karşılaştırması yapmak yerine sadece makine kodunu göz ardı ettik. Büyük kafalar için teşekkürler.
David Marx

19

Her biri aynı singletonu döndürür None- İşlevsel bir fark yoktur.

Ben returnerken işlevden (bu durumda çıplak returndaha yaygındır) ya da başka bir şey dönmek için gerekmedikçe ifadeyi bırakmak makul deyim olduğunu düşünüyorum None. Ayrıca mantıklı ve return Nonebaşka bir yol döndüren başka bir yol içeren bir işlevdeyken yazmak için deyimsel gibi görünüyor None. return NoneAçıkça yazmak , okuyucuya daha ilginç bir şey veren başka bir dalın (ve arama kodunun muhtemelen her iki dönüş değeri türünü işlemesi gerekeceği) görsel bir ipucudur.

Genellikle Python, döndüren işlevler Nonegibi kullanılan voidC fonksiyonları - Bunların amacı girdi argümanları üzerinde çalışmak üzere genellikle yerinde (küresel veri (kullandığınız sürece Ürperir )). Geri dönmek Nonegenellikle argümanların mutasyona uğradığını daha açık hale getirir. Bu, returnifadeyi neden "dil sözleşmeleri" açısından terk etmenin mantıklı olduğunu biraz daha açık hale getirir .

Dedi ki, zaten bu şeyler etrafında önceden ayarlanmış sözleşmeleri olan bir kod tabanı üzerinde çalışıyorsanız, kesinlikle kod tabanı üniforma kalmasına yardımcı olmak için takım elbise takip ediyorum ...


1
Veya daha genel olarak, bir fonksiyon herhangi bir returnifadeye çarpmadan sona erdiğinde geri döner None.

İşlev bir değer döndürmesi bekleniyorsa, return deyimini atlamak deyimsel değildir. Yalnızca yan etkilerle çalışan işlevler return ifadesini atlamalıdır.
molekül

@molecule - Evet, sanırım burada açıklamamda en iyi işi yapmadım. Yukarıdaki (çok daha iyi) cevap tam bir klon yapmadan güncellemeye çalıştım. Bu yazı ile hala çok mutlu değilim ... Bir parçam onu ​​silmek istiyor (yukarıdaki cevap çok daha iyi olduğu için) ve bir parçam tutmak istiyor - 9 kişi şu ana kadar iyi olduğunu düşündü bir sebepten ötürü. Belki bir başkasının kaçırdığı bir şeye çarptım?
mgilson

1
@ZAB - Bunun mümkün olduğunu düşünmüyorum. Python'da bir şeyi herhangi bir şeyle yatırabilirim (bu tasarımdan kaynaklanır ve az kullanılırsa harika bir özelliktir). Özellikle, olmayan bir işlevi olan bir işlevi maymun yaması. "İfade değil" kontrollerinin tümü ayrıştırma zamanında gerçekleşir, ancak maymun düzeltme eki nedeniyle bu çalışma zamanına kadar gerçekleşemez. IOW, tamamen farklı. Şahsen, mevcut davranışın oldukça makul olduğunu düşünüyorum (ve diğer üst düzey dillerle tutarlı), ancak ikna etmeniz gereken kişi değilim :-).
mgilson

1
@ZAB - her ikisi de Rubyve Javascriptpython ile aynı yaklaşımı benimser. Emin oradaki değilim olduğu ifadesinde "boşluk" demek yüksek seviyeli dillerin örnekler ama şu an (siz düşünün belki de herhangi düşünemiyorum Javaüst düzey bir dil) ... Nasıl olur maymun yama bir fonksiyon (diğer şeylerin yanı sıra testlerde alay etmek için yararlıdır) varsayımsal bir dünyada çalışır, voidbu fonksiyonun bir şey döndürmemesi için python'un bir anahtar kelimesi var mı? (Ayrıca, daha önce söylediğim gibi, beni bunun kötü bir tasarım olduğuna ikna etmenize gerek yok. Haklı olsanız bile hiçbir şey yapamam)
mgilson

4

Diğerlerinin cevapladığı gibi, sonuç tamamen aynıdır, Noneher durumda iade edilir.

Fark stilistiktir, ancak PEP8'in kullanımın tutarlı olmasını gerektirdiğini lütfen unutmayın :

Dönüş ifadelerinde tutarlı olun. Bir işlevdeki tüm döndürme ifadeleri bir ifade döndürmeli ya da hiçbiri döndürmemelidir. Herhangi bir döndürme ifadesi bir ifade döndürürse, hiçbir değerin döndürülmediği döndürme ifadeleri bunu açıkça döndürme Yok olarak belirtmeli ve işlevin sonunda (ulaşılabilirse) açık bir dönüş ifadesi bulunmalıdır.

Evet:

def foo(x):
    if x >= 0:
        return math.sqrt(x)
    else:
        return None

def bar(x):
    if x < 0:
        return None
    return math.sqrt(x)

Hayır:

def foo(x):
    if x >= 0:
        return math.sqrt(x)

def bar(x):
    if x < 0:
        return
    return math.sqrt(x)

https://www.python.org/dev/peps/pep-0008/#programming-recommendations


Temel olarak, Nonebir işlevde değer olmayan bir değer döndürürseniz, dönüş değerinin anlamı olduğu ve arayanlar tarafından yakalanması gerektiği anlamına gelir. Bu nedenle, geri döndüğünüzde None, Nonebu durumda anlam ifade etmek için açık olması gerekir , olası dönüş değerlerinden biridir.

Hiç geri dönüşe ihtiyacınız yoksa, fonksiyon temel olarak bir fonksiyon yerine bir prosedür olarak çalışır, bu yüzden sadece returnifadeyi dahil etmeyin .

Prosedür benzeri bir işlev yazıyorsanız ve daha önce geri dönme fırsatı varsa (yani o noktada zaten işiniz bitmiştir ve işlevin geri kalanını yürütmeniz gerekmiyorsa) returnokuyucuya sinyal vermek için boş s yürütmenin sadece erken bir bitişidir ve Nonedolaylı olarak döndürülen değerin bir anlamı yoktur ve yakalanması amaçlanmamıştır (yordam benzeri işlev her zaman Noneyine de döner ).


3

İşlevsellik açısından bunların hepsi aynıdır, aralarındaki fark kod okunabilirliği ve stilindedir (dikkate alınması önemlidir)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.