Program Tip

Python에서 증가 및 감소 연산자의 동작

programtip 2020. 9. 29. 18:26
반응형

Python에서 증가 및 감소 연산자의 동작


사전 증가 / 감소 연산자가 변수 (예 :)에 적용될 수 있습니다 ++count. 컴파일되지만 실제로 변수의 값을 변경하지는 않습니다!

파이썬에서 사전 증가 / 감소 연산자 (++ /-)의 동작은 무엇입니까?

Python이 C / C ++에서 볼 수있는 이러한 연산자의 동작과 다른 이유는 무엇입니까?


++운영자가 아닙니다. 두 명의 +연산자입니다. +운영자는이다 신원 아무것도하지 않는다 연산자. (설명 : 단항 연산자 +-단항 연산자는 숫자에서만 작동하지만 가상 ++연산자가 문자열에서 작동 할 것이라고 예상하지 않을 것이라고 가정 합니다.

++count

다음으로 구문 분석

+(+count)

어떤 의미로

count

+=원하는 작업을 수행 하려면 약간 더 긴 연산자 를 사용해야합니다 .

count += 1

일관성과 단순성을 위해 ++--연산자가 제외 되었다고 생각합니다 . 나는 귀도 반 로섬이 결정에 대해 준 정확한 주장을 모르지만 몇 가지 주장을 상상할 수 있습니다.

  • 더 간단한 구문 분석. 기술적으로 파싱 ++count은 모호합니다 +. +,, count(두 개의 단항 +연산자)처럼 쉽게 ++, count(하나의 단항 ++연산자). 중요한 구문 모호성은 아니지만 존재합니다.
  • 더 간단한 언어. ++의 동의어 일뿐입니다 += 1. 그것은 C 컴파일러가 어리 석고 대부분의 컴퓨터가 가지고 a += 1있는 inc명령어 로 최적화하는 방법을 몰랐기 때문에 발명 된 속기 입니다. 컴파일러와 바이트 코드 해석 언어를 최적화하는 오늘날, 프로그래머가 코드를 최적화 할 수 있도록 언어에 연산자를 추가하는 것은 일반적으로 특히 일관되고 읽을 수 있도록 설계된 Python과 같은 언어에서 눈살을 찌푸립니다.
  • 혼란스러운 부작용. ++연산자 를 사용하는 언어에서 흔히 발생하는 한 가지 오류 는 사전 및 사후 증가 / 감소 연산자 간의 차이 (우선 순위 및 반환 값 모두)를 혼합하는 것입니다. Python은 언어 "gotcha"-s를 제거하는 것을 좋아합니다. 우선 순위 문제C에서 사전 / 사후 증가는 엉망에 놀라 울 정도로 쉽게 꽤 털이합니다.

증가 또는 감소를 원할 때 일반적으로 정수에 대해 수행합니다. 이렇게 :

b++

그러나 파이썬에서 정수는 불변 입니다. 그것은 당신이 그들을 바꿀 수 없다는 것입니다. 정수 객체를 여러 이름으로 사용할 수 있기 때문입니다. 이 시도:

>>> b = 5
>>> a = 5
>>> id(a)
162334512
>>> id(b)
162334512
>>> a is b
True

위의 a와 b는 실제로 동일한 객체입니다. a를 증가 시키면 b도 증가합니다. 그것은 당신이 원하는 것이 아닙니다. 따라서 재 할당해야합니다. 이렇게 :

b = b + 1

또는 더 간단합니다.

b += 1

에 재 할당 b됩니다 b+1. 증분 연산자가 아닙니다. 증분하지 않기 b때문에 다시 할당합니다.

간단히 말해서, 파이썬은 여기서 다르게 동작합니다. 왜냐하면 그것은 C가 아니고 기계 코드를 둘러싼 저수준 래퍼가 아니라 증가가 의미가없고 C 에서처럼 필요하지 않은 고수준 동적 언어이기 때문입니다. , 예를 들어 루프가있을 때마다 사용합니다.


다른 답변은 단순한 사람이 +일반적으로 하는 일 (즉, 숫자를 그대로 두는 것)을 보여주는 한 정확하지만 어떤 일이 발생하는지 설명하지 않는 한 불완전합니다.

정확히 말하면 +x평가 됩니다 .x.__pos__()++xx.__pos__().__pos__()

나는 다음과 같이 매우 이상한 클래스 구조를 상상할 수 있습니다. (어린이 여러분, 집에서 이것을하지 마세요!)

class ValueKeeper(object):
    def __init__(self, value): self.value = value
    def __str__(self): return str(self.value)

class A(ValueKeeper):
    def __pos__(self):
        print 'called A.__pos__'
        return B(self.value - 3)

class B(ValueKeeper):
    def __pos__(self):
        print 'called B.__pos__'
        return A(self.value + 19)

x = A(430)
print x, type(x)
print +x, type(+x)
print ++x, type(++x)
print +++x, type(+++x)

파이썬에는 이러한 연산자가 없지만 실제로 필요한 경우 동일한 기능을 가진 함수를 작성할 수 있습니다.

def PreIncrement(name, local={}):
    #Equivalent to ++name
    if name in local:
        local[name]+=1
        return local[name]
    globals()[name]+=1
    return globals()[name]

def PostIncrement(name, local={}):
    #Equivalent to name++
    if name in local:
        local[name]+=1
        return local[name]-1
    globals()[name]+=1
    return globals()[name]-1

용법:

x = 1
y = PreIncrement('x') #y and x are both 2
a = 1
b = PostIncrement('a') #b is 1 and a is 2

함수 내에서 지역 변수를 변경하려면 locals ()를 두 번째 인수로 추가해야합니다. 그렇지 않으면 전역 변경을 시도합니다.

x = 1
def test():
    x = 10
    y = PreIncrement('x') #y will be 2, local x will be still 10 and global x will be changed to 2
    z = PreIncrement('x', locals()) #z will be 11, local x will be 11 and global x will be unaltered
test()

또한 이러한 기능으로 다음을 수행 할 수 있습니다.

x = 1
print(PreIncrement('x'))   #print(x+=1) is illegal!

그러나 제 생각에는 접근 방식을 따르는 것이 훨씬 더 명확합니다.

x = 1
x+=1
print(x)

감소 연산자 :

def PreDecrement(name, local={}):
    #Equivalent to --name
    if name in local:
        local[name]-=1
        return local[name]
    globals()[name]-=1
    return globals()[name]

def PostDecrement(name, local={}):
    #Equivalent to name--
    if name in local:
        local[name]-=1
        return local[name]+1
    globals()[name]-=1
    return globals()[name]+1

나는 자바 스크립트를 파이썬으로 번역하는 모듈에서 이러한 함수를 사용했습니다.


Python에서는 Common Lisp, Scheme 또는 Ruby와 같은 언어와 달리 표현식과 문 사이의 구분이 엄격하게 적용됩니다.

위키 백과

So by introducing such operators, you would break the expression/statement split.

For the same reason you can't write

if x = 0:
  y = 1

as you can in some other languages where such distinction is not preserved.


Yeah, I missed ++ and -- functionality as well. A few million lines of c code engrained that kind of thinking in my old head, and rather than fight it... Here's a class I cobbled up that implements:

pre- and post-increment, pre- and post-decrement, addition,
subtraction, multiplication, division, results assignable
as integer, printable, settable.

Here 'tis:

class counter(object):
    def __init__(self,v=0):
        self.set(v)

    def preinc(self):
        self.v += 1
        return self.v
    def predec(self):
        self.v -= 1
        return self.v

    def postinc(self):
        self.v += 1
        return self.v - 1
    def postdec(self):
        self.v -= 1
        return self.v + 1

    def __add__(self,addend):
        return self.v + addend
    def __sub__(self,subtrahend):
        return self.v - subtrahend
    def __mul__(self,multiplier):
        return self.v * multiplier
    def __div__(self,divisor):
        return self.v / divisor

    def __getitem__(self):
        return self.v

    def __str__(self):
        return str(self.v)

    def set(self,v):
        if type(v) != int:
            v = 0
        self.v = v

You might use it like this:

c = counter()                          # defaults to zero
for listItem in myList:                # imaginary task
     doSomething(c.postinc(),listItem) # passes c, but becomes c+1

...already having c, you could do this...

c.set(11)
while c.predec() > 0:
    print c

....or just...

d = counter(11)
while d.predec() > 0:
    print d

...and for (re-)assignment into integer...

c = counter(100)
d = c + 223 # assignment as integer
c = c + 223 # re-assignment as integer
print type(c),c # <type 'int'> 323

...while this will maintain c as type counter:

c = counter(100)
c.set(c + 223)
print type(c),c # <class '__main__.counter'> 323

EDIT:

And then there's this bit of unexpected (and thoroughly unwanted) behavior,

c = counter(42)
s = '%s: %d' % ('Expecting 42',c) # but getting non-numeric exception
print s

...because inside that tuple, getitem() isn't what used, instead a reference to the object is passed to the formatting function. Sigh. So:

c = counter(42)
s = '%s: %d' % ('Expecting 42',c.v) # and getting 42.
print s

...or, more verbosely, and explicitly what we actually wanted to happen, although counter-indicated in actual form by the verbosity (use c.v instead)...

c = counter(42)
s = '%s: %d' % ('Expecting 42',c.__getitem__()) # and getting 42.
print s

TL;DR

Python does not have unary increment/decrement operators (--/++). Instead, to increment a value, use

a += 1

More detail and gotchas

But be careful here. If you're coming from C, even this is different in python. Python doesn't have "variables" in the sense that C does, instead python uses names and objects, and in python ints are immutable.

so lets say you do

a = 1

What this means in python is: create an object of type int having value 1 and bind the name a to it. The object is an instance of int having value 1, and the name a refers to it. The name a and the object to which it refers are distinct.

Now lets say you do

a += 1

Since ints are immutable, what happens here is as follows:

  1. look up the object that a refers to (it is an int with id 0x559239eeb380)
  2. look up the value of object 0x559239eeb380 (it is 1)
  3. add 1 to that value (1 + 1 = 2)
  4. create a new int object with value 2 (it has object id 0x559239eeb3a0)
  5. rebind the name a to this new object
  6. Now a refers to object 0x559239eeb3a0 and the original object (0x559239eeb380) is no longer refered to by the name a. If there aren't any other names refering to the original object it will be garbage collected later.

Give it a try yourself:

a = 1
print(hex(id(a)))
a += 1
print(hex(id(a)))

참고URL : https://stackoverflow.com/questions/1485841/behaviour-of-increment-and-decrement-operators-in-python

반응형