Khi bạn gọi một chức năng trong Python và đưa ra một số đối số ... chúng có được thông qua bởi giá trị không? Không! Bằng cách tham khảo? Không! Họ được thông qua bằng cách chuyển nhượng.
Nhiều ngôn ngữ lập trình truyền thống sử dụng một trong hai mô hình khi chuyển các đối số cho các chức năng:
Một số ngôn ngữ sử dụng mô hình qua từng giá trị; và
Hầu hết các loại khác sử dụng mô hình tham chiếu qua từng lần.
Phải nói rằng, điều quan trọng là phải biết mô hình mà Python sử dụng, bởi vì điều đó ảnh hưởng đến cách xử lý mã của bạn.
Trong pydon không, bạn sẽ:
Xem rằng Python không sử dụng các mô hình chuyển qua từng giá trị cũng như các mô hình chuyển qua;
Hiểu rằng Python sử dụng mô hình chuyển qua từng lần;
Tìm hiểu về chức năng tích hợp
2
6
0;
Tạo sự hiểu biết tốt hơn cho mô hình đối tượng Python;
nhận ra rằng mỗi đối tượng có 3 tính chất rất quan trọng xác định nó;
hiểu sự khác biệt giữa các đối tượng đột biến và bất biến;
Tìm hiểu sự khác biệt giữa các bản sao nông và sâu; và
Tìm hiểu cách sử dụng mô -đun
2
6
1 để thực hiện cả hai loại bản sao đối tượng.
Bây giờ bạn có thể nhận được bản sao MIỄN PHÍ của bạn về Sách điện tử Pydon'ts - Viết mã Python tuyệt đẹp trên Gumroad.free copy of the ebook “Pydon'ts – Write beautiful Python code” on Gumroad.
Python có qua giá trị không?
Trong mô hình chuyển qua giá trị, khi bạn gọi một hàm với một tập hợp các đối số, dữ liệu được sao chép vào hàm. Điều này có nghĩa là bạn có thể sửa đổi các đối số theo cách bạn vui lòng và bạn sẽ không thể thay đổi trạng thái của chương trình bên ngoài chức năng. Đây không phải là những gì Python làm, Python không sử dụng mô hình qua từng giá trị.
Nhìn vào đoạn mã sau đó, nó có thể trông giống như Python sử dụng giá trị qua từng giá trị:
def foo(x):
x = 4
a = 3
foo(a)
print(a)
# 3
Điều này có vẻ như mô hình qua từng giá trị vì chúng tôi đã cho nó 3, thay đổi nó thành 4 và thay đổi không được phản ánh ở bên ngoài (
2
6
2 vẫn là 3).
Nhưng, trên thực tế, Python không sao chép dữ liệu vào chức năng.
Để chứng minh điều này, tôi sẽ chỉ cho bạn một chức năng khác:
3, được xác định bên ngoài hàm, đã thay đổi sau khi gọi hàm
2
6
4. Do đó, Python không sử dụng mô hình qua từng giá trị.
Python có được tham chiếu không?
Trong một mô hình tham chiếu qua thực sự, hàm được gọi là truy cập vào các biến của callee! Đôi khi, nó có thể trông giống như đó là những gì Python làm, nhưng Python không sử dụng mô hình tham chiếu qua từng lần.
Tôi sẽ cố gắng hết sức để giải thích tại sao đó không phải là những gì Python làm:
Nếu Python sử dụng mô hình tham chiếu qua từng lần, chức năng sẽ thay đổi hoàn toàn giá trị của
2
6
3 bên ngoài hàm, nhưng đó không phải là những gì đã xảy ra, như chúng ta có thể thấy.
Hãy để tôi chỉ cho bạn một tình huống tham chiếu thực tế.
Đây là một số mã Pascal:
program callByReference;
var
x: integer;
procedure foo(var a: integer);
{ create a procedure called `foo` }
begin
a := 6 { assign 6 to `a` }
end;
begin
x := 2; { assign 2 to `x` }
writeln(x); { print `x` }
foo(x); { call `foo` with `x` }
writeln(x); { print `x` }
end.
Nhìn vào các dòng cuối cùng của mã đó:
Chúng tôi gán
2
6
6 cho
2
6
7 với
2
6
8;
Chúng tôi in
2
6
7;
Chúng tôi gọi
>>> id(obj)
2698212637504 # the identity of `obj`
>>> type(obj)
<class 'list'> # the type of `obj`
>>> obj
[1, 2, 3] # the contents of `obj`
0 với
2
6
7 là đối số; và
Chúng tôi in lại
2
6
7.
Đầu ra của chương trình này là gì?
Tôi tưởng tượng rằng hầu hết các bạn sẽ không có thông dịch viên Pascal nằm xung quanh, vì vậy bạn chỉ có thể truy cập tio.run và chạy mã này trực tuyến
Nếu bạn chạy cái này, bạn sẽ thấy rằng đầu ra là
2
6
Điều này có thể khá đáng ngạc nhiên, nếu phần lớn kinh nghiệm lập trình của bạn là ở Python!
Quy trình
>>> id(obj)
2698212637504 # the identity of `obj`
>>> type(obj)
<class 'list'> # the type of `obj`
>>> obj
[1, 2, 3] # the contents of `obj`
0 đã nhận được một cách hiệu quả biến
2
6
7 và thay đổi giá trị mà nó chứa. Sau khi
>>> id(obj)
2698212637504 # the identity of `obj`
>>> type(obj)
<class 'list'> # the type of `obj`
>>> obj
[1, 2, 3] # the contents of `obj`
0 được thực hiện, biến
2
6
7 (sống bên ngoài
>>> id(obj)
2698212637504 # the identity of `obj`
>>> type(obj)
<class 'list'> # the type of `obj`
>>> obj
[1, 2, 3] # the contents of `obj`
0) có một giá trị khác. Bạn không thể làm bất cứ điều gì như thế này trong Python.
Mô hình đối tượng Python
Để thực sự hiểu được cách cư xử của Python khi gọi các chức năng, tốt nhất là trước tiên chúng ta hiểu các đối tượng Python là gì và làm thế nào để mô tả chúng.
Ba đặc điểm của các đối tượng
Trong Python, mọi thứ đều là một đối tượng và mỗi đối tượng được đặc trưng bởi ba điều:
Bản sắc của nó (một số nguyên xác định duy nhất đối tượng, giống như các số an sinh xã hội xác định con người);
một loại (xác định các hoạt động bạn có thể làm với đối tượng của mình); và
nội dung của đối tượng.
Đây là một đối tượng và ba đặc điểm của nó:
>>> id(obj)
2698212637504 # the identity of `obj`
>>> type(obj)
<class 'list'> # the type of `obj`
>>> obj
[1, 2, 3] # the contents of `obj`
Như chúng ta có thể thấy ở trên,
2
6
0 là chức năng tích hợp mà bạn sử dụng để truy vấn danh tính của một đối tượng và
>>> id(obj)
2698212637504 # the identity of `obj`
>>> type(obj)
<class 'list'> # the type of `obj`
>>> obj
[1, 2, 3] # the contents of `obj`
9 là chức năng tích hợp mà bạn sử dụng để truy vấn loại đối tượng.
(Im)mutability
Khả năng đột biến (IM) của một đối tượng phụ thuộc vào loại của nó. Nói cách khác, (IM) biến đổi là một đặc điểm của các loại, không phải của các đối tượng cụ thể!
Nhưng chính xác thì nó có nghĩa là gì đối với một đối tượng có thể thay đổi? Hoặc cho một đối tượng là bất biến?
Hãy nhớ lại rằng một đối tượng được đặc trưng bởi danh tính, loại của nó và nội dung của nó. Một loại có thể thay đổi nếu bạn có thể thay đổi nội dung của các đối tượng mà không thay đổi danh tính và loại của nó.
Danh sách là một ví dụ tuyệt vời của một loại dữ liệu có thể thay đổi. Tại sao? Bởi vì danh sách là container: Bạn có thể đặt những thứ bên trong danh sách và bạn có thể xóa nội dung từ bên trong cùng danh sách đó.
Dưới đây, bạn có thể thấy làm thế nào nội dung của danh sách
Tuy nhiên, khi đối phó với các vật thể bất biến, đó là một câu chuyện hoàn toàn khác. Nếu chúng ta kiểm tra một từ điển tiếng Anh, thì đây là những gì chúng ta nhận được cho định nghĩa của những người khác không thể tin được:
tính từ: bất biến - không thay đổi theo thời gian hoặc không thể thay đổi.
Nội dung của đối tượng bất biến không bao giờ thay đổi. Lấy một chuỗi làm ví dụ:
>>> obj = "Hello, world!"
Chuỗi là một ví dụ tốt cho cuộc thảo luận này bởi vì, đôi khi, chúng có thể trông có thể thay đổi. Nhưng họ thì không!
Một chỉ số rất tốt cho thấy một đối tượng là bất biến là khi tất cả các phương thức của nó trả về một cái gì đó. Đây không phải là phương thức
4. Thay vào đó, chuỗi mới đã được tạo và trả lại cho bạn.
Một gợi ý tuyệt vời khác về thực tế là các chuỗi là bất biến là bạn không thể gán cho các chỉ số của nó:
>>> obj[0]
'H'
>>> obj[0] = "h"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
Điều này cho thấy rằng, khi một chuỗi được tạo, nó vẫn giữ nguyên. Nó có thể được sử dụng để xây dựng các chuỗi khác, nhưng bản thân chuỗi luôn luôn. ở lại. không thay đổi.
Một lần nữa, những cái tên này chỉ là nhãn. Nhãn mà tôi quyết định bám vào cùng một đối tượng. Làm thế nào chúng ta có thể biết đó là cùng một đối tượng? Chà, tất cả các số an sinh xã hội của họ (IDS) phù hợp, vì vậy chúng phải là cùng một đối tượng:
Hãy nghĩ về nó về mặt cặp song sinh hoàn hảo. Khi hai anh chị em là cặp song sinh hoàn hảo, họ trông giống hệt nhau. Tuy nhiên, họ là những người khác nhau!
>>> [].append(0) # No return.
>>> obj.upper() # A string is returned.
'HELLO, WORLD!"4
Chỉ là một lưu ý phụ, nhưng là một điều quan trọng, bạn nên biết về nhà điều hành
>>> [].append(0) # No return.
>>> obj.upper() # A string is returned.
'HELLO, WORLD!"
4.
Nói chung, khi bạn muốn phủ nhận một điều kiện, bạn đặt một
>>> [].append(0) # No return.
>>> obj.upper() # A string is returned.
'HELLO, WORLD!"
>>> [].append(0) # No return.
>>> obj.upper() # A string is returned.
'HELLO, WORLD!"
8, cũng cung cấp toán tử
>>> [].append(0) # No return.
>>> obj.upper() # A string is returned.
'HELLO, WORLD!"
9 ... Thật tuyệt vời ?!
Nhiệm vụ là biệt danh
Nếu chúng ta tiếp tục đẩy phép ẩn dụ này về phía trước, việc gán các biến cũng giống như đặt một biệt danh mới cho ai đó.
Bạn bè của tôi từ trường cấp hai gọi tôi là Rojer Rojer. Bạn bè của tôi từ trường đại học gọi tôi là Gir Giraoo. Những người tôi không gần gũi gọi tôi bằng tên của tôi - Hồi Rodrigo. Tuy nhiên, bất kể họ gọi tôi là gì, tôi vẫn là tôi, phải không?
Nếu một ngày tôi quyết định thay đổi kiểu tóc của mình, mọi người sẽ thấy kiểu tóc mới, bất kể họ gọi tôi là gì!
Theo cách tương tự, nếu tôi sửa đổi nội dung của một đối tượng, tôi có thể sử dụng bất kỳ biệt danh nào tôi thích thấy rằng những thay đổi đó đã xảy ra. Ví dụ: chúng ta có thể thay đổi phần tử giữa của danh sách chúng ta đã chơi xung quanh với:
>>> id(obj)
2698212637504 # the identity of `obj`
>>> type(obj)
<class 'list'> # the type of `obj`
>>> obj
[1, 2, 3] # the contents of `obj`
0 để sửa đổi phần tử giữa, nhưng sự thay đổi đó cũng có thể nhìn thấy từ tất cả các biệt danh khác.
Why?
Bởi vì tất cả đều chỉ vào cùng một đối tượng danh sách.
Python là thông qua
Đã đặt ra tất cả những điều này, bây giờ chúng tôi đã sẵn sàng để hiểu làm thế nào Python chuyển các lập luận cho các chức năng.
Khi chúng ta gọi một hàm, mỗi tham số của hàm được gán cho đối tượng chúng được truyền vào. Về bản chất, mỗi tham số bây giờ trở thành một biệt danh mới cho các đối tượng được đưa ra.
Lập luận bất biến
Nếu chúng ta vượt qua các lập luận bất biến, thì chúng ta không có cách nào để tự sửa đổi các đối số. Rốt cuộc, đó là những gì có nghĩa là bất biến: Không phải thay đổi.
Đó là lý do tại sao nó có thể trông giống như Python sử dụng mô hình qua từng giá trị. Bởi vì cách duy nhất mà chúng ta có thể có tham số giữ một cái gì đó khác là bằng cách gán nó cho một điều hoàn toàn khác. Khi chúng tôi làm điều đó, chúng tôi đang sử dụng lại cùng một biệt danh cho một đối tượng khác:
>>> id(obj)
2698212637504 # the identity of `obj`
>>> type(obj)
<class 'list'> # the type of `obj`
>>> obj
[1, 2, 3] # the contents of `obj`
0 với đối số
>>> obj[0]
'H'
>>> obj[0] = "h"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
2, như thể chúng ta đang thực hiện
>>> obj[0]
'H'
>>> obj[0] = "h"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
3 khi bắt đầu chức năng.
Ngay sau đó, chúng tôi có
>>> obj[0]
'H'
>>> obj[0] = "h"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
4. Điều này có nghĩa là, hãy lấy biệt danh "thanh" và trỏ nó vào số nguyên
>>> obj[0]
'H'
>>> obj[0] = "h"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
5. Python không quan tâm rằng
>>> obj = "Hello, world!"
7, như một biệt danh (như một tên biến) đã được sử dụng. Bây giờ nó đang chỉ vào đó
>>> obj[0]
'H'
>>> obj[0] = "h"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
5!
Lập luận thay đổi
Mặt khác, các đối số có thể thay đổi có thể được thay đổi. Chúng tôi có thể sửa đổi nội dung nội bộ của họ. Một ví dụ điển hình của một đối tượng có thể thay đổi là một danh sách: các yếu tố của nó có thể thay đổi (và độ dài của nó cũng vậy).
Đó là lý do tại sao nó có thể trông giống như Python sử dụng mô hình tham chiếu qua từng lần. Tuy nhiên, khi chúng ta thay đổi nội dung của một đối tượng, chúng ta đã không thay đổi danh tính của chính đối tượng. Tương tự, khi bạn thay đổi kiểu tóc hoặc quần áo, số an sinh xã hội của bạn không thay đổi:
Bạn có hiểu những gì tôi đang cố gắng nói không? Nếu không, hãy bỏ một bình luận bên dưới và tôi sẽ cố gắng giúp đỡ.
Cẩn thận khi gọi các chức năng
Điều này cho thấy bạn nên cẩn thận khi xác định các chức năng của bạn. Nếu chức năng của bạn mong đợi các đối số có thể thay đổi, bạn nên thực hiện một trong hai:
Không làm thay đổi lập luận theo bất kỳ cách nào; hoặc
Tài liệu rõ ràng rằng đối số có thể bị đột biến.
Cá nhân, tôi thích đi theo cách tiếp cận đầu tiên: không thay đổi lập luận; Nhưng có những lúc và địa điểm cho cách tiếp cận thứ hai.
Đôi khi, bạn cần phải lấy lập luận làm cơ sở cho một loại chuyển đổi nào đó, điều đó có nghĩa là bạn sẽ muốn thay đổi lập luận. Trong những trường hợp đó, bạn có thể nghĩ về việc thực hiện một bản sao của đối số (được thảo luận trong phần tiếp theo), nhưng việc thực hiện bản sao đó có thể tốn nhiều tài nguyên. Trong những trường hợp đó, đột biến đối số có thể là lựa chọn hợp lý duy nhất.
Tạo bản sao
Bản sao nông so với sâu
Sao chép một đối tượng, có nghĩa là tạo một đối tượng thứ hai có một danh tính khác (do đó, là một đối tượng khác) nhưng có cùng nội dung. Nói chung, chúng tôi sao chép một đối tượng để chúng tôi có thể làm việc với nó và biến đổi nó, đồng thời bảo tồn đối tượng đầu tiên.
Khi sao chép các đối tượng, có một vài sắc thái cần được thảo luận.
Sao chép các đối tượng bất biến
Điều đầu tiên cần được nói là, đối với các đối tượng bất biến, không có ý nghĩa gì khi nói về các bản sao.
Bản sao của người Viking chỉ có ý nghĩa đối với các đối tượng có thể thay đổi. Nếu đối tượng của bạn là bất biến và nếu bạn muốn bảo tồn một tham chiếu đến nó, bạn chỉ có thể thực hiện một nhiệm vụ thứ hai và làm việc với nó:
Đầu tiên, chúng tôi tạo một danh sách bên trong danh sách và chúng tôi sao chép danh sách bên ngoài. Bây giờ, vì nó là một bản sao, danh sách được sao chép không phải là cùng một đối tượng với danh sách bên ngoài gốc:
Nhưng nếu chúng không phải là cùng một đối tượng, thì chúng ta có thể sửa đổi nội dung của một trong các danh sách và người kia sẽ không phản ánh sự thay đổi:
>>> obj[0]
'H'
>>> obj[0] = "h"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
9 đều phản ánh những thay đổi đó ...
Nhưng không phải bản sao được cho là cho tôi một danh sách thứ hai mà tôi có thể thay đổi mà không ảnh hưởng đến danh sách đầu tiên? Đúng! Và đó là những gì đã xảy ra!
00: Rốt cuộc, yếu tố thứ ba của cả hai đã chỉ vào một đối tượng danh sách, và nó vẫn là! Đó là nội dung (bên trong) của đối tượng mà chúng ta đang chỉ ra đã thay đổi.
Đôi khi, chúng tôi không muốn điều này xảy ra: Đôi khi, chúng tôi không muốn các đối tượng có thể thay đổi để chia sẻ các đối tượng có thể thay đổi bên trong.
Kỹ thuật sao chép nông phổ biến
Khi làm việc với danh sách, người ta thường sử dụng việc cắt để tạo ra một bản sao nông của danh sách:
Sử dụng chức năng tích hợp cho loại tương ứng, trên chính đối tượng, cũng xây dựng các bản sao nông. Điều này hoạt động cho các danh sách và từ điển, và có khả năng làm việc cho các loại có thể thay đổi khác.
Dưới đây là một ví dụ với danh sách bên trong danh sách:
Khi bạn muốn sao chép một đối tượng, kỹ lưỡng và bạn không muốn bản sao chia sẻ tham chiếu đến các đối tượng bên trong, bạn cần thực hiện một bản sao sâu của đối tượng. Bạn có thể nghĩ về một bản sao sâu như một thuật toán đệ quy.
Bạn sao chép các yếu tố của cấp độ đầu tiên và, bất cứ khi nào bạn tìm thấy một yếu tố có thể thay đổi ở cấp độ đầu tiên, bạn sẽ tái sử dụng và sao chép nội dung của các yếu tố đó.
Để hiển thị ý tưởng này, đây là một triển khai đệ quy đơn giản của một bản sao sâu cho các danh sách có chứa các danh sách khác:
program callByReference;
var
x: integer;
procedure foo(var a: integer);
{ create a procedure called `foo` }
begin
a := 6 { assign 6 to `a` }
end;
begin
x := 2; { assign 2 to `x` }
writeln(x); { print `x` }
foo(x); { call `foo` with `x` }
writeln(x); { print `x` }
end.
17 đủ thông minh để xử lý các vấn đề có thể phát sinh với các định nghĩa tròn, ví dụ! Đó là, khi một đối tượng chứa một đối tượng khác có chứa tên đầu tiên: Việc thực hiện đệ quy ngây thơ của một thuật toán sao chép sâu sẽ vào một vòng lặp vô hạn!
Nếu bạn viết các đối tượng tùy chỉnh của riêng mình và bạn muốn chỉ định các bản sao nông và sâu của chúng nên được tạo như thế nào, bạn chỉ cần thực hiện lần lượt
Đó là một mô -đun tuyệt vời, theo ý kiến của tôi.
Ví dụ trong mã
Bây giờ chúng tôi đã đi sâu vào lý thuyết - ý định chơi chữ & nbsp; -, đã đến lúc cho bạn thấy một số mã thực tế chơi với các khái niệm này.
Đối số mặc định có thể thay đổi
Hãy bắt đầu với một yêu thích Twitter:
Python là một ngôn ngữ đáng kinh ngạc nhưng đôi khi dường như có những điều kỳ quặc 🤪
Ví dụ: một điều thường gây nhầm lẫn cho người mới bắt đầu là lý do tại sao bạn không nên sử dụng danh sách làm giá trị mặc định 👇
Đây là một chủ đề sẽ giúp bạn hiểu 💯 pic.twitter.com/hvhpjs2psh này
- Rodrigo 🐍📝 (@mathsppblog) ngày 5 tháng 10 năm 2021
Rõ ràng, đó là một ý tưởng tồi để sử dụng các đối tượng có thể thay đổi làm đối số mặc định. Đây là một đoạn trích cho bạn thấy lý do tại sao:
program callByReference;
var
x: integer;
procedure foo(var a: integer);
{ create a procedure called `foo` }
begin
a := 6 { assign 6 to `a` }
end;
begin
x := 2; { assign 2 to `x` }
writeln(x); { print `x` }
foo(x); { call `foo` with `x` }
writeln(x); { print `x` }
end.
1
Hàm trên nối một phần tử vào danh sách và, nếu không có danh sách nào được đưa ra, hãy nối nó vào một danh sách trống theo mặc định.
Tuyệt vời, hãy đưa chức năng này vào sử dụng tốt:
program callByReference;
var
x: integer;
procedure foo(var a: integer);
{ create a procedure called `foo` }
begin
a := 6 { assign 6 to `a` }
end;
begin
x := 2; { assign 2 to `x` }
writeln(x); { print `x` }
foo(x); { call `foo` with `x` }
writeln(x); { print `x` }
end.
21 vào danh sách khác mà chúng tôi có. Và cuối cùng, chúng tôi sử dụng nó để nối một
>>> obj[0]
'H'
>>> obj[0] = "h"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
5 vào một danh sách trống ... ngoại trừ đó không phải là những gì xảy ra!
Hóa ra, khi chúng ta xác định một hàm, các đối số mặc định được tạo và lưu trữ ở một nơi đặc biệt:
program callByReference;
var
x: integer;
procedure foo(var a: integer);
{ create a procedure called `foo` }
begin
a := 6 { assign 6 to `a` }
end;
begin
x := 2; { assign 2 to `x` }
writeln(x); { print `x` }
foo(x); { call `foo` with `x` }
writeln(x); { print `x` }
end.
3
Điều này có nghĩa là đối số mặc định luôn là cùng một đối tượng. Do đó, vì nó là một đối tượng có thể thay đổi, nội dung của nó có thể thay đổi theo thời gian. Đó là lý do tại sao, trong mã ở trên,
program callByReference;
var
x: integer;
procedure foo(var a: integer);
{ create a procedure called `foo` }
begin
a := 6 { assign 6 to `a` }
end;
begin
x := 2; { assign 2 to `x` }
writeln(x); { print `x` }
foo(x); { call `foo` with `x` }
writeln(x); { print `x` }
end.
4
Đây là lý do tại sao, nói chung, các đối tượng có thể thay đổi không nên được sử dụng làm đối số mặc định.
Thực tiễn tiêu chuẩn, trong những trường hợp này, là sử dụng
27 và sau đó sử dụng đường ngắn mạch Boolean để gán giá trị mặc định:
program callByReference;
var
x: integer;
procedure foo(var a: integer);
{ create a procedure called `foo` }
begin
a := 6 { assign 6 to `a` }
end;
begin
x := 2; { assign 2 to `x` }
writeln(x); { print `x` }
foo(x); { call `foo` with `x` }
writeln(x); { print `x` }
end.
5
Với việc triển khai này, chức năng hiện hoạt động như mong đợi:
program callByReference;
var
x: integer;
procedure foo(var a: integer);
{ create a procedure called `foo` }
begin
a := 6 { assign 6 to `a` }
end;
begin
x := 2; { assign 2 to `x` }
writeln(x); { print `x` }
foo(x); { call `foo` with `x` }
writeln(x); { print `x` }
end.
program callByReference;
var
x: integer;
procedure foo(var a: integer);
{ create a procedure called `foo` }
begin
a := 6 { assign 6 to `a` }
end;
begin
x := 2; { assign 2 to `x` }
writeln(x); { print `x` }
foo(x); { call `foo` with `x` }
writeln(x); { print `x` }
end.
7
Ngay cả khi không có nhiều bối cảnh, chúng ta có thể thấy những gì đang xảy ra: khi hiển thị lệnh trợ giúp cho một phần nhất định, chúng ta có thể muốn thụt vào nó (hoặc không) để hiển thị các phụ thuộc phân cấp.
41, tương tự như từ điển, chứa các biến môi trường được xác định.
Dưới đây là một vài ví dụ từ máy (Windows) của tôi:
program callByReference;
var
x: integer;
procedure foo(var a: integer);
{ create a procedure called `foo` }
begin
a := 6 { assign 6 to `a` }
end;
begin
x := 2; { assign 2 to `x` }
writeln(x); { print `x` }
foo(x); { call `foo` with `x` }
writeln(x); { print `x` }
end.
44 của nó, nó cần thiết lập một loạt các biến môi trường.
Các biến môi trường này được đặt để đưa ra bối cảnh cần thiết cho tập lệnh CGI sẽ được chạy. Tuy nhiên, chúng tôi không muốn thực sự sửa đổi môi trường hiện tại!
Vì vậy, những gì chúng tôi làm là tạo ra một bản sao sâu của môi trường, và sau đó chúng tôi sửa đổi nó thành nội dung trái tim của chúng tôi! Sau khi chúng tôi hoàn thành, chúng tôi bảo Python thực thi tập lệnh CGI và chúng tôi cung cấp môi trường bị thay đổi như một đối số.
Cách chính xác mà điều này được thực hiện có thể không tầm thường để hiểu. Tôi, đối với một người, đừng nghĩ rằng tôi có thể giải thích nó cho bạn. Nhưng điều đó không có nghĩa là chúng ta không thể suy ra các phần của nó:
Đây là mã:
program callByReference;
var
x: integer;
procedure foo(var a: integer);
{ create a procedure called `foo` }
begin
a := 6 { assign 6 to `a` }
end;
begin
x := 2; { assign 2 to `x` }
writeln(x); { print `x` }
foo(x); { call `foo` with `x` }
writeln(x); { print `x` }
end.
9
Như chúng ta có thể thấy, chúng tôi đã sao chép môi trường và xác định một số biến. Cuối cùng, chúng tôi đã tạo ra một quy trình con mới có được môi trường sửa đổi.
Sự kết luận
Đây là điểm chính của Pydon không, đối với bạn, trên một đĩa bạc:
Cấm Python sử dụng mô hình chuyển giao từng lần và hiểu nó đòi hỏi bạn phải nhận ra tất cả các đối tượng được đặc trưng bởi một số nhận dạng, loại của chúng và nội dung của chúng.
Điều này không cho bạn thấy rằng:
Python không sử dụng mô hình chuyển qua từng giá trị, cũng như mô hình vượt qua;
Python sử dụng một mô hình chuyển đổi qua từng lần (sử dụng biệt danh trực tuyến);
Mỗi đối tượng được đặc trưng bởi
bản sắc của nó;
loại của nó; và
Nội dung của nó.
Hàm
2
6
0 được sử dụng để truy vấn định danh của đối tượng;
Hàm
>>> id(obj)
2698212637504 # the identity of `obj`
>>> type(obj)
<class 'list'> # the type of `obj`
>>> obj
[1, 2, 3] # the contents of `obj`
9 được sử dụng để truy vấn loại đối tượng;
Loại đối tượng xác định liệu nó có thể thay đổi hay bất biến;
Bản sao nông sao chép tham chiếu của các đối tượng có thể thay đổi lồng nhau;
Các bản sao sâu thực hiện các bản sao cho phép một đối tượng và các yếu tố bên trong của nó, được thay đổi mà không bao giờ ảnh hưởng đến bản sao;
20 nếu bạn muốn các đối tượng của riêng mình có thể giải quyết được.
Xem thêm
Nếu bạn thích nội dung video, bạn có thể kiểm tra video YouTube này, được lấy cảm hứng từ bài viết này.
Nếu bạn thích Pydon này, đừng chắc chắn để lại phản ứng bên dưới và chia sẻ điều này với bạn bè và đồng nghiệp của bạn. Ngoài ra, hãy đăng ký nhận bản tin để bạn không bỏ lỡ một Pydon nào!
Tôi hy vọng bạn đã học được điều gì đó mới! Nếu bạn đã làm, hãy xem xét theo bước chân của những độc giả đã mua cho tôi một lát bánh pizza. Đóng góp nhỏ của bạn giúp tôi sản xuất nội dung này miễn phí và không spam bạn với quảng cáo khó chịu.
Người giới thiệu
Python 3 Docs, FAQ lập trình, Cách tôi viết một hàm với các tham số đầu ra (gọi theo tham chiếu)? -a-function-with-output-parameters-call-by-preference [truy cập lần cuối 04-10-2021];
Python 3 Docs, Thư viện tiêu chuẩn Python,
2
6
1, https://docs.python.org/3/l Library/copy.html [truy cập lần cuối 05-10-2021];
effbot.org, cuộc gọi của đối tượng (thông qua arquivo.pt,), https://arquivo.pt/wayback/20160516131553/http://effbot.org/zone/call-by-byject.htm 04-10-2021];
effbot.org, đối tượng của Python (thông qua arquivo.pt,), https://arquivo.pt/wayback/20191115002033/http://effbot.org/zone/python-objects.htm -2021];
Robert Heaton, Hồi là Python Pass-By-Reference hoặc Pass-by-Value, https://robertheaton.com/2014/02/09/pythons-pass-by-bject-bectre- as-as-as-as-by-philip -K-dick/ [truy cập lần cuối 04-10-2021];
Câu hỏi và câu trả lời của StackoverFlow, Làm cách nào để tôi vượt qua một biến bằng cách tham khảo ?,, https://stackoverflow.com/q/986006/2828287 [truy cập lần cuối 04-10-2021];
Câu hỏi và câu trả lời của stackoverflow, các giá trị vượt qua trong python [trùng lặp], https://stackoverflow.com/q/534375/2828287 [truy cập lần cuối 04-10-2021];
Chủ đề Twitter của @mathsppblog, https://twitter.com/mathsppblog/status/1445148566721335298 [truy cập lần cuối 20-10-2021];