50

Trong khi tích hợp một ứng dụng Django mà tôi chưa từng sử dụng trước đây, tôi đã tìm thấy hai cách khác nhau được sử dụng để định nghĩa các hàm trong các lớp. Tác giả dường như sử dụng cả hai đều rất cố tình. Người đầu tiên là một trong Bản thân tôi sử dụng rất nhiều:Khi nào tôi nên sử dụng @classmethod và khi def method (self)?

class Dummy(object): 

    def some_function(self,*args,**kwargs): 
     do something here 
     self is the class instance 

Một trong những khác là một trong những tôi không sử dụng, chủ yếu là bởi vì tôi không hiểu khi sử dụng nó, và để làm gì:

class Dummy(object): 

    @classmethod 
    def some_function(cls,*args,**kwargs): 
     do something here 
     cls refers to what? 

trong các tài liệu Python các classmethod trang trí được giải thích với câu này:

một phương pháp lớp nhận lớp như là đối số đầu tiên ngầm, chỉ như một phương pháp dụ nhận được ví dụ.

Vì vậy, tôi đoán cls đề cập đến Dummy chính nó (số class, không phải ví dụ). Tôi không hiểu chính xác tại sao điều này tồn tại, bởi vì tôi luôn có thể làm điều này:

type(self).do_something_with_the_class 

Đây có phải là chỉ vì lợi ích của sự rõ ràng, hoặc đã làm tôi bỏ lỡ phần quan trọng nhất: những điều ma quái và hấp dẫn mà không thể thực hiện mà không có nó?

Trả lời

47

Đoán của bạn là chính xác - bạn hiểu được cách hoạt độngclassmethod s.

tại sao được rằng các phương pháp này có thể được gọi là cả trên một thể hiện HOẶC trên lớp (trong cả hai trường hợp, đối tượng lớp sẽ được thông qua như là đối số đầu tiên):

class Dummy(object): 

    @classmethod 
    def some_function(cls,*args,**kwargs): 
     print cls 

#both of these will have exactly the same effect 
Dummy.some_function() 
Dummy().some_function() 

Về việc sử dụng những ngày trường: có ít nhất hai công dụng chính để gọi một classmethod trên một ví dụ:

  1. self.some_function() sẽ gọi cho phiên bản của some_function vào loại thực tế của self, chứ không phải là Clas trong đó cuộc gọi đó sẽ xảy ra (và sẽ không cần chú ý nếu lớp được đổi tên); và
  2. Trong trường hợp cần some_function để triển khai một số giao thức, nhưng rất hữu ích khi chỉ gọi riêng đối tượng lớp.

Sự khác biệt với staticmethod: Có một cách khác để xác định phương pháp mà không truy cập dữ liệu Ví dụ, gọi staticmethod. Điều đó tạo ra một phương thức mà không nhận được một đối số đầu tiên tiềm ẩn nào cả; theo đó nó sẽ không được thông qua bất kỳ thông tin nào về cá thể hoặc lớp mà nó được gọi.

In [6]: class Foo(object): some_static = staticmethod(lambda x: x+1) 

In [7]: Foo.some_static(1) 
Out[7]: 2 

In [8]: Foo().some_static(1) 
Out[8]: 2 

In [9]: class Bar(Foo): some_static = staticmethod(lambda x: x*2) 

In [10]: Bar.some_static(1) 
Out[10]: 2 

In [11]: Bar().some_static(1) 
Out[11]: 2 

Việc sử dụng chính tôi đã tìm thấy cho nó là để thích nghi với một chức năng hiện có (mà không mong đợi để nhận được một self) là một phương pháp trên một lớp (hoặc đối tượng).

+1

Tốt nhất: Tôi thích câu trả lời được chia thành cách thức - tại sao. Theo như tôi đã nhận nó bây giờ @classmethod cho phép truy cập vào các chức năng mà không cần một ví dụ. Đây chính xác là những gì tôi đang tìm kiếm, cảm ơn bạn. – marue

+0

@marue Bạn được chào đón! – Marcin

+0

Tôi muốn nói các phương thức gọi lớp trên các phiên bản là kiểu mã hóa không tốt - không có lý do gì để làm như vậy và chỉ có thể gây nhầm lẫn. Nhưng có nó hoạt động (java cho phép cùng một điều, nhưng vấn đề một cảnh báo biên dịch khi gọi phương pháp tĩnh thông qua các trường hợp) – Voo

0

Nếu bạn thêm trang trí @classmethod, Điều đó có nghĩa là bạn sẽ làm cho phương thức đó là phương thức tĩnh của java hoặc C++.(phương pháp tĩnh là thuật ngữ chung Tôi đoán ;)) Python cũng có @staticmethod. và sự khác biệt giữa classmethod và staticmethod là liệu bạn có thể truy cập vào lớp hoặc biến tĩnh bằng cách sử dụng đối số hoặc classname hay không .

class TestMethod(object): 
    cls_var = 1 
    @classmethod 
    def class_method(cls): 
     cls.cls_var += 1 
     print cls.cls_var 

    @staticmethod 
    def static_method(): 
     TestMethod.cls_var += 1 
     print TestMethod.cls_var 
#call each method from class itself. 
TestMethod.class_method() 
TestMethod.static_method() 

#construct instances 
testMethodInst1 = TestMethod()  
testMethodInst2 = TestMethod() 

#call each method from instances 
testMethodInst1.class_method() 
testMethodInst2.static_method() 

tất cả các lớp đó tăng cls.cls_var lên 1 và in nó.

Và mọi lớp học sử dụng cùng một tên trên cùng phạm vi hoặc trường hợp được xây dựng với các lớp này sẽ chia sẻ các phương pháp đó. Chỉ có một TestMethod.cls_var và cũng chỉ có một TestMethod.class_method(), TestMethod.static_method()

Và câu hỏi quan trọng. tại sao các phương pháp này là cần thiết.

classmethod hoặc staticmethod rất hữu ích khi bạn đặt lớp đó làm nhà máy hoặc khi bạn phải khởi tạo lớp học của mình chỉ một lần. như mở tệp một lần và sử dụng phương thức nguồn cấp dữ liệu để đọc từng dòng tệp.

+1

(a) Phương pháp tĩnh là một cái gì đó khác; (b) classmethods không được chia sẻ bởi mỗi lớp. – Marcin

+0

@Marcin cảm ơn vì đã cho tôi biết các định nghĩa không rõ ràng của tôi và tất cả những điều đó. –

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