Apakah campuran Python anti-pola?

34

Saya sepenuhnya menyadari hal itu pylintdan alat analisis statis lainnya tidak semuanya tahu, dan kadang-kadang saran mereka harus tidak taat. (Ini berlaku untuk berbagai kelas pesan, bukan hanya conventions.)


Jika saya punya kelas suka

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()

Jelas, itu dibuat-buat. Ini contoh yang lebih baik, jika Anda suka .

Saya percaya gaya ini disebut menggunakan "mixins".

Seperti alat-alat lain, pylinttingkat kode ini di -21.67 / 10, terutama karena berpikir more_methodsdan related_methodstidak memiliki selfatau atribut otherfunc, stack, annd my_varkarena tanpa menjalankan kode, itu tampaknya tidak bisa melihat related_methodsdan more_methodsdicampur-in ke implement_methods.

Kompiler dan alat analisis statis tidak selalu dapat menyelesaikan Masalah Pemutusan , tetapi saya merasa ini jelas merupakan kasus di mana melihat apa yang diwarisi oleh implement_methodsakan menunjukkan ini benar-benar valid, dan itu akan menjadi hal yang sangat mudah untuk dilakukan.

Mengapa alat analisis statis menolak pola OOP yang valid ini (menurut saya)?

Antara:

  1. Mereka bahkan tidak mencoba memeriksa warisan atau

  2. mixin tidak disarankan menggunakan Python idiomatis dan mudah dibaca


# 1 jelas salah karena jika saya meminta pylintuntuk memberi tahu saya tentang kelas saya yang mewarisi unittest.TestCaseyang menggunakan self.assertEqual, (sesuatu yang didefinisikan hanya dalam unittest.TestCase), itu tidak mengeluh.

Apakah mixin unpythonic atau berkecil hati?

kucing
sumber
1
Apakah ini pertanyaan yang buruk? Apakah di luar topik? apakah itu tidak bisa dijawab? Apakah saya bodoh? Orang dapat melakukan DV tetapi mereka tidak ingin membantu memperbaikinya.
kucing
1
Ada beberapa yang mungkin bosan meminta orang bertanya "apakah ini pola (anti-)" atau "apakah ini (tidak) pythonic".
9
@MichaelT Tidak apa-apa. Mereka dapat berhenti meninjau pertanyaan itu.
Katana314
2
Orang @tac akan downvote karena berbagai alasan, tetapi tidak pernah diminta untuk mengatakan mengapa - tombol downvote memiliki tip alat yang mengatakan, "pertanyaan ini tidak menunjukkan upaya penelitian apa pun; tidak jelas atau tidak berguna" - tidak jelas, jika jawaban yang bisa diterima. 8 naik dan turun 1 sebenarnya cukup bagus, terutama pada pertanyaan, di mana downvotes gratis. Jangan biarkan itu membuat Anda kecewa. Tepuk tangan.
Aaron Hall
@ AaronHall Saya sadar orang diizinkan melakukan apa yang mereka suka dengan suara mereka, memang saya memberi tahu pengguna baru yang mengeluh hal yang sama.
kucing

Jawaban:

16

Mixin bukan kasus penggunaan yang dianggap oleh alat. Itu tidak berarti itu kasus penggunaan yang buruk, hanya yang tidak umum untuk python.

Apakah mixin digunakan secara tepat dalam contoh tertentu adalah masalah lain. Anti-pola mixin yang paling sering saya lihat adalah menggunakan mixin ketika hanya ada satu kombinasi yang dimaksudkan. Itu hanya jalan memutar untuk menyembunyikan kelas dewa. Jika Anda tidak dapat memikirkan alasan saat ini untuk menukar atau mengabaikan salah satu mixin, itu seharusnya bukan mixin.

Karl Bielefeldt
sumber
ya, saya akui itu objek dewa. Dalam hal ini saya berpendapat bahwa OK untuk CPU menjadi objek dewa.
kucing
15

Saya percaya bahwa Mixin dapat, tentu saja, Pythonic. Namun, cara idiomatis untuk membungkam virus Anda - dan meningkatkan keterbacaan Mixins Anda - adalah untuk keduanya (1) mendefinisikan metode abstrak yang secara eksplisit menentukan metode yang harus diterapkan oleh anak-anak Mixin, dan (2) pra-definisi Nonebidang-nilai untuk anggota data Mixin bahwa anak-anak harus menginisialisasi.

Menerapkan pola ini pada contoh Anda:

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()
UltraBird
sumber
2
+1 untuk jawaban Anda, meskipun barang abstract other(self): passitu memperdagangkan kebingungan orang lain untuk saya
cat
Ini bahkan lebih membingungkan tanpa @abstractmethod ;-) Saya mulai dengan Java terlebih dahulu jadi ini tidak masalah bagi saya.
Chris Huang-Leaver
9

Saya pikir mixin bisa baik, tetapi saya juga berpikir pylint benar dalam hal ini. Penafian: hal-hal berdasarkan opini berikut.

Kelas yang baik, termasuk mixin, memiliki satu tanggung jawab yang jelas. Idealnya, mixin harus membawa semua status yang akan diakses, dan logika untuk menanganinya. Misalnya mixin yang baik dapat menambahkan last_updatedbidang ke kelas model ORM, memberikan logika untuk pengaturannya, dan metode untuk mencari catatan tertua / terbaru.

Mengacu pada anggota instance yang tidak dideklarasikan (variabel dan metode) memang terlihat sedikit aneh.

Pendekatan yang tepat sangat tergantung pada tugas yang dihadapi.

Ini mungkin mixin dengan bit relevan dari negara yang disimpan di dalamnya.

Ini mungkin hierarki kelas yang berbeda di mana metode yang saat ini Anda distribusikan melalui mixin berada di kelas dasar, sementara perbedaan implementasi tingkat yang lebih rendah milik subkelas. Ini terlihat paling cocok untuk kasus Anda dengan operasi stack.

Ini mungkin dekorator kelas yang menambahkan satu atau dua metode; ini biasanya masuk akal ketika Anda harus memberikan beberapa argumen kepada dekorator untuk memengaruhi pembuatan metode.

Nyatakan masalah Anda, jelaskan masalah desain Anda yang lebih besar, maka kami dapat berdebat jika ada sesuatu yang anti-pola dalam kasus Anda.

9000
sumber
6

Linter tidak sadar bahwa Anda menggunakan kelas sebagai mixin. Pylint sadar bahwa Anda menggunakan mixin jika Anda menambahkan akhiran 'mixin' atau 'Mixin' di akhir nama kelas, maka linter berhenti mengeluh.

linter_without_mixins linter2_with_mixin

Mixin tidak buruk atau bagus, hanya alat. Anda menjadikannya sebagai penggunaan yang baik atau penggunaan yang buruk.

dotoscat
sumber
2
ini berbunyi lebih seperti komentar, lihat Bagaimana Menjawab
nyamuk
2
ini adalah jawaban yang berharga karena saya rasa saya tidak akan pernah tahu tentang petunjuk itu sebaliknya
cat
1

Apakah mixin oke?

Apakah campuran Python anti-pola?

Mixin tidak disarankan - mereka adalah use-case yang bagus untuk multiple inheritance.

Mengapa linter Anda mengeluh?

Pylint jelas mengeluh karena tidak tahu di mana otherfunc, stackdan my_var berasal.

Sepele?

Tidak ada alasan langsung yang jelas bagi Anda untuk memisahkan kedua metode ini ke dalam kelas induk yang terpisah, baik dalam contoh Anda dalam pertanyaan, atau dalam contoh terkait Anda yang lebih sepele, yang ditunjukkan di sini.

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" 

Biaya mixin dan kebisingan

Biaya dari apa yang Anda lakukan adalah membuat laporan laporan Anda berisik. Kebisingan itu dapat mengaburkan masalah yang lebih penting dengan kode Anda. Ini adalah biaya penting untuk menimbang. Biaya lain adalah bahwa Anda memisahkan kode yang saling terkait menjadi ruang nama yang berbeda yang dapat mempersulit programmer untuk menemukan artinya.

Kesimpulan

Warisan memungkinkan penggunaan kembali kode. Jika Anda mendapatkan kode yang dapat digunakan kembali dengan mixin Anda, hebat, mereka telah menciptakan nilai untuk Anda yang mungkin lebih besar daripada kemungkinan biaya lainnya. Jika Anda tidak mendapatkan penggunaan kembali / deduplikasi baris kode, Anda mungkin tidak mendapatkan banyak nilai untuk mixin Anda, dan pada saat itu, saya pikir biaya kebisingan lebih besar daripada manfaatnya.

Aaron Hall
sumber
Ada alasan yang baik untuk memisahkan mereka dalam contoh yang ditautkan dan tidak terkait - lebih mudah bagi saya untuk mengatur kode saya ketika saya memiliki sebagian kecil dari kelas penuh yang mengimplementasikan matematika, yang lain yang menerapkan string, dan seterusnya, dan Anda mencampurnya bersama-sama untuk mendapatkan Sup Keempat.
kucing
"Biaya lain adalah Anda memisahkan kode Anda menjadi ruang nama yang berbeda yang dapat mempersulit programmer untuk menemukan arti" - tidak, sama sekali tidak demikian. Ruang nama kelas memudahkan untuk mengetahui apa yang dilakukan sekelompok metode, dan ketika seseorang ingin menggunakan tumpukan, mereka harus memanggil / mengimplementasikan Sup Keempat, bukan bahan
cat
@cat mungkin karena mereka dibuat dan tidak digunakan dalam proyek besar yang nyata, tidak ada contoh yang benar-benar mendukung poin Anda menggunakan mixin. Keduanya hanya menunjukkan satu kali mixin digunakan, dalam hal ini hanya menempatkan implementasi di satu tempat adalah gaya dan organisasi yang lebih baik. Sekarang jika Anda bisa menunjukkan case di mana Anda ingin fitur-fitur umum di seluruh kelas tetapi tidak ingin kelas dasar yang umum, di situlah Anda akan menggunakan mixin. Yang mana di samping pertanyaan linting Anda (UltraBird menjawab dengan baik). Tapi ini menjawab pertanyaan Anda secara umum mengenai penerapan mixin.
dlamblin