2013-05-24 29 views
8
class parent(object): 
    @classmethod 
    def a_class_method(cls): 
    print "in class method %s" % cls 

    @staticmethod 
    def a_static_method(): 
    print "static method" 

    def useless_func(self): 
    pass 


p1, p2 = parent(),parent() 

id(p1) == id(p2) // False 

id(p1.useless_func) == id(p2.useless_func) // True 

Trong đoạn mã trên, tôi không hiểu tại sao useless_func có cùng id khi nó thuộc về hai đối tượng khác nhau?Phương pháp đối tượng của cùng một lớp có cùng một id?

+0

thể trùng lặp của http://stackoverflow.com/ Câu hỏi/13348031/python-bound-và-unbound-method-object –

+0

@AnkitJaiswal nó khác nhau – jamylak

Trả lời

7

Dưới đây là những gì tôi nghĩ đang xảy ra:

  1. Khi bạn dereference p1.useless_func, một bản sao của nó được tạo ra trong bộ nhớ. vị trí bộ nhớ này được trả về bởi id
  2. Vì không có tài liệu tham khảo cho các bản sao của phương pháp vừa tạo ra, nó được khai hoang bởi GC, và địa chỉ bộ nhớ có sẵn một lần nữa
  3. Khi bạn dereference p2.useless_func, một bản sao của nó được tạo ra trong cùng một địa chỉ bộ nhớ (nó có sẵn), mà bạn lấy lại bằng cách sử dụng id một lần nữa.
  4. Bản sao thứ hai là GCD

Nếu bạn đang chạy một loạt các mã khác và kiểm tra id của phương pháp dụ một lần nữa, tôi sẽ đặt cược các id s sẽ là giống nhau, nhưng khác nhau từ lần chạy ban đầu.

Ngoài ra, bạn có thể nhận thấy rằng trong ví dụ của David Wolver, ngay sau khi tham chiếu lâu dài đến phương thức sao chép thu được thì số id trở nên khác.

Để xác nhận lý thuyết này, đây là một phiên vỏ sử dụng Jython (cùng kết quả với PyPy), mà không sử dụng bộ sưu tập tài liệu tham khảo đếm rác CPython của:

Jython 2.5.2 (Debian:hg/91332231a448, Jun 3 2012, 09:02:34) 
[OpenJDK Server VM (Oracle Corporation)] on java1.7.0_21 
Type "help", "copyright", "credits" or "license" for more information. 
>>> class parent(object): 
...  def m(self): 
...    pass 
... 
>>> p1, p2 = parent(), parent() 
>>> id(p1.m) == id(p2.m) 
False 
+3

Ah, chúng tôi có một người chiến thắng! Điều đó có ý nghĩa hoàn hảo. Câu trả lời rất hay. –

+0

@jamylak Đó là một bản chỉnh sửa rất hào phóng.Tôi tin rằng có đủ nội dung ở đó để đảm bảo một câu trả lời riêng biệt, trên thực tế. –

+0

@Asad Tôi không tin như vậy, nó thuộc về đây – jamylak

11

Đây là một câu hỏi rất thú vị!

Trong điều kiện của bạn, chúng xuất hiện giống nhau:

Python 2.7.2 (default, Oct 11 2012, 20:14:37) 
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> class Foo(object): 
... def method(self): pass 
... 
>>> a, b = Foo(), Foo() 
>>> a.method == b.method 
False 
>>> id(a.method), id(b.method) 
(4547151904, 4547151904) 

Tuy nhiên, hãy chú ý rằng khi bạn làm bất cứ điều gì với họ, họ trở nên khác nhau:

>>> a_m = a.method 
>>> b_m = b.method 
>>> id(a_m), id(b_m) 
(4547151*9*04, 4547151*5*04) 

Và sau đó, khi kiểm tra một lần nữa, họ đã thay đổi một lần nữa!

>>> id(b.method) 
4547304416 
>>> id(a.method) 
4547304416 

Khi một phương pháp trên một cá thể được truy cập, một thể hiện của "phương pháp ràng buộc" được trả về. Một phương pháp ràng buộc lưu trữ một tham chiếu đến cả hai trường hợp và đối tượng chức năng của phương pháp:

>>> a_m 
<bound method Foo.method of <__main__.Foo object at 0x10f0e9a90>> 
>>> a_m.im_func is Foo.__dict__['method'] 
True 
>>> a_m.im_self is a 
True 

(lưu ý rằng tôi cần phải sử dụng Foo.__dict__['method'], không Foo.method, vì Foo.method sẽ mang lại một "phương pháp cởi ra" ... mục đích mà là một bài tập cho người đọc)

Mục đích của đối tượng "phương pháp liên kết" này là làm cho các phương thức "hoạt động hợp lý" khi chúng được truyền xung quanh như các hàm. Ví dụ: khi tôi gọi hàm a_m(), tức là giống hệt để gọi a.method(), mặc dù chúng tôi không có tham chiếu rõ ràng đến a nữa. Ngược lại hành vi này với JavaScript (ví dụ), trong đó var method = foo.method; method() không không sản xuất cùng một kết quả như foo.method().

SO! Điều này đưa chúng ta trở lại câu hỏi ban đầu: tại sao dường như id(a.method) mang lại giá trị giống như id(b.method)? Tôi tin rằng Asad là chính xác: nó phải làm với bộ gom rác đếm tham chiếu của Python *: khi biểu thức id(a.method) được đánh giá, một phương thức ràng buộc được cấp phát, ID được tính toán, và phương thức ràng buộc được deallocated. Khi phương pháp ràng buộc tiếp theo - cho b.method - được cấp phát, nó được cấp phát chính xác cùng một vị trí trong bộ nhớ, vì không có bất kỳ phân bổ nào (hoặc đã là số lượng cân bằng) do phương pháp ràng buộc cho a.method được phân bổ. Điều này có nghĩa là a.method dường như có cùng một vị trí bộ nhớ là b.method. Cuối cùng, điều này giải thích tại sao các vị trí bộ nhớ dường như thay đổi lần thứ hai chúng được kiểm tra: các phân bổ khác đã diễn ra giữa lần kiểm tra thứ nhất và thứ hai có nghĩa là lần thứ hai chúng được phân bổ tại một vị trí khác (lưu ý: chúng được phân bổ lại bởi vì tất cả các tham chiếu đến chúng đều bị mất; các phương thức liên kết được lưu trữ †, do đó truy cập cùng một phương thức hai lần sẽ trả về cùng một cá thể: a_m0 = a.method; a_m1 = a.method; a_m0 is a_m1 => True).

*: pedants lưu ý: thực ra, điều này không liên quan gì đến bộ thu rác thực tế, chỉ tồn tại để đối chiếu với tham chiếu vòng tròn… nhưng… đó là một câu chuyện cho một ngày khác.
†: ít nhất trong CPython 2.7; CPython 2.6 dường như không cache các phương thức bị ràng buộc, điều này sẽ khiến tôi mong đợi rằng hành vi không được chỉ định.

+2

Tôi tin rằng trong ví dụ thứ hai của bạn, bạn đã có hai tài liệu tham khảo khác nhau, nhưng a.method và b.method vẫn có cùng một id. – Hamish

+1

@Hamish Đó không phải là cách id hoạt động: 'a = [] b = id (a) == id (b) True' – Patashu

+0

Bạn đang nói về các phương pháp bị ràng buộc trước đó - vậy tại sao không đề cập đến chúng ngay bây giờ, vì đó là một nửa đây là? – Ryan

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