2009-07-16 39 views
14

Có cách nào trong python để tăng đối tượng int tại chỗ, int dường như không thực hiện __iadd__ nên + = 1 thực sự trả về một đối tượng mớităng int đối tượng

>>> n=1 
>>> id(n) 
9788024 
>>> n+=1 
>>> id(n) 
9788012 

Những gì tôi muốn là n duy trì chỉ vào cùng một đối tượng.

Mục đích: Tôi có lớp có nguồn gốc từ int và tôi muốn thực hiện loại C '++ n' nhà điều hành cho lớp đó

Kết luận: ok như int là không thay đổi không có cách nào, có vẻ như tôi sẽ phải viết một lớp học của riêng tôi như sau:

class Int(object): 
    def __init__(self, value): 
     self._decr = False 
     self.value = value 

    def __neg__(self): 
     if self._decr: 
      self.value -= 1 
     self._decr = not self._decr 
     return self 

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

    def __cmp__(self, n): 
     return cmp(self.value, n) 

    def __nonzero__(self): 
     return self.value 

n = Int(10) 
while --n: 
    print n 
+0

Tại sao bạn muốn thực hiện một nhà điều hành tiền tố cho nó? Bạn sẽ thêm một bộ tiền xử lý tùy chỉnh để chuyển đổi ++ n thành một cuộc gọi phương thức? – Ryan

+1

hmm Tôi chỉ muốn cho bạn bè thấy python có thể làm trong khi --n: print n;) –

+0

xem điều này cho một cách tốt đẹp nếu hơi phức tạp để bọc ints của bạn trong một lớp ẩn danh (có thể thay đổi) sẽ hoạt động như 'tham khảo': http://stackoverflow.com/a/1123054/409638 tức là ref = type ('',(), {'n': 1}) – robert

Trả lời

12

ints là không thay đổi, do đó bạn sẽ phải xây dựng lớp học của riêng bạn với tất cả các phương pháp của int nếu bạn muốn có một "int có thể thay đổi"

+5

Các int trong lớp đó sẽ vẫn không thay đổi được. –

+1

Nó không có sự khác biệt nếu int của lớp không thay đổi, giá trị của thuộc tính là biến, vì vậy bạn có thể định nghĩa một lớp 'MutableInt' đang hoạt động, không phải là bạn muốn. –

+0

Tôi đã làm điều này: https://github.com/markrages/python_mutable_number – markrages

3

Có lẽ sẽ dễ dàng hơn khi tạo một lớp thực hiện các phương thức int và kết thúc một số nguyên bên trong.

+1

Không chỉ dễ dàng hơn, nhưng có thể là cách duy nhất là int không thể thay đổi được – Arkady

0

Vâng, câu trả lời ngắn gọn là, ints là không thay đổi.

3

Nếu bạn hoàn toàn phải làm cho mã đó hoạt động, đây là một phương pháp bẩn, trong đó một phương pháp thể hiện di chuyển lên một khung và ghi đè mục nhập của người dân địa phương của riêng nó. Sẽ không khuyên bạn nên. (như, thực sự là không. Tôi thậm chí còn không biết nó làm gì. Điều gì sẽ xảy ra với trường hợp cũ? Tôi không biết đủ về các khung hình ...). Thực sự, tôi chỉ đăng bài này bởi vì mọi người đều nói rằng điều đó là không thể, khi thực tế nó chỉ là hình thức vô lý. ;-)

import sys 
class FakeInt(int): 
    def __init__(self, *arg, **kwarg): 
     self._decr = False 
     int.__init__(self, *arg, **kwarg) 
    def __neg__(self): 
     if self._decr: 

      upLocals = sys._getframe(1).f_locals 
      keys, values = zip(*upLocals.items()) 
      i = list(values).index(self) 

      result = FakeInt(self-1) 
      upLocals[keys[i]]=result 

      return result 
     self._decr = not self._decr 
     return self 

A = FakeInt(10) 
while --A: 
    print A, 

kết quả đầu ra:

9 8 7 6 5 4 3 2 1 
+0

trên một lưu ý không liên quan, không ai biết nếu nó có thể tìm thấy chỉ mục của một mục trong một bộ mà không chuyển đổi nó vào một danh sách đầu tiên? i = list (giá trị) .index (self) có vẻ như là một vòng xoay. – Markus

+2

+1 thú vị, nhưng có, tôi sẽ sợ sử dụng –

+0

@Markus a = (1,2,3,4,5); a.index (3) kết quả trong 2. Ít nhất này là với python 3 –

2

Bạn có thể đặt một đối tượng bất biến bên trong một container có thể thay đổi; danh sách là dễ nhất.

in Mã này 0, chứng minh vấn đề:

a = 0  # `a` points to a new int (a `0`) 
b = a  # `b` points to the same thing as `a` (the `0`) 
b = 1  # `b` points to a new int (a `1`) 
print(a) # `a` still points to the same thing (the `0`) 

Nếu bạn đặt int trong một danh sách, nhưng nếu không sử dụng cùng một mã như trước đây, bạn có thể có được hiệu quả của việc có một int có thể thay đổi (mặc dù đó là danh sách đang bị đột biến thực sự):

a = [0]  # `a` points to a new `0` inside a new list 
b = a   # `b` points to the same thing as `a` (the list) 
b[0] = 1  # the list that `a` and `b` point to is mutated 
print(a[0]) # `a[0]` points to the same object as `b[0]` (the `1`) 

Trong thực tế, bạn nên cấu trúc dữ liệu của mình để 'lừa' ở trên là thừa. Các ví dụ không nên được sử dụng trực tiếp, nhưng sẽ giúp bạn tìm ra những việc cần làm.

4

Bạn có thể dùng ctypes làm số nguyên có thể thay đổi. Việc chọn đúng ctype sẽ rất quan trọng, vì chúng giới hạn kích thước của số nguyên mà chúng có thể mang theo.

>>> from ctypes import c_int64 
>>> num = c_int64(0) 
>>> id(num) 
4447709232 
>>> def increment(number): 
...  number.value += 1 
... 
>>> increment(num) 
>>> increment(num) 
>>> increment(num) 
>>> num.value 
3 
>>> id(num) 
4447709232 
>>> 

Thông tin thêm: https://docs.python.org/2/library/ctypes.html#fundamental-data-types

+0

Đối với bản ghi, điều này là chậm hơn so với incrementing một số nguyên bình thường. – Zaz

+0

Nó có lẽ là một ý tưởng tồi vì một vài lý do nhưng dù sao đi nữa, bây giờ tôi biết một điều standart để nhập 'như mutable_int'. – Daerdemandt

0

Tôi đã có một vấn đề tương tự ngày hôm nay và đã đưa ra một lớp được gọi là IterInt cho phép bạn tăng hoặc giảm tại chỗ sử dụng "+" và "-" trang trí.

Cách sử dụng:

x = IterInt() 

print x 
# result: 0 

print +x 
# result: 1 

print +x 
# result: 2 

print +x 
# result: 3 

print -x 
# result: 2 

print -x 
# result: 1 

print -x 
# result: 0 

Trong trường hợp của tôi, tôi đã có một tình huống mà tôi muốn sửa đổi thực đơn hiện của một ứng dụng bằng cách chèn một số mặt hàng lệnh sau một chỉ số cụ thể.API được cung cấp mà tôi đang sử dụng có chức năng "addCommand" có thể lấy chỉ mục để chèn.

xem xét mã này giả nơi đơn có lệnh một đường g, một cái gì đó giống như đơn = [a, e, g], và tôi muốn để chèn được ở chỉ số 1-4

idx = 1 
menu.addCommand(b, index=idx) 
idx += 1 
menu.addCommand(c, index=idx) 
idx += 1 
menu.addCommand(d, index=idx) 
idx += 1 
menu.addCommand(e, index=idx) 
idx += 1 

# result: menu = [a, b, c, d, e, f] 

Nó sẽ được tốt đẹp nếu tôi có thể viết nó để tăng idx tại chỗ như c, nơi tôi có thể làm idx + +, nhưng chức năng không cho phép python của idx + = 1 phương pháp luận trong các đối số.

Giải pháp:

class IterInt(int): 
""" 
This function will return the next integer from the init_value starting point or 0 if None. 
Each subsequent call to increment returns the next value 
:param init_value: 
:return: 
""" 
def __init__(self, init_value=None): 
    if init_value is None: 
     init_value = 0 

    if init_value is not None: 
     self.increment_value = init_value 
    self.increment_value = init_value 

def __pos__(self): 
    self.increment_value += 1 
    return self.increment_value 

def __neg__(self): 
    self.increment_value -= 1 
    return self.increment_value 


idx = IterInt(1) 
menu.addCommand(b, index=+idx) 
menu.addCommand(c, index=+idx) 
menu.addCommand(d, index=+idx) 
menu.addCommand(e, index=+idx) 

# result: menu = [a, b, c, d, e, f] 
Các vấn đề liên quan