Apa arti pesan "Metode publik yang terlalu sedikit" dari pylint

110

Saya menjalankan pylint pada beberapa kode, dan menerima pesan kesalahan "Metode publik terlalu sedikit (0/2)". apa maksud dari pesan ini? Itu pylint tidak membantu:

Digunakan ketika kelas memiliki terlalu sedikit metode publik, jadi pastikan itu sangat berharga.

monsur
sumber
1
Seperti apa kelasmu? Apakah kelas melakukan hal lain selain menyimpan data?
Blender
1
Semua yang dilakukan kelas adalah menyimpan data.
monsur
2
Nah, itu masalahmu. Kelas tidak dimaksudkan untuk menyimpan data. Untuk itulah struktur data seperti kamus dan daftar digunakan.
Blender
Menarik, terima kasih! Pesan kesalahan pylint bisa dibuat lebih berguna. Bagaimanapun, jangan ragu untuk mengubah komentar Anda menjadi jawaban dan saya akan menyetujuinya.
monsur
6
Tapi dimana definisi "sedikit"? Saya punya satu metode. Itulah alasan mengapa kelas itu ada. Bagaimana pylint mendefinisikan "sedikit"? Lebih dari 2? Mengapa?
Zordid

Jawaban:

124

Kesalahan pada dasarnya mengatakan bahwa kelas tidak dimaksudkan untuk hanya menyimpan data, karena pada dasarnya Anda memperlakukan kelas sebagai kamus. Kelas harus memiliki setidaknya beberapa metode untuk mengoperasikan data yang mereka pegang.

Jika kelas Anda terlihat seperti ini:

class MyClass(object):
    def __init__(self, foo, bar):
        self.foo = foo
        self.bar = bar

Pertimbangkan untuk menggunakan kamus atau namedtuple gantinya. Meskipun jika suatu kelas tampaknya pilihan terbaik, gunakanlah. pylint tidak selalu tahu yang terbaik.

Perhatikan bahwa namedtupleitu tidak dapat diubah dan nilai yang ditetapkan pada instansiasi tidak dapat diubah nanti.

Blender
sumber
72
+1 untuk "pylint tidak tahu yang terbaik" - gunakan penilaian Anda sendiri tetapi sebagai aturan, jika yang Anda butuhkan adalah "struct", gunakan dictatau namedtuple. Gunakan kelas ketika Anda ingin menambahkan beberapa logika ke objek Anda (misalnya, Anda ingin hal-hal terjadi saat dibuat, Anda memerlukan beberapa hal khusus yang terjadi ketika ditambahkan, Anda ingin melakukan beberapa operasi padanya, mengontrol bagaimana ditampilkan, dll.)
Burhan Khalid
Terima kasih atas tanggapan mendetail! Kasus penggunaan saya mirip dengan yang disebutkan Burhan, saya melakukan beberapa pemrosesan pada data saat dibuat.
monsur
6
Kesalahan ini tidak masuk akal jika Anda memiliki Meta (metaclass) di dalam definisi kelas Anda.
alexander_ch
11
namedtuplemenyebalkan - selain memiliki sintaks yang jelek, Anda tidak dapat mendokumentasikannya atau memberikan nilai default dengan mudah.
rr-
6
Setiap kali saya menggunakannya, namedtuplesaya menyesali keputusan itu. Tidak konsisten untuk mengizinkan atribut akses bernama dan akses terindeks.
theorifice
39

Jika Anda memperluas kelas, saran saya adalah menonaktifkan peringatan ini secara sistematis dan melanjutkan, misalnya, dalam kasus tugas Celery:

class MyTask(celery.Task):  # pylint: disable=too-few-public-methods                                                                                   
    """base for My Celery tasks with common behaviors; extends celery.Task

    ...             

Bahkan jika Anda hanya memperluas satu fungsi, Anda pasti membutuhkan kelas untuk membuat fungsi teknik ini, dan memperluas jelas lebih baik daripada meretas kelas pihak ketiga!

Sage
sumber
Memiliki diable ini, pra-komit sekarang memberi saya: Nilai opsi buruk 'too-few-public-method' (nilai-opsi-buruk)
Mercury
Apakah Anda memasukkan metode 's'? Pesan nilai opsi-buruk Anda tidak memilikinya.
bijak
4
Mungkin cara yang lebih baik untuk menonaktifkannya adalah dengan mengatur min-public-methods=0di [BASIC]bagian file konfigurasi. Ini memungkinkan Anda meletakkannya di baris terpisah dari semua disable=barang Anda (di [MESSAGE CONTROL]) yang menurut saya mempermudah menambahkan komentar mendetail tentang mengapa Anda mengaktifkan dan menonaktifkan hal-hal bersama dengan perubahan konfigurasi.
cjs
15

Ini adalah kasus lain dari pylintaturan buta.

"Kelas tidak dimaksudkan untuk menyimpan data" - ini adalah pernyataan yang salah. Kamus tidak bagus untuk segalanya. Anggota data kelas adalah sesuatu yang berarti, item kamus adalah sesuatu yang opsional. Bukti: Anda dapat melakukannya dictionary.get('key', DEFAULT_VALUE)untuk mencegah KeyError, tetapi tidak ada yang sederhana __getattr__dengan default.

EDIT - cara yang disarankan untuk menggunakan struct

Saya perlu memperbarui jawaban saya. Sekarang - jika Anda membutuhkan filestruct , Anda memiliki dua opsi bagus:

a) Gunakan saja attrs

Ini adalah perpustakaan untuk itu:

https://www.attrs.org/en/stable/

import attr

@attr.s
class MyClass(object):  # or just MyClass: for Python 3
    foo = attr.ib()
    bar = attr.ib()

Apa yang Anda dapatkan ekstra: tidak menulis konstruktor, nilai default, validasi,, __repr__objek hanya-baca (untuk menggantinamedtuples , bahkan dengan Python 2) dan banyak lagi.

b) Gunakan dataclasses (Py 3.7+)

Mengikuti komentar hwjp, saya juga merekomendasikan dataclasses :

https://docs.python.org/3/library/dataclasses.html

Ini hampir sebagus attrs , dan merupakan mekanisme pustaka standar ("termasuk baterai"), tanpa ketergantungan tambahan, kecuali Python 3.7+.

Sisa jawaban Sebelumnya

NamedTupletidak bagus - terutama sebelum python 3 typing.NamedTuple: https://docs.python.org/3/library/typing.html#typing.NamedTuple - Anda harus memeriksa pola "kelas yang diturunkan dari NamedTuple". Python 2 -namedtuples dibuat dari deskripsi string - jelek, buruk dan "pemrograman di dalam string literal" bodoh.

Saya setuju dengan dua jawaban saat ini ("pertimbangkan untuk menggunakan sesuatu yang lain, tetapi pilint tidak selalu benar" - yang diterima, dan "gunakan komentar penekan pilek"), tetapi saya punya saran sendiri.

Izinkan saya menunjukkan ini sekali lagi: Beberapa kelas dimaksudkan hanya untuk menyimpan data.

Sekarang opsi untuk juga mempertimbangkan - gunakan property-ies.

class MyClass(object):
    def __init__(self, foo, bar):
        self._foo = foo
        self._bar = bar

    @property
    def foo(self):
        return self._foo

    @property
    def bar(self):
        return self._bar

Di atas Anda memiliki properti hanya-baca, yang OK untuk Objek Nilai (misalnya seperti yang ada di Desain Didorong Domain), tetapi Anda juga dapat menyediakan penyetel - dengan cara ini kelas Anda akan dapat mengambil tanggung jawab atas bidang yang Anda miliki - misalnya untuk melakukan beberapa validasi, dll. (jika Anda memiliki penyetel, Anda dapat menetapkan menggunakannya dalam konstruktor, yaitu self.foo = fooalih-alih langsung self._foo = foo, tapi hati-hati, penyetel mungkin menganggap bidang lain sudah diinisialisasi, dan kemudian Anda memerlukan validasi kustom dalam konstruktor) .

Tomasz Gandor
sumber
2
Di Python 3.7 dan yang lebih baru, dataclass memberikan solusi yang baik, menangani beberapa keburukan dari namaiuple, dan mereka sempurna untuk Objek Nilai DDD.
hwjp
Saya setuju, dan mulai tahun 2020 ini adalah cara standar untuk pergi. Untuk memiliki mekanisme jangkauan versi luas (2.7, 3.3+ jika saya ingat) Anda dapat menggunakan attrspustaka, yang sebenarnya merupakan cetak biru untuk membuat dataclassesmodul.
Tomasz Gandor
namedtuplesmemiliki sintaks aneh untuk pewarisan ... mengharuskan setiap kelas menggunakan satu untuk mengetahui bahwa itu adalah tuple bernama dan __new__bukan digunakan __init__. dataclassestidak memiliki batasan ini
Erik Aronesty
4

Sulit ketika atasan Anda mengharapkan prinsip tanggung jawab tunggal, tetapi pylint mengatakan tidak. Jadi tambahkan metode kedua ke kelas Anda sehingga kelas Anda melanggar prinsip tanggung jawab tunggal. Seberapa jauh Anda dimaksudkan untuk mengambil prinsip tanggung jawab tunggal ada di mata yang melihatnya.

Perbaikan saya,

Saya menambahkan metode tambahan ke kelas saya, jadi sekarang melakukan 2 hal.

def __str__(self):
    return self.__class__.__name__

Saya hanya ingin tahu apakah saya perlu membagi kelas saya menjadi 2 file terpisah sekarang, dan mungkin juga modul.

masalah terpecahkan, tetapi tidak dengan kolega saya yang menghabiskan sepanjang hari memperdebatkan spesifikasi, daripada melanjutkannya, seperti hidup dan mati.

Sean Bradley
sumber