Là mixins Python là một mô hình chống?


34

Tôi hoàn toàn biết rằng pylintvà các công cụ phân tích tĩnh khác không phải là tất cả, và đôi khi lời khuyên của họ phải không được tuân theo. (Điều này áp dụng cho các loại tin nhắn khác nhau, không chỉ conventions.)


Nếu tôi có lớp như

class related_methods():

    def a_method(self):
        self.stack.function(self.my_var)

class more_methods():

    def b_method(self):
        self.otherfunc()

class implement_methods(related_methods, more_methods):

    def __init__(self):
        self.stack  = some()
        self.my_var = other()

    def otherfunc(self):
        self.a_method()

Rõ ràng, đó là giả. Đây là một ví dụ tốt hơn, nếu bạn thích .

Tôi tin rằng phong cách này được gọi là sử dụng "mixins".

Giống như các công cụ khác, pylintđánh giá mã này -21.67 / 10, chủ yếu là vì nó nghĩ more_methodsrelated_methodskhông có selfhoặc thuộc tính otherfunc, stackmy_varvì không chạy mã, nó dường như không thể nhìn thấy related_methodsmore_methodsđược trộn lẫn vào implement_methods.

Trình biên dịch và các công cụ phân tích tĩnh không phải lúc nào cũng có thể giải quyết được vấn đề Ngừng , nhưng tôi cảm thấy đây chắc chắn là một trường hợp trong đó nhìn vào những gì được thừa hưởng implement_methodssẽ cho thấy điều này là hoàn toàn hợp lệ và đó là một điều rất dễ thực hiện.

Tại sao các công cụ phân tích tĩnh từ chối mẫu OOP hợp lệ (tôi nghĩ) này?

Hoặc:

  1. Họ thậm chí không thử kiểm tra thừa kế hoặc

  2. mixins không được khuyến khích trong Python thành ngữ, dễ đọc


# 1 rõ ràng là không chính xác bởi vì nếu tôi yêu cầu pylintcho tôi biết về một lớp của tôi thừa hưởng unittest.TestCaseviệc sử dụng đó self.assertEqual, (một cái gì đó chỉ được xác định trong unittest.TestCase), thì nó không phàn nàn.

Là mixin unpythonic hoặc không khuyến khích?


1
Đây có phải là một câu hỏi xấu? Là lạc đề? nó không thể trả lời Là tôi ngu ngốc? Mọi người có thể DV nhưng họ không muốn giúp cải thiện nó.
mèo

1
Có một số người có thể mệt mỏi khi có người hỏi "đây có phải là một mô hình (chống)" hay "đây là (không) pythonic".

9
@MichaelT Điều đó tốt. Họ có thể ngừng xem xét các câu hỏi sau đó.
Katana314

2
@tac mọi người sẽ downvote vì nhiều lý do, nhưng không bao giờ được yêu cầu tại sao - nút downvote có một mẹo công cụ nói rằng "câu hỏi này không cho thấy bất kỳ nỗ lực nghiên cứu nào; nó không rõ ràng hoặc không hữu ích" - một điều mơ hồ, nếu câu trả lời chấp nhận được. 8 lên và 1 xuống thực sự khá tốt, đặc biệt là về một câu hỏi, trong đó downvote là miễn phí. Đừng để nó làm bạn thất vọng. Chúc mừng.
Aaron Hall

@AaronHall Tôi biết mọi người được phép làm những gì họ thích với phiếu bầu của họ, thực sự tôi nói với những người dùng mới phàn nàn điều tương tự.
mèo

Câu trả lời:


16

Mixins không phải là trường hợp sử dụng được xem xét bởi công cụ. Điều đó không có nghĩa đó là một trường hợp sử dụng tồi, chỉ là một trường hợp không phổ biến đối với trăn.

Liệu mixin có được sử dụng phù hợp trong một trường hợp cụ thể hay không là một vấn đề khác. Loại chống trộn mixin mà tôi thấy thường xuyên nhất là sử dụng mixin khi chỉ có một ý định là một hỗn hợp. Đó chỉ là một cách vòng để che giấu một lớp thần. Nếu bạn không thể nghĩ ra một lý do ngay bây giờ để trao đổi hoặc loại bỏ một trong các mixin, thì đó không phải là một mixin.


Vâng, đó là một đối tượng thần, tôi thừa nhận. Trong trường hợp này, tôi cho rằng CPU ổn là một đối tượng thần.
con mèo

15

Tôi tin rằng Mixins hoàn toàn có thể là Pythonic. Tuy nhiên, cách thành ngữ để làm im lặng kẻ nói dối của bạn - và cải thiện khả năng đọc của Mixins - là cả hai (1) xác định các phương thức trừu tượng xác định rõ ràng các phương thức mà trẻ em Mixin cần phải thực hiện và (2) xác định trước NoneCác trường được định giá cho các thành viên dữ liệu Mixin mà trẻ phải khởi tạo.

Áp dụng mô hình này vào ví dụ của bạn:

from abc import ABC, abstractmethod


class related_methods():
    my_var = None
    stack = None

    def a_method(self):
        self.stack.function(self.my_var)


class more_methods(ABC):
    @abstractmethod
    def otherfunc(self):
        pass

    def b_method(self):
        self.otherfunc()


class implement_methods(related_methods, more_methods):
    def __init__(self):
        self.stack  = some()
        self.my_var = other()

    def otherfunc(self):
        self.a_method()

2
+1 cho câu trả lời của bạn, mặc dù abstract other(self): passđiều này đánh đổi sự nhầm lẫn của kẻ nói dối đối với tôi
con mèo

Nó thậm chí còn khó hiểu hơn nếu không có @ababmetmethod ;-) Tôi đã bắt đầu với Java trước vì vậy điều này rất tốt cho tôi.
Chris Huang-Leaver

9

Tôi nghĩ mixin có thể tốt, nhưng tôi cũng nghĩ pylint là đúng trong trường hợp này. Disclaimer: công cụ dựa trên ý kiến ​​sau.

Một lớp tốt, bao gồm mixins, có một trách nhiệm rõ ràng. Lý tưởng nhất, một mixin nên mang tất cả trạng thái mà nó sẽ truy cập và logic để xử lý nó. Ví dụ, một mixin tốt có thể thêm một last_updatedtrường vào lớp mô hình ORM, cung cấp logic để thiết lập nó và các phương thức để tìm kiếm bản ghi cũ nhất / mới nhất.

Đề cập đến các thành viên thể hiện không được khai báo (các biến và phương thức) có vẻ hơi lạ.

Cách tiếp cận đúng rất nhiều phụ thuộc vào nhiệm vụ trong tầm tay.

Nó có thể là một mixin với một chút trạng thái có liên quan được giữ trong đó.

Nó có thể là một hệ thống phân cấp lớp khác nhau trong đó các phương thức mà bạn hiện đang phân phối thông qua một mixin nằm trong một lớp cơ sở, trong khi các khác biệt triển khai ở cấp độ thấp hơn thuộc về các lớp con. Điều này có vẻ phù hợp nhất cho trường hợp của bạn với các hoạt động ngăn xếp.

Nó có thể là một trang trí lớp có thêm một hoặc hai phương thức; điều này thường có ý nghĩa khi bạn phải truyền một số đối số cho trình trang trí để ảnh hưởng đến việc tạo phương thức.

Nêu vấn đề của bạn, giải thích mối quan tâm thiết kế lớn hơn của bạn, sau đó chúng tôi có thể tranh luận nếu có gì đó là một mô hình chống trong trường hợp của bạn.


6

Kẻ nói dối không biết rằng bạn sử dụng một lớp làm mixin. Pylint nhận thức được rằng bạn sử dụng mixin nếu bạn thêm hậu tố 'mixin' hoặc 'Mixin' vào cuối tên lớp, sau đó kẻ nói dối ngừng phàn nàn.

linter_without_mixin linter2_with_mixin

Mixins không phải là xấu hay tốt, chỉ là một công cụ. Bạn làm cho họ sử dụng tốt hoặc sử dụng xấu.


2
cái này đọc giống như một bình luận, xem Cách trả lời
gnat

2
Đây là một câu trả lời có giá trị bởi vì tôi không nghĩ rằng mình đã từng biết về gợi ý đó
mèo

1

Mixin có ổn không?

Là mixins Python là một mô hình chống?

Mixins không được khuyến khích - chúng là một trường hợp sử dụng tốt cho nhiều kế thừa.

Tại sao kẻ nói dối của bạn phàn nàn?

Pylint rõ ràng phàn nàn vì nó không biết nơi otherfunc, stackmy_var đến từ.

Không đáng kể?

Không có lý do chính đáng rõ ràng nào ngay lập tức để bạn tách hai phương thức này thành các lớp cha riêng biệt, trong ví dụ của bạn trong câu hỏi hoặc trong ví dụ liên kết tầm thường hơn của bạn, được hiển thị ở đây.

201
202 class OpCore():
203     # nothing runs without these
204
205 class OpLogik(): 
206     # logic methods... 
207 
208 class OpString(): 
209     # string things
210 
211 
212 class Stack(OpCore, OpLogik, OpString): 
213 
214     "the mixin mixer of the above mixins" 

Chi phí mixin và tiếng ồn

Các chi phí của những gì bạn đang làm là làm cho báo cáo kẻ nói dối của bạn ồn ào. Tiếng ồn đó có thể che khuất các vấn đề quan trọng hơn với mã của bạn. Đây là một chi phí quan trọng để cân nhắc. Một chi phí khác là việc bạn tách mã liên quan đến các không gian tên khác nhau có thể khiến các lập trình viên khó khám phá ý nghĩa của nó hơn.

Phần kết luận

Kế thừa cho phép tái sử dụng mã. Nếu bạn nhận được tái sử dụng mã với mixins của mình, thật tuyệt, họ đã tạo ra giá trị cho bạn có thể vượt xa các chi phí khác có thể có. Nếu bạn không nhận được tái sử dụng / sao chép mã của các dòng mã, có lẽ bạn không nhận được nhiều giá trị cho mixins của mình và tại thời điểm đó, tôi nghĩ rằng chi phí của tiếng ồn lớn hơn lợi ích.


Có một lý do chính đáng để tách chúng trong ví dụ không liên kết - không dễ dàng hơn - tôi có thể tổ chức mã của mình dễ dàng hơn khi tôi có một phần của một lớp đầy đủ thực hiện toán học, một lớp khác thực hiện các chuỗi, v.v. và bạn trộn chúng lại với nhau để có được Forth Soup.
mèo

"Một chi phí khác là việc bạn tách mã của mình thành các không gian tên khác nhau có thể khiến các lập trình viên khó khám phá ý nghĩa của" - không, hoàn toàn không phải vậy. Các không gian tên lớp giúp dễ dàng hơn để biết một nhóm phương thức làm gì và khi ai đó muốn sử dụng ngăn xếp, họ nên gọi / thực hiện Forth Soup, chứ không phải các thành phần riêng lẻ
cat

@cat có thể vì chúng bị chiếm dụng và không được sử dụng trong một dự án lớn thực sự, không có ví dụ nào thực sự hỗ trợ các điểm sử dụng mixins của bạn. Cả hai chỉ hiển thị một lần mixin được sử dụng, trong trường hợp đó chỉ cần đặt việc thực hiện ở một nơi là phong cách và tổ chức tốt hơn. Bây giờ nếu bạn có thể hiển thị trường hợp bạn muốn các tính năng phổ biến trên các lớp nhưng không muốn có một lớp cơ sở chung, thì đó là nơi bạn sử dụng mixin. Đó là bên cạnh câu hỏi linting của bạn (UltraBird trả lời tốt đó). Nhưng điều này trả lời câu hỏi của bạn nói chung liên quan đến khả năng áp dụng mixin.
dlamblin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.