2013-12-18 21 views
28

Có lẽ đây là câu hỏi phong cách hơn là kỹ thuật nhưng tôi có một lớp python với một số biến thành viên và tôi muốn nó hoạt động sao cho một số biến thành viên được khởi tạo khi người dùng đầu tiên tạo một cá thể của lớp (tức là trong hàm __init__) và tôi muốn các biến thành viên khác được định nghĩa từ các đối số của các hàm thành viên sẽ được gọi sau này. Vì vậy, câu hỏi của tôi là tôi nên khởi tạo tất cả các biến thành viên trong các chức năng __init__ (và thiết lập những người sẽ được xác định sau này để giá trị giả) hoặc khởi tạo một số trong các chức năng __init__ và một số trong các chức năng sau này. Tôi nhận ra điều này có thể khó hiểu nên đây là một vài ví dụ.Python - tất cả các biến thành viên được khởi tạo trong __init__

Ví dụ này có var3 đặt thành 0 ban đầu trong hàm __init__, sau đó đặt thành giá trị mong muốn sau này trong hàm my_funct.

class myClass(object): 
    def __init__(self,var1,var2): 
     self.var1=var1 
     self.var2=var2 
     self.var3=0 

    def my_funct(self,var3): 
     self.var3=var3 

và trong ví dụ này, var3 không được định nghĩa ở tất cả trong __init__ chức năng

class myClass(object): 
    def __init__(self,var1,var2): 
     self.var1=var1 
     self.var2=var2 

    def my_funct(self,var3): 
     self.var3=var3 

Tôi không nghĩ rằng một trong hai cách sẽ làm cho một sự khác biệt lớn (có thể là một sự khác biệt nhỏ trong sử dụng bộ nhớ) . Nhưng tôi đã tự hỏi nếu một trong số này được ưa thích hơn khác vì một lý do nào đó.

Trả lời

19

Trong lập trình hướng đối tượng, tùy thuộc vào nhà phát triển để đảm bảo đối tượng luôn ở trạng thái nhất quán sau khi khởi tạo và sau khi phương thức kết thúc. Ngoài ra, bạn có thể tự do phát triển lớp học theo ý muốn (lưu ý một số nguyên tắc nhất định với phân lớp/ghi đè và vv).

Công cụ như Pylint sẽ cảnh báo khi bạn đặt các biến mẫu bên ngoài __init__. Có thể lập luận rằng việc đặt tất cả các biến mẫu trong __init__ là sạch hơn nhưng nó không phải là một quy tắc phải luôn được tuân thủ.

+1

Đồng ý. Tính nhất quán là chìa khóa - bạn không muốn người ngoài sử dụng API hoặc lớp của bạn ở trạng thái không hợp lệ. –

+0

Bạn có thể định nghĩa ngắn gọn 'trạng thái nhất quán' có nghĩa là gì không. Điều này có nghĩa là không có biến thành viên mới nào được thêm sau khi instantiation? – user1893354

+1

@ user1893354 bạn có thể thêm các biến sau khi instantiation nhưng nó không nên có thể tạo một đối tượng, gọi một hoặc nhiều phương pháp và kết thúc với một đối tượng lộn xộn. Hành vi của các phương thức và giá trị trả về của chúng phải luôn nhất quán. Ví dụ, chúng ta không thể có một lớp 'Car' báo cáo là cả hai" bị hỏng "và" hoạt động đúng ". –

3

Tôi thực sự sẽ không khuyến khích khởi tạo các biến mà bạn không cần lúc nào trong __init__ thành giá trị mặc định tùy ý.

Tôi đặt câu hỏi về việc bạn sử dụng OO trong trường hợp này, nhưng tôi chắc rằng có trường hợp hợp lệ và dễ hiểu khi __init__ sẽ không làm mọi thứ và lớp sẽ tự sửa đổi thêm bằng cách thêm các thuộc tính bổ sung Các phương pháp khác.

Cách thích hợp trong quan điểm của tôi để kiểm tra xem một biến đã được đặt trong khi chạy một phương pháp có thể muốn sử dụng nó sẽ là sử dụng hasattr. Đây là trong trường hợp đây là một cách hợp lệ để sử dụng phương pháp và thử nghiệm chỉ chuyển đổi hành vi một cách hợp lý.

Một cách khác là thử và sử dụng nó và xử lý ngoại lệ và cung cấp một số thông tin thân thiện với người dùng về những gì người dùng trong lớp của bạn đang làm sai. Đây là trong trường hợp phương thức cần thuộc tính được thiết lập trước khi chạy.

tức là người đàn ông, bạn đã khởi tạo lớp, nhưng bạn cần đảm bảo thuộc tính z tồn tại bằng cách gọi phương thức z_init trước khi chạy phương thức z_run.

Một cách khác, được cho là theo cách nhiều hơn, sẽ chỉ là tài liệu cách sử dụng phương thức trong chuỗi tài liệu và sau đó để cho ngoại lệ bay khi nó được sử dụng không đúng cách. Điều này là đủ tốt cho việc thực hiện đầu tiên của một cái gì đó và sau đó bạn có thể tập trung vào nhiệm vụ tiếp theo. Đây là tình huống tương tự như trên, phương thức cần thuộc tính được thiết lập.

Lý do tôi không thích ý tưởng khởi tạo biến thành mặc định tùy ý là điều này có thể gây nhầm lẫn (vì tùy ý) và là nhiễu dòng.

Nếu giá trị là không tùy ý và chỉ đơn giản là giá trị mặc định có thể thay đổi, bạn nên sử dụng giá trị mặc định theo phương pháp __init__ có thể bị ghi đè. Nó cũng có thể là một trạng thái ban đầu hợp lệ, cũng là không phải là tùy ý và bạn nên đặt nó theo phương thức __init__. Vì vậy, câu trả lời thực sự là nó phụ thuộc, và bạn có lẽ nên tránh nó và đặt câu hỏi về việc sử dụng OO nếu bạn đang làm điều này bằng cách thêm thuộc tính vào các phương pháp khác hoặc khởi tạo thuộc tính cho các giá trị tùy ý.

Trong khi Simeon Visser đang nói để giữ cho đối tượng của bạn ở trạng thái nhất quán, anh ta không có cơ sở cho sự nhất quán nào dựa trên ví dụ trừu tượng của bạn. Trong khi Pylint cảnh báo về loại điều này, cảnh báo từ các chương trình lint chỉ đơn giản là một người đánh giá cấp cao có thể được cảnh báo về những điều mà thường là chỉ ra mùi mã. Tôi nói người đánh giá cấp cao vì người đánh giá thực sự nên đọc và hiểu tất cả mã của bạn và do đó không thực sự cần Pylint.

Một ví dụ mà phá vỡ quy tắc của ngón tay cái:

class Mutant(object): 
    """A mutant!""" 

    def __init__(self): 
     """A mutant is born with only 1 eye and 1 mouth""" 

     self.eyes = 1 
     self.mouth = 1 
     self.location = 'Montana' 

    def roll_to(self, location): 
     """If they have limbs, running is less dangerous""" 

     if hasattr(self, 'limbs'): 
      print 'Your mutant broke its limbs off!!' 
      del self.limbs 

     self.location = location 

    def run_to(self, location): 
     """If they don't have limbs, running is not effective""" 

     if not hasattr(self, 'limbs'): 
      print 'Your mutant tries to run but he has no limbs.' 
     else: 
      self.location = location 

    def grow_limbs(self, number_of_limbs): 
     """Ah, evolution!""" 

     assert number_of_limbs > 0, 'Cannot grow 0 or less limbs...' 

     if hasattr(self, 'limbs'): 
      self.limbs += number_of_limbs 
     else: 
      self.limbs = number_of_limbs 
+0

Điểm tốt. Tôi đã nghĩ đến trường hợp một trong các biến thành viên là đầu ra của một hàm thành viên mà bạn muốn lưu trong đối tượng. Trong trường hợp này, biến chỉ có thể được khởi tạo với một giá trị thực sau khi hàm thành viên được gọi. – user1893354

+0

Vì vậy, hãy để tôi chắc chắn rằng tôi hiểu bạn một cách chính xác ... Ví dụ, một 'obj' có' output_complex_calculation', và bạn muốn 'obj.set_result_of_complex_calculation (obj.output_of_complex_calculation())' –

+0

ví dụ, nếu bạn có một lớp đó là một mô hình dự đoán mà người dùng nhập vào các tham số của mô hình lúc khởi tạo. Sau đó, người dùng gọi hàm .predict() để tạo danh sách các truy vấn dự đoán. Nhưng bạn sẽ muốn lưu các dự đoán này cho đối tượng này dưới dạng biến thành viên. Sau đó, có thể một số chức năng thành viên khác sẽ làm điều gì đó với biến thành viên dự đoán mới này. Vì vậy, trong trường hợp này, các giá trị thực cho biến thành viên dự đoán chỉ có thể được khởi tạo sau khi .predict() được gọi. – user1893354

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