2013-03-01 55 views
44

Làm cách nào để chuyển một số nguyên theo tham chiếu bằng Python?Truyền số nguyên theo tham chiếu trong Python

Tôi muốn sửa đổi giá trị của biến mà tôi chuyển đến hàm. Tôi đã đọc rằng mọi thứ trong Python đều được truyền theo giá trị, nhưng phải có một thủ thuật đơn giản. Ví dụ, trong Java bạn có thể vượt qua các loại tài liệu tham khảo của Integer, Long vv

  1. Làm thế nào tôi có thể vượt qua một số nguyên vào một chức năng bằng cách tham khảo?
  2. Thực tiễn tốt nhất là gì?
+0

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

Trả lời

55

Nó không hoàn toàn hoạt động theo cách đó trong Python. Python chuyển các tham chiếu đến các đối tượng. Bên trong hàm của bạn, bạn có một đối tượng - Bạn tự do biến đổi đối tượng đó (nếu có thể). Tuy nhiên, số nguyên là không thay đổi. Một giải pháp khác là chuyển số nguyên trong vùng chứa có thể bị đột biến:

def change(x): 
    x[0] = 3 

x = [1] 
change(x) 
print x 

Đây là điều xấu xí/vụng về nhưng bạn sẽ không làm tốt hơn trong Python. Lý do là bởi vì trong Python, gán (=) mất bất kỳ đối tượng là kết quả của phía bên tay phải và liên kết nó với bất cứ điều gì là ở phía bên tay trái * (hoặc chuyển nó đến hàm thích hợp). Hiểu được điều này, chúng ta có thể thấy tại sao không có cách nào thay đổi giá trị của một đối tượng bất biến bên trong một hàm - bạn không thể thay đổi bất kỳ thuộc tính nào vì nó không thay đổi được và bạn không thể chỉ định ". biến "một giá trị mới bởi vì sau đó bạn đang thực sự tạo một đối tượng mới (mà khác với đối tượng cũ) và đặt cho nó tên mà đối tượng cũ có trong không gian tên cục bộ.

Thường thì cách giải quyết là chỉ cần trở các đối tượng mà bạn muốn:

def multiply_by_2(x): 
    return 2*x 

x = 1 
x = multiply_by_2(x) 

* Trong ví dụ trường hợp đầu tiên ở trên, 3 thực sự được thông qua để x.__setitem__.

+5

"Python chuyển đối tượng." Không. Python chuyển các tham chiếu (con trỏ tới các đối tượng). – user102008

+2

@ user102008 - Điểm công bằng. Các ngữ nghĩa tại thời điểm này nhận được rất lầy lội tôi cảm thấy. Cuối cùng, chúng cũng không phải là "con trỏ". Ít nhất, chắc chắn không giống như bạn có trong 'C'. (Ví dụ: họ không phải bị dereferenced). Trong mô hình tinh thần của tôi, nó dễ dàng hơn để nghĩ về những thứ như "Tên" và "Đối tượng". Nhiệm vụ liên kết một "Tên" (s) ở bên trái với một "đối tượng" (s) ở bên phải. Khi bạn gọi một hàm, bạn chuyển đối tượng "" (gắn kết hiệu quả nó với một tên cục bộ mới bên trong hàm). – mgilson

+0

Đây tất nhiên là một mô tả về tham chiếu python * là gì, nhưng không dễ để tìm cách mô tả ngắn gọn cho những người không quen thuộc với thuật ngữ đó. – mgilson

-1

Trong Python, mọi thứ được truyền theo giá trị, nhưng nếu bạn muốn sửa đổi một số trạng thái, bạn có thể thay đổi giá trị của một số nguyên bên trong danh sách hoặc đối tượng được chuyển đến phương thức.

+0

Bất kỳ downvoters chăm sóc bình luận? – recursive

+1

Tôi nghĩ, bởi vì 'mọi thứ được truyền bởi giá trị' không thực sự đúng. Trích dẫn tài liệu: 'đối số được truyền bằng cách sử dụng gọi theo giá trị (trong đó giá trị luôn là tham chiếu đối tượng, không phải giá trị của đối tượng)' – Astery

+0

Danh sách, đối tượng và từ điển được chuyển theo tham chiếu – Mashakal

6

Thực sự, cách tốt nhất là lùi lại và hỏi xem bạn có thực sự cần thực hiện điều này hay không. Tại sao bạn có muốn sửa đổi giá trị của biến mà bạn đang chuyển sang hàm không?

Nếu bạn cần làm điều đó để nhanh chóng hack, cách nhanh nhất là chuyển số list giữ số nguyên và dán [0] xung quanh mọi lần sử dụng, như câu trả lời của mgilson.

Nếu bạn cần làm điều gì đó quan trọng hơn, hãy viết class có thuộc tính int, vì vậy bạn có thể đặt nó. Tất nhiên điều này buộc bạn phải đưa ra một cái tên tốt cho lớp học, và cho thuộc tính - nếu bạn không thể nghĩ ra bất cứ điều gì, hãy quay lại và đọc câu đó một lần nữa, và sau đó sử dụng list.

Thông thường, nếu bạn đang cố gắng chuyển một số thành ngữ Java trực tiếp sang Python, bạn đang làm sai.Ngay cả khi có điều gì đó tương ứng trực tiếp (như với static/@staticmethod), bạn vẫn không muốn sử dụng nó trong hầu hết các chương trình Python chỉ vì bạn sẽ sử dụng nó trong Java.

+0

JAVA không truyền số nguyên theo tham chiếu (số nguyên hoặc đối tượng bất kỳ. Đối tượng đóng hộp cũng được thay thế khi gán). –

+0

@LuisMasuelli Vâng, các primit được đóng hộp được xử lý giống như đồ vật, điều duy nhất ngăn cản việc sử dụng chúng như OP muốn là thực tế là các hộp không thay đổi được (và vì bản thân các nguyên thủy cũng không thay đổi được, toàn bộ điều này là bất biến và chỉ có thể thay đổi ở cấp độ biến đổi) – Kroltan

0

Trong Python, mọi giá trị là một tham chiếu (một con trỏ đến một đối tượng), giống như các phần tử không nguyên thủy trong Java. Ngoài ra, giống như Java, Python chỉ có giá trị vượt qua. Vì vậy, ngữ nghĩa, chúng khá giống nhau.

Vì bạn đề cập đến Java trong câu hỏi của mình, tôi muốn biết cách bạn đạt được những gì bạn muốn trong Java. Nếu bạn có thể hiển thị nó trong Java, tôi có thể chỉ cho bạn cách làm điều đó một cách chính xác tương đương trong Python.

20

Hầu hết các trường hợp bạn cần phải chuyển qua tham chiếu là nơi bạn cần trả lại nhiều giá trị trở lại cho người gọi. Một "thực hành tốt nhất" là sử dụng nhiều giá trị trả về, điều này dễ dàng hơn nhiều trong Python so với các ngôn ngữ như Java.

Dưới đây là một ví dụ đơn giản:

def RectToPolar(x, y): 
    r = (x ** 2 + y ** 2) ** 0.5 
    theta = math.atan2(y, x) 
    return r, theta # return 2 things at once 

r, theta = RectToPolar(3, 4) # assign 2 things at once 
1
class PassByReference: 
    def Change(self, var): 
     self.a = var 
     print(self.a) 
s=PassByReference() 
s.Change(5)  
0

Có lẽ hơn một chút tự chủ tài liệu hơn so với danh sách-of-length-1 Bí quyết là loại trống lừa cũ:

def inc_i(v): 
    v.i += 1 

x = type('',(), {})() 
x.i = 7 
inc_i(x) 
print(x.i) 
+0

Hoặc quấn số trong một lớp: https://github.com/markrages/python_mutable_number – markrages

0

Một mảng phần tử đơn lẻ một phần là có thể thay đổi và cho hầu hết các mục đích, nó có thể được đánh giá như thể nó là một biến số python. Do đó, nó là một vùng chứa số tham chiếu thuận tiện hơn so với một danh sách phần tử đơn.

import numpy as np 
    def triple_var_by_ref(x): 
     x[0]=x[0]*3 
    a=np.array([2]) 
    triple_var_by_ref(a) 
    print(a+1) 

đầu ra:

3 
Các vấn đề liên quan