developer tip

조건에서 할당 할 수 있습니까?

optionbox 2020. 10. 28. 08:01
반응형

조건에서 할당 할 수 있습니까?


조건에 할당 할 수 있습니까?

예를 들어.

if (a=some_func()):
    # Use a

시도해 보지 않겠습니까?

>>> def some_func():
...   return 2
... 
>>> a = 2
>>> if (a = some_func()):
  File "<stdin>", line 1
    if (a = some_func()):
          ^
SyntaxError: invalid syntax
>>> 

그래서 안돼.


아니요, BDFL은 그 기능을 좋아하지 않았습니다.

내가 앉은 자리에서 "Benevolent Dictator For Life"인 Guido van Rossum은 Python을 가능한 한 단순하게 유지하기 위해 열심히 싸웠습니다. 우리는 그가 내린 결정 중 일부에 대해 고민 할 수 있습니다. 하지만 파이썬을 설계하는위원회가 없었고, 대신 디자이너의 감성을 통해 필터링하는 장점에 기반을 둔 신뢰할 수있는 "자문위원회" 가 하나의 멋진 언어 인 IMHO를 만들어 냈습니다.


업데이트-원래 답변이 하단 근처에 있습니다.

Python 3.8은 PEP572 를 가져올 것입니다 .

Abstract
이것은 NAME : = expr 표기법을 사용하여 표현식 내의 변수에 할당하는 방법을 생성하기위한 제안입니다. 새 예외 인 TargetScopeError가 추가되고 평가 순서에 한 가지 변경 사항이 있습니다.

https://lwn.net/Articles/757713/

"PEP 572 혼란"은 BDFL (Benevolent dictator for life) Guido van Rossum이 이끄는 2018 Python Language Summit 세션의 주제였습니다. PEP 572는 언어에 할당 표현식 (또는 "인라인 할당")을 추가하려고하지만, python-ideas에 대한 여러 차례의 라운드 후에도 python-dev 메일 링 목록의 여러 방대한 스레드에 대한 오랜 논의를 보았습니다. 이러한 스레드는 종종 논쟁의 여지가 많았으며 많은 사람들이 아마 방금 조정했을 정도로 방대했습니다. 정상 회담에서 Van Rossum은 기능 제안에 대한 개요를 제공했으며이를 수용하는 경향이 있지만 향후 이러한 종류의 스레드 폭발을 방지하는 방법에 대해서도 논의하고 싶었습니다.

https://www.python.org/dev/peps/pep-0572/#examples-from-the-python-standard-library

Python 표준 라이브러리의 예

site.py env_base는이 행에서만 사용되며 if에 할당을 지정하여 블록의 "헤더"로 이동합니다.

흐름:

env_base = os.environ.get("PYTHONUSERBASE", None)
if env_base:
    return env_base

향상:

if env_base := os.environ.get("PYTHONUSERBASE", None):
    return env_base
_pydecimal.py

중첩 된 경우를 피하고 하나의 들여 쓰기 수준을 제거합니다.

흐름:

if self._is_special:
    ans = self._check_nans(context=context)
    if ans:
        return ans

향상:

if self._is_special and (ans := self._check_nans(context=context)):
    return ans

copy.py 코드는 더 규칙적으로 보이고 다중 중첩 된 경우를 피합니다. (이 예의 출처는 부록 A를 참조하십시오.)

흐름:

reductor = dispatch_table.get(cls)
if reductor:
    rv = reductor(x)
else:
    reductor = getattr(x, "__reduce_ex__", None)
    if reductor:
        rv = reductor(4)
    else:
        reductor = getattr(x, "__reduce__", None)
        if reductor:
            rv = reductor()
        else:
            raise Error(
                "un(deep)copyable object of type %s" % cls)

향상:

if reductor := dispatch_table.get(cls):
    rv = reductor(x)
elif reductor := getattr(x, "__reduce_ex__", None):
    rv = reductor(4)
elif reductor := getattr(x, "__reduce__", None):
    rv = reductor()
else:
    raise Error("un(deep)copyable object of type %s" % cls)
datetime.py

tz는 s + = tz에만 사용되며 if 내부로 할당을 이동하면 범위를 표시하는 데 도움이됩니다.

흐름:

s = _format_time(self._hour, self._minute,
                 self._second, self._microsecond,
                 timespec)
tz = self._tzstr()
if tz:
    s += tz
return s

향상:

s = _format_time(self._hour, self._minute,
                 self._second, self._microsecond,
                 timespec)
if tz := self._tzstr():
    s += tz
return s

sysconfig.py while 조건에서 fp.readline ()을 호출하고 if 라인에서 .match ()를 호출하면 코드가

이해하기 어렵게 만듭니다.

흐름:

while True:
    line = fp.readline()
    if not line:
        break
    m = define_rx.match(line)
    if m:
        n, v = m.group(1, 2)
        try:
            v = int(v)
        except ValueError:
            pass
        vars[n] = v
    else:
        m = undef_rx.match(line)
        if m:
            vars[m.group(1)] = 0

향상:

while line := fp.readline():
    if m := define_rx.match(line):
        n, v = m.group(1, 2)
        try:
            v = int(v)
        except ValueError:
            pass
        vars[n] = v
    elif m := undef_rx.match(line):
        vars[m.group(1)] = 0

목록 이해 단순화 목록 이해는 조건을 캡처하여 효율적으로 매핑하고 필터링 할 수 있습니다.

results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]

마찬가지로 하위 표현식은 처음 사용할 때 이름을 지정하여 기본 표현식 내에서 재사용 할 수 있습니다.

stuff = [[y := f(x), x/y] for x in range(5)]

두 경우 모두 변수 y는 포함 범위 (즉, 결과 또는 물건과 동일한 수준)에 바인딩됩니다.

조건 값 캡처 할당 표현식은 if 또는 while 문의 헤더에서 좋은 효과를내는 데 사용할 수 있습니다.

# Loop-and-a-half
while (command := input("> ")) != "quit":
    print("You entered:", command)

# Capturing regular expression match objects
# See, for instance, Lib/pydoc.py, which uses a multiline spelling
# of this effect
if match := re.search(pat, text):
    print("Found:", match.group(0))
# The same syntax chains nicely into 'elif' statements, unlike the
# equivalent using assignment statements.
elif match := re.search(otherpat, text):
    print("Alternate found:", match.group(0))
elif match := re.search(third, text):
    print("Fallback found:", match.group(0))

# Reading socket data until an empty string is returned
while data := sock.recv(8192):
    print("Received data:", data)

특히 while 루프를 사용하면 무한 루프, 할당 및 조건이 필요하지 않습니다. 또한 단순히 함수 호출을 조건으로 사용하는 루프와이를 조건으로 사용하지만 실제 값을 사용하는 루프 사이에 부드러운 병렬을 생성합니다.

Fork 저수준 UNIX 세계의 예 :

if pid := os.fork():
    # Parent code
else:
    # Child code

원래 답변

http://docs.python.org/tutorial/datastructures.html

Note that in Python, unlike C, assignment cannot occur inside expressions. C programmers may grumble about this, but it avoids a common class of problems encountered in C programs: typing = in an expression when == was intended.

also see:

http://effbot.org/pyfaq/why-can-t-i-use-an-assignment-in-an-expression.htm


Not directly, per this old recipe of mine -- but as the recipe says it's easy to build the semantic equivalent, e.g. if you need to transliterate directly from a C-coded reference algorithm (before refactoring to more-idiomatic Python, of course;-). I.e.:

class DataHolder(object):
    def __init__(self, value=None): self.value = value
    def set(self, value): self.value = value; return value
    def get(self): return self.value

data = DataHolder()

while data.set(somefunc()):
  a = data.get()
  # use a

BTW, a very idiomatic Pythonic form for your specific case, if you know exactly what falsish value somefunc may return when it does return a falsish value (e.g. 0), is

for a in iter(somefunc, 0):
  # use a

so in this specific case the refactoring would be pretty easy;-).

If the return could be any kind of falsish value (0, None, '', ...), one possibility is:

import itertools

for a in itertools.takewhile(lambda x: x, iter(somefunc, object())):
    # use a

but you might prefer a simple custom generator:

def getwhile(func, *a, **k):
    while True:
      x = func(*a, **k)
      if not x: break
      yield x

for a in getwhile(somefunc):
    # use a

Yes, but only from Python 3.8 and onwards.

PEP 572 proposes Assignment Expressions and has already been accepted.

Quoting the Syntax and semantics part of the PEP:

# Handle a matched regex
if (match := pattern.search(data)) is not None:
    # Do something with match

# A loop that can't be trivially rewritten using 2-arg iter()
while chunk := file.read(8192):
   process(chunk)

# Reuse a value that's expensive to compute
[y := f(x), y**2, y**3]

# Share a subexpression between a comprehension filter clause and its output
filtered_data = [y for x in data if (y := f(x)) is not None]

In your specific case, you will be able to write

if a := some_func():
    # Use a

No. Assignment in Python is a statement, not an expression.


Thanks to Python 3.8 new feature it will be possible to do such a thing from this version, although not using = but Ada-like assignment operator :=. Example from the docs:

# Handle a matched regex
if (match := pattern.search(data)) is not None:
    # Do something with match

You can define a function to do the assigning for you:

def assign(name, value):
    import inspect
    frame = inspect.currentframe()
    try:
        locals_ = frame.f_back.f_locals
    finally:
        del frame 
    locals_[name] = value
    return value

if assign('test', 0):
    print("first", test)
elif assign('xyz', 123):
    print("second", xyz)

One of the reasons why assignments are illegal in conditions is that it's easier to make a mistake and assign True or False:

some_variable = 5

# This does not work
# if True = some_variable:
#   do_something()

# This only works in Python 2.x
True = some_variable

print True  # returns 5

In Python 3 True and False are keywords, so no risk anymore.

참고URL : https://stackoverflow.com/questions/2603956/can-we-have-assignment-in-a-condition

반응형