Pertanyaan Python - semua variabel anggota harus diinisialisasi di __init__


Mungkin ini lebih merupakan pertanyaan gaya daripada yang teknis tapi saya memiliki kelas python dengan beberapa anggota variabel dan saya ingin memilikinya bekerja sehingga beberapa variabel anggota diinisialisasi ketika pengguna pertama kali membuat sebuah instance dari kelas (yaitu dalam __init__ function) dan saya ingin variabel anggota lain untuk didefinisikan dari argumen fungsi anggota yang akan dipanggil nanti. Jadi pertanyaan saya adalah saya harus menginisialisasi semua anggota variabel dalam __init__ fungsi (dan mengatur yang akan didefinisikan nanti ke nilai dummy) atau menginisialisasi beberapa di __init__ fungsi dan beberapa fungsi nanti. Saya menyadari ini mungkin sulit dimengerti jadi inilah beberapa contoh.

Contoh ini memiliki var3 set ke 0 awalnya di __init__ fungsi, lalu atur ke nilai yang diinginkan nanti di fungsi 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

dan dalam contoh ini, var3 tidak didefinisikan sama sekali dalam __init__ fungsi

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

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

Saya tidak berpikir cara yang baik akan membuat perbedaan besar (mungkin sedikit perbedaan dalam penggunaan memori). Tapi saya bertanya-tanya apakah salah satu dari ini lebih disukai daripada yang lain untuk beberapa alasan.


32
2017-12-18 14:58


asal


Jawaban:


Dalam pemrograman berorientasi obyek, terserah kepada pengembang untuk memastikan objek selalu dalam keadaan yang konsisten setelah instantiasi dan setelah metode selesai. Selain itu, Anda bebas mengembangkan kelas sesuai keinginan (dengan tetap memperhatikan prinsip-prinsip tertentu dengan subclassing / overriding dan sebagainya).

Alat seperti Pylint akan memperingatkan saat Anda menyetel variabel instan di luar __init__. Dapat dikatakan bahwa pengaturan semua variabel instan dalam __init__ lebih bersih tetapi bukan aturan yang harus dipatuhi setiap saat.


22
2017-12-18 15:01



Saya benar-benar akan mencegah variabel inisialisasi yang tidak selalu Anda perlukan __init__ ke nilai default yang berubah-ubah.

Saya mempertanyakan penggunaan OO Anda jika ini kasusnya, tapi saya yakin ada kasus yang valid dan dapat dimengerti di mana __init__ tidak akan melakukan semuanya, dan kelas akan ingin memodifikasi lebih lanjut dengan menambahkan atribut tambahan dengan metode lain.

Cara yang tepat menurut saya untuk menguji apakah suatu variabel ditetapkan saat menjalankan metode yang mungkin ingin menggunakannya akan digunakan hasattr. Ini dalam kasus ini adalah cara yang valid untuk menggunakan metode dan tes hanya mengubah perilaku dengan cara yang masuk akal.

Cara lain adalah dengan mencoba dan menggunakannya dan menangani pengecualian dan memberikan beberapa informasi yang ramah pengguna tentang apa yang dilakukan pengguna kelas Anda salah. Ini dalam kasus metode membutuhkan atribut yang harus diatur sebelum dijalankan.

Ya. Hei, Anda melakukan inisialisasi kelas, tetapi Anda perlu memastikan z atribut ada dengan memanggil z_init metode sebelum menjalankan z_run metode.

Cara lain, bisa dibilang yang lebih pythonic, adalah hanya mendokumentasikan bagaimana menggunakan metode dalam docstring dan kemudian membiarkan pengecualian terbang ketika digunakan dengan tidak semestinya. Ini cukup baik untuk implementasi pertama dari sesuatu dan Anda kemudian dapat fokus pada tugas berikutnya. Ini adalah situasi yang sama seperti di atas, metode ini membutuhkan atribut yang akan diatur.

Alasan saya tidak suka ide menginisialisasi variabel ke default sewenang-wenang adalah ini dapat membingungkan (karena itu sewenang-wenang) dan adalah derau garis.

Jika nilainya tidak sewenang-wenang dan hanya nilai default yang dapat diubah Anda harus menggunakan nilai default dalam __init__ metode yang dapat ditimpa. Ini juga bisa menjadi keadaan awal yang valid, yang juga tidak sewenang-wenang dan Anda harus mengaturnya di __init__ metode.

Jadi jawaban yang sebenarnya adalah tergantung, dan Anda mungkin harus menghindarinya dan mempertanyakan penggunaan OO Anda jika Anda melakukan ini dengan menambahkan atribut dalam metode lain atau menginisialisasi atribut ke nilai sewenang-wenang.

Sementara Simeon Visser mengatakan untuk menjaga objek Anda dalam keadaan yang konsisten, ia tidak memiliki dasar untuk konsistensi apa yang didasarkan pada contoh abstrak Anda. Sementara Pylint memperingatkan pada hal semacam ini, peringatan dari program lint hanya jadi peninjau tingkat tinggi dapat disiagakan tentang hal-hal yang biasanya menunjukkan bau kode. Saya mengatakan peninjau tingkat tinggi karena resensi nyata harus membaca dan memahami semua kode Anda, dan dengan demikian tidak benar-benar membutuhkan Pylint.

Contoh yang melanggar aturan praktis:

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

3
2017-12-18 15:54



Berikut adalah kutipan dari sololearn.com (situs gratis untuk mempelajari python)

"Properti menyediakan cara menyesuaikan akses ke atribut instan. Mereka dibuat dengan menempatkan dekorator properti di atas metode, yang berarti ketika atribut instan dengan nama yang sama dengan metode diakses, metode akan dipanggil sebagai gantinya.

Satu penggunaan umum properti adalah membuat atribut hanya-baca. "

Contoh (juga dari sololearn.com):

class Pizza:
    def __init__(self, toppings):
    self.toppings = toppings

    @property
    def pineapple_allowed(self):
       return False

   pizza = Pizza(["cheese", "tomato"])
   print(pizza.pineapple_allowed)
   pizza.pineapple_allowed = True

Hasil:

  >>>
 False
 AttributeError: can't set attribute
 >>>

Jika var3 bergantung pada var1 dan var2, Anda dapat melakukannya

class myClass:
    def __init__(self,var1,var2):
        self.var1=var1
        self.var2=var2
    @property
    def var3(self):
        return(self.var1+self.var2)  #var3 depends on var1 and var2
 m1=myClass(1,2)
 print(m1.var3)   # var3 is 3

var3 juga dapat diatur ke apa pun yang Anda inginkan menggunakan fungsi setter. Perhatikan bahwa Anda dapat menghindari pengaturan var3 ke nilai arbitrer dengan menggunakan None.

class myClass2(object):
    def __init__(self,var1,var2):
        self.var1=var1
        self.var2=var2
        self._var3=None     # None or an initial value that makes sense
        @property
        def var3(self):
            return(self._var3)
        @var3.setter
        def var3(self,value):
            self._var3=value
   m2=myClass(1,2)
   print(m2.var3)        # var3 is none
   print(m2.var3(10))    # var3 is set to 10 

0
2018-06-19 06:29