C # null birleştirme operatörünün bir Python eşdeğeri var mı?


302

C # 'da atama sırasında kolay (kısa) null kontrole izin veren null birleştirme operatörü (olarak yazılır ??) vardır:

string s = null;
var other = s ?? "some default value";

Python eşdeğeri var mı?

Yapabileceğimi biliyorum:

s = None
other = s if s else "some default value"

Ama daha kısa bir yolu var mı (tekrar etmeme gerek yok s)?


14
??Operatör olarak önerilmiştir PEP 505 .
200_success

Yanıtlar:


422
other = s or "some default value"

Tamam, oroperatörün nasıl çalıştığı netleştirilmelidir . Bir boolean operatörüdür, bu nedenle boolean bağlamında çalışır. Değerler boole değilse, operatörün amaçları için boole'ye dönüştürülür.

Not oroperatörü yalnızca dönmez Trueya False. Bunun yerine, ilk işlenen true olarak değerlendirilirse ilk işlenen döndürür ve ilk işlenen false olarak değerlendirilirse ikinci işlenen döndürülür.

Bu durumda, ifade x or ydöner xEğer öyleyse Truetrue veya değerlendirir mantıksala dönüştürüldüğünde. Aksi takdirde geri döner y. Çoğu durumda, bu C♯'nin boş birleştirici operatörünün aynı amacına hizmet edecektir, ancak unutmayın:

42    or "something"    # returns 42
0     or "something"    # returns "something"
None  or "something"    # returns "something"
False or "something"    # returns "something"
""    or "something"    # returns "something"

Değişkeninizi sbir sınıf örneğine başvuru olan veya None(sınıfınız üyeleri tanımlamadığı __nonzero__()ve__len__() ), boş-kaynaştırma operatör aynı anlamsallıktadır kullanmak güvenlidir.

Aslında, Python'un bu yan etkisine sahip olmak bile yararlı olabilir. Hangi değerlerin yanlış olarak değerlendirildiğini bildiğiniz için, Noneözel olarak (örneğin bir hata nesnesi) kullanmadan varsayılan değeri tetiklemek için bunu kullanabilirsiniz .

Bazı dillerde bu davranışa Elvis operatörü denir .


3
Bu aynı olacak mı? Demek istediğim, sgeçerli bir değer olsa da doğru değil mi? (Python'u tanımıyorum, bu yüzden 'doğruluk' kavramının geçerli olup olmadığından emin değilim.)
cHao

9
Sabit sayıya ek olarak 0 sayısı Noneve boş kaplar (dizeler dahil) yanlış kabul edilir False. Diğer her şey doğru kabul edilir. Buradaki ana tehlikenin gerçek ama dize olmayan bir değer alacağınız olduğunu söyleyebilirim, ancak bu bazı programlarda sorun olmayacak.
tür

25
S diğerinin kullanılması , s None veya False ise varsayılan değeri alır ve bu istenen değildir.
pafcu

6
Bunun da neden olduğu pek çok karanlık hata var. Örneğin Python 3.5 öncesinde, datetime.time(0)aynı zamanda sahteli!
Antti Haapala

19
Bu kötü. Tuzakları hakkında bir bildirim eklemenizi tavsiye ederim. Ve tavsiye değil kullanmak için.
Mateen Ulhaq

61

kesinlikle,

other = s if s is not None else "default value"

Aksi takdirde, s = Falseolacak"default value" ne amaçlı olduğunu olmayabilir, hangi.

Bunu kısaltmak istiyorsanız, şunu deneyin:

def notNone(s,d):
    if s is None:
        return d
    else:
        return s

other = notNone(s, "default value")

1
Consider x()?.y()?.z()
nurettin

40

İlk argümanı döndürmeyecek bir fonksiyon None:

def coalesce(*arg):
  return reduce(lambda x, y: x if x is not None else y, arg)

# Prints "banana"
print coalesce(None, "banana", "phone", None)

reduce()ilk argüman olmasa bile tüm argümanları gereksiz yere yineleyebilir None, böylece bu sürümü de kullanabilirsiniz:

def coalesce(*arg):
  for el in arg:
    if el is not None:
      return el
  return None

23
def coalesce(*arg): return next((a for a in arg if a is not None), None)bir satırdaki son örneğinizle aynı şeyi yapar.
glglgl

2
İnsanların sytnax vb.
Eric Twilegar

2
glglgl en iyi cevaba sahiptir. Büyük bir test dizisinde timeit kullandım ve azaltma uygulaması kabul edilemeyecek kadar yavaş, sürüm için çok satırlı / hızlı ise ve bir sonraki uygulama çok az geridedir. Bir sonraki versiyon, sadelik ve kısalık göz önüne alındığında en iyi genel versiyon.
kil

3
@glglgl ilginç bir snippet'e sahip. Maalesef Python'un adında bir paya sahip olmadığı için böyle birleşme kısa devre yapmaz; kod çalıştırılmadan önce tüm argümanlar değerlendirilir.
user1338062

Consider x()?.y()?.z()
nurettin

5

Bunun cevaplandığını anlıyorum, ancak nesnelerle uğraşırken başka bir seçenek daha var.

Olabilecek bir nesneniz varsa:

{
   name: {
      first: "John",
      last: "Doe"
   }
}

Kullanabilirsiniz:

obj.get(property_name, value_if_null)

Sevmek:

obj.get("name", {}).get("first", "Name is missing") 

{}Varsayılan değer olarak eklenerek , "ad" eksikse, boş bir nesne döndürülür ve bir sonraki get'e iletilir. Bu, C # 'daki null-safe-navigation ile benzerdir obj?.name?.first.


Tüm nesneler değil .get, bu sadece
dikte

Ben de kapsayacak cevap düzenlemesi yapıyorum getattr().
dgw

geton dict, değer None ise varsayılan parametreyi kullanmaz ancak anahtar, dict içinde olmadığı için değer yoksa varsayılan parametreyi kullanır. sonuç olarak {'a': None}.get('a', 'I do not want None')size verecek None.
Patrick Mevzek

3

Juliano'nun "veya" davranışı hakkındaki cevabına ek olarak: "hızlı"

>>> 1 or 5/0
1

Bu yüzden bazen bu gibi şeyler için yararlı bir kısayol olabilir

object = getCachedVersion() or getFromDB()

17
Aradığınız terim "kısa devreler" dir.
jpmc26

1

Ayrıca, tekli değerler için @Bothwells cevabına (ki ben tercih ederim), işlev dönüş değerlerinin değerlendirmesini geçersiz kılmak için, yeni walrus-operatörünü (python3.8'den beri) kullanabilirsiniz:

def test():
    return

a = 2 if (x:= test()) is None else x

Bu nedenle, testişlevin iki kez değerlendirilmesi gerekmez (olduğu gibi a = 2 if test() is None else test())


1

Birden fazla boş birleştirme işlemini iç içe yerleştirmeniz gerektiğinde, örneğin:

model?.data()?.first()

Bu kolayca çözülebilecek bir sorun değildir or. Ayrıca .get()bir sözlük türü veya benzeri (ve yine de iç içe olamaz) gerektiren çözülemez veyagetattr() NoneType özniteliğe sahip olmadığında bir istisna atacak olan çözülemez.

Dile boş birleştirme eklemeyi düşünen ilgili pip PEP 505'tir ve belgeyle ilgili tartışma python-ideas dizisinde bulunmaktadır.


0

@Hugh Bothwell, @mortehu ve @glglgl tarafından verilen yanıtlar.

Test için Veri Kümesini Ayarla

import random

dataset = [random.randint(0,15) if random.random() > .6 else None for i in range(1000)]

Uygulamaları tanımlayın

def not_none(x, y=None):
    if x is None:
        return y
    return x

def coalesce1(*arg):
  return reduce(lambda x, y: x if x is not None else y, arg)

def coalesce2(*args):
    return next((i for i in args if i is not None), None)

Test fonksiyonu yap

def test_func(dataset, func):
    default = 1
    for i in dataset:
        func(i, default)

Python 2.7 kullanarak mac i7 @ 2.7Ghz sonuçları

>>> %timeit test_func(dataset, not_none)
1000 loops, best of 3: 224 µs per loop

>>> %timeit test_func(dataset, coalesce1)
1000 loops, best of 3: 471 µs per loop

>>> %timeit test_func(dataset, coalesce2)
1000 loops, best of 3: 782 µs per loop

Açıkçası not_noneİşlev OP'nin sorusuna doğru cevap verir ve "yanlış" sorununu çözer. Ayrıca okunması en hızlı ve en kolay olanıdır. Mantığı birçok yerde uyguluyorsanız, gitmek için en iyi yoldur.

Eğer bir yinelemesiz 1. null olmayan değeri bulmak istediğiniz bir sorun varsa, o zaman @ mortehu yanıt yoludur. Ancak bu durumu kısmen ele alabilse de, OP'den farklı bir soruna bir çözümdür . Yinelenebilir VE varsayılan bir değer alamaz. Son argüman döndürülen varsayılan değer olacaktır, ancak o zaman bu durumda bir yinelemeyi geçemezsiniz ve son argümanın varsayılan bir değer olduğu açık değildir.

Daha sonra aşağı yapabilirsin, ama yine not_nullde tek değer kullanım durumu için kullanırım.

def coalesce(*args, **kwargs):
    default = kwargs.get('default')
    return next((a for a in arg if a is not None), default)

0

Benim gibi burada bu soruna uygulanabilir bir çözüm arayan tökezledi, değişken tanımsız olabilir, ben var en yakın:

if 'variablename' in globals() and ((variablename or False) == True):
  print('variable exists and it\'s true')
else:
  print('variable doesn\'t exist, or it\'s false')

Globalleri kontrol ederken bir dizeye ihtiyaç duyulduğunu, ancak daha sonra değeri kontrol ederken gerçek değişkenin kullanıldığını unutmayın.

Değişken varlığı hakkında daha fazla bilgi: Bir değişkenin olup olmadığını nasıl kontrol edebilirim?


1
(variablename or False) == Trueaynıdırvariablename == True
mic

-2
Python has a get function that its very useful to return a value of an existent key, if the key exist;
if not it will return a default value.

def main():
    names = ['Jack','Maria','Betsy','James','Jack']
    names_repeated = dict()
    default_value = 0

    for find_name in names:
        names_repeated[find_name] = names_repeated.get(find_name, default_value) + 1

adı sözlük içinde bulamazsanız, default_value değerini döndürür, ad varsa, 1 ile varolan herhangi bir değeri ekler.

umarım bu yardımcı olabilir


1
Merhaba, Stack Overflow'a hoş geldiniz. Cevabınız, halihazırda mevcut cevaplar tarafından kapsanmayan hangi yeni bilgileri ekliyor? Örneğin @ Craig'in cevabı
Gricey

-6

Aşağıdaki iki fonksiyon, birçok değişken test senaryosuyla uğraşırken çok yararlı olduğunu bulduk.

def nz(value, none_value, strict=True):
    ''' This function is named after an old VBA function. It returns a default
        value if the passed in value is None. If strict is False it will
        treat an empty string as None as well.

        example:
        x = None
        nz(x,"hello")
        --> "hello"
        nz(x,"")
        --> ""
        y = ""   
        nz(y,"hello")
        --> ""
        nz(y,"hello", False)
        --> "hello" '''

    if value is None and strict:
        return_val = none_value
    elif strict and value is not None:
        return_val = value
    elif not strict and not is_not_null(value):
        return_val = none_value
    else:
        return_val = value
    return return_val 

def is_not_null(value):
    ''' test for None and empty string '''
    return value is not None and len(str(value)) > 0

5
Bu tür şeyler, diğer dillerden içe aktarılan, farklı türlerden (katı veya katı olmayan!) Bir miktar farklı terminoloji (örneğin, "null" ve "nz", ikisi de Python bağlamında bir şey anlamına gelmez) ekler. Bu sadece karışıklık yaratır. Açık "is None" kontrolleri kullanmanız gerekir. Ayrıca, bir işlev çağrısı kullandığınızda operatörlerin yapabileceği herhangi bir kısa semantikten yararlanamazsınız.
spookylukey
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.