C # null 병합 연산자와 동등한 Python이 있습니까?


301

C #에는 할당하는 동안 쉬운 (짧은) null 검사를 허용 하는 null 병합 연산자 (로 작성 ??)가 있습니다.

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

파이썬과 동등한 것이 있습니까?

나는 내가 할 수 있다는 것을 안다.

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

그러나 더 짧은 방법이 s있습니까 ( 반복 할 필요가없는 곳 )?


14
??연산자는 다음과 같이 제안된다 PEP (505) .
200_success

답변:


421
other = s or "some default value"

or운영자가 어떻게 작동 하는지 명확히해야 합니다. 부울 연산자이므로 부울 컨텍스트에서 작동합니다. 값이 부울이 아닌 경우 연산자의 목적으로 부울로 변환됩니다.

점을 유의 or운영자는 반환하지 않습니다 TrueFalse. 대신, 첫 번째 피연산자가 true로 평가되면 첫 번째 피연산자를 리턴하고 첫 번째 피연산자가 false로 평가되면 두 번째 피연산자를 리턴합니다.

이 경우 표현식 x or y은 부울로 변환 될 때 true이거나 true로 평가 x되면 리턴 합니다 True. 그렇지 않으면를 반환합니다 y. 대부분의 경우 C♯의 null-coalescing 연산자와 같은 목적으로 사용되지만 다음을 명심하십시오.

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

당신이 당신의 변수를 사용하는 경우 s중 하나의 클래스의 인스턴스에 대한 참조 또는 보류 뭔가 None(긴 클래스 멤버 정의하지 않는 한 __nonzero__()__len__()), 널 병합 연산자와 같은 의미를 사용하는 것이 안전합니다.

사실, 파이썬의 부작용을 갖는 것이 유용 할 수도 있습니다. 어떤 값이 false로 평가되는지 알고 있으므로이를 사용하여 None구체적으로 (예 : 오류 개체) 사용하지 않고 기본값을 트리거 할 수 있습니다 .

일부 언어에서는이 동작을 Elvis 연산자 라고합니다 .


3
이것은 동일하게 작동합니까? 내 말 s은, 유효한 가치이지만 진실하지 않으면 깨질 것인가? (나는 파이썬을 모른다. 그래서 'truthy'의 개념이 적용되는지 확실하지 않다.)
cHao

9
None상수 외에도 숫자 0, 및 빈 컨테이너 (문자열 포함)는 거짓으로 간주됩니다 False. 다른 모든 것들은 사실로 간주됩니다. 나는 여기에서 가장 큰 위험은 당신이 사실이지만 문자열이 아닌 값을 얻을 것이지만 일부 프로그램에서는 문제가되지 않을 것이라고 말할 것입니다.
kindall

25
이 사용하는 다른 것은 s는 아무도없는 경우 기본값을 얻을 것이다 또는 False 원하는 무엇하지 않을 수 있습니다.
pafcu

6
이로 인해 많은 모호한 버그가 있습니다. 예를 들어 Python 3.5 이전 datetime.time(0)에는 허위였습니다!
Antti Haapala

19
이것은 나쁘다. 함정에 대한 통지를 추가하는 것이 좋습니다. 그리고 사용 하지 않는 것이 좋습니다 .
Mateen Ulhaq

61

엄밀히 말하면,

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

그렇지 않으면 s = False될 것입니다 "default value"의도 된 것이 아닐 수있다.

더 짧게 만들려면 다음을 시도하십시오.

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

다음은 아닌 첫 번째 인수를 반환하는 함수입니다 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()첫 번째 인수가 아닌 경우에도 모든 인수를 불필요하게 반복 할 수 있으므로이 None버전을 사용할 수도 있습니다.

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)한 줄에서 마지막 예제와 동일합니다.
glglgl

2
나는 사람들이 sytnax 등을 설명한다면 설명하고 싶지만, 병합은 임의의 인수 목록을 취하므로 이것이 정말로 최고의 대답이어야합니다.
Eric Twilegar

2
glglgl이 가장 좋습니다. 큰 테스트 배열에서 timeit을 사용했으며 축소 구현이 용납 될 수 없을 정도로 느리고 버전이 여러 줄인 경우가 가장 빠르며 다음 구현은 매우 약간 뒤떨어져 있습니다. 다음 버전은 단순성과 간결성을 고려할 때 전반적으로 가장 좋습니다.
clay

3
@glglgl에는 흥미로운 스 니펫이 있습니다. 불행히도 파이썬에는 이름 별 패스가 없기 때문에 이와 같은 통합은 단락이 아닙니다. 코드가 실행되기 전에 모든 인수가 평가됩니다.
user1338062

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

5

나는 이것이 대답한다는 것을 알고 있지만 객체를 다룰 때 다른 옵션이 있습니다.

다음과 같은 물체가있는 경우 :

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

당신이 사용할 수있는:

obj.get(property_name, value_if_null)

처럼:

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

{}"name"이 없으면 기본값으로 추가 하여 빈 오브젝트가 리턴되고 다음 get으로 전달됩니다. 이것은 C #의 null 안전 탐색과 유사 obj?.name?.first합니다.


모든 개체가 .get이 개체 만-처럼 DICT 작동하는 것은,
timdiels

답변을 편집하기 위해 제출하고 getattr()있습니다.
dgw

geton dict에서는 값이 None이면 기본 매개 변수를 사용하지 않지만 키가 dict에 없기 때문에 값이 존재하지 않으면 기본 매개 변수를 사용합니다. {'a': None}.get('a', 'I do not want None')여전히 None결과를 제공합니다 .
Patrick Mevzek

3

"또는"의 행동에 대한 Juliano의 답변 외에도 "빠른"

>>> 1 or 5/0
1

때로는 때로는 다음과 같은 것들에 유용한 지름길이 될 수도 있습니다.

object = getCachedVersion() or getFromDB()

17
당신이 찾고있는 용어는 "단락"입니다.
jpmc26

1

또한 단일 값에 대한 @Bothwells 응답 (내가 선호하는)에 추가하여 함수 반환 값의 null 확인을 위해 새로운 walrus-operator를 사용할 수 있습니다 (python3.8부터).

def test():
    return

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

따라서, test함수 (같이 두 번 계산 될 필요가 없다 a = 2 if test() is None else test())


1

다음과 같은 둘 이상의 null 병합 작업을 중첩해야하는 경우 :

model?.data()?.first()

이것은 쉽게 해결되는 문제가 아닙니다 or. .get()사전 유형이나 이와 유사한 것을 요구하거나 (어쨌든 중첩 될 수없는) 또는 해결할 수 없습니다.getattr() NoneType에 속성이없는 경우 예외가 발생 .

언어에 null 병합을 추가하는 것을 고려한 관련 pip는 PEP 505 이며 문서와 관련된 토론은 python-ideas 스레드에 있습니다.


0

@Hugh Bothwell, @mortehu 및 @glglgl의 답변과 관련하여.

테스트를위한 설정 데이터 셋

import random

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

구현 정의

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)

테스트 기능 만들기

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

Python 2.7을 사용하는 Mac i7 @ 2.7Ghz의 결과

>>> %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

분명히 not_none 함수는 OP의 질문에 올바르게 대답하고 "거짓"문제를 처리합니다. 또한 가장 빠르고 쉽게 읽을 수 있습니다. 여러 곳에서 논리를 적용하는 경우 가장 좋은 방법입니다.

iterable에서 null이 아닌 첫 번째 값을 찾는 데 문제가 있다면 @mortehu의 응답이 좋습니다. 그러나 OP와 다른 문제에 대한 솔루션 이지만 부분적으로 처리 할 수 ​​있습니다. iterable 및 기본값을 사용할 수 없습니다. 마지막 인수는 반환 된 기본값이지만,이 경우 반복 가능한 값을 전달하지 않으며 마지막 인수가 기본값 인 기본값이라는 것도 명확하지 않습니다.

그런 다음 아래에서 수행 할 수 있지만 여전히 not_null단일 값 사용 사례에 사용합니다.

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

0

변수가 정의되지 않았을 때이 문제에 대한 실행 가능한 솔루션을 찾고있는 저와 같은 사람들에게는 가장 가까운 것은 다음과 같습니다.

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')

전역을 체크인 할 때는 문자열이 필요하지만 나중에 값을 확인할 때는 실제 변수가 사용됩니다.

변수 존재에 대한 추가 정보 : 변수가 존재 하는지 어떻게 확인합니까?


1
(variablename or False) == True과 동일variablename == True
마이크

-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

사전에서 이름을 찾을 수 없으면 default_value를 반환하고 이름이 있으면 1을 사용하여 기존 값을 추가합니다.

이것이 도움이되기를 바랍니다.


1
안녕하세요, Stack Overflow에 오신 것을 환영합니다. 기존 답변으로 아직 다루지 않은 어떤 새로운 정보가 답변에 추가됩니까? 예를 들어
@Craig

-6

아래의 두 가지 기능은 많은 변수 테스트 사례를 처리 할 때 매우 유용한 것으로 나타났습니다.

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
이런 종류의 것들은 다른 언어에서 가져온 약간의 다른 용어 (예 : "null"과 "nz"는 파이썬의 맥락에서 아무것도 의미하지 않습니다)와 변형 (엄격 또는 엄격하지 않음)을 추가합니다. 이것은 혼란을 추가합니다. 명시 적 "없음"검사는 사용해야합니다. 또한 함수 호출을 사용할 때 운영자가 수행 할 수있는 바로 가기 시맨틱의 이점을 얻지 못합니다.
spookylukey
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.