Saya tahu metode virtual dari PHP atau Java.
Bagaimana mereka bisa diimplementasikan dengan Python?
Atau haruskah saya mendefinisikan metode kosong dalam kelas abstrak dan menimpanya?
Jawaban:
Tentu, dan Anda bahkan tidak perlu mendefinisikan metode di kelas dasar. Dalam Python, metode lebih baik daripada virtual - metode ini benar-benar dinamis, karena pengetikan dengan Python adalah pengetikan bebek .
class Dog:
def say(self):
print "hau"
class Cat:
def say(self):
print "meow"
pet = Dog()
pet.say() # prints "hau"
another_pet = Cat()
another_pet.say() # prints "meow"
my_pets = [pet, another_pet]
for a_pet in my_pets:
a_pet.say()
Cat
dan Dog
di Python bahkan tidak harus diturunkan dari kelas dasar yang sama untuk mengizinkan perilaku ini - Anda mendapatkannya secara gratis. Meskipun demikian, beberapa programmer lebih memilih untuk mendefinisikan hierarki kelas mereka dengan cara yang lebih kaku untuk mendokumentasikannya dengan lebih baik dan menerapkan beberapa ketelitian pengetikan. Ini juga dimungkinkan - lihat misalnya abc
modul standar .
raise NotImplementedError()
Ini adalah pengecualian yang disarankan untuk dimunculkan pada "metode virtual murni" dari kelas dasar "abstrak" yang tidak mengimplementasikan metode.
https://docs.python.org/3.5/library/exceptions.html#NotImplementedError mengatakan:
Pengecualian ini berasal dari
RuntimeError
. Dalam kelas dasar yang ditentukan pengguna, metode abstrak harus memunculkan pengecualian ini ketika mereka membutuhkan kelas turunan untuk mengganti metode.
Seperti yang dikatakan orang lain, ini sebagian besar adalah konvensi dokumentasi dan tidak diperlukan, tetapi dengan cara ini Anda mendapatkan pengecualian yang lebih berarti daripada kesalahan atribut yang hilang.
Misalnya:
class Base(object):
def virtualMethod(self):
raise NotImplementedError()
def usesVirtualMethod(self):
return self.virtualMethod() + 1
class Derived(Base):
def virtualMethod(self):
return 1
print Derived().usesVirtualMethod()
Base().usesVirtualMethod()
memberikan:
2
Traceback (most recent call last):
File "./a.py", line 13, in <module>
Base().usesVirtualMethod()
File "./a.py", line 6, in usesVirtualMethod
return self.virtualMethod() + 1
File "./a.py", line 4, in virtualMethod
raise NotImplementedError()
NotImplementedError
Terkait: Apakah mungkin membuat kelas abstrak dengan Python?
Metode Python selalu virtual.
Sebenarnya, di versi 2.6 python menyediakan sesuatu yang disebut kelas dasar abstrak dan Anda dapat secara eksplisit mengatur metode virtual seperti ini:
from abc import ABCMeta
from abc import abstractmethod
...
class C:
__metaclass__ = ABCMeta
@abstractmethod
def my_abstract_method(self, ...):
Ia bekerja dengan sangat baik, asalkan kelas tersebut tidak mewarisi dari kelas yang sudah menggunakan metaclass.
Metode Python selalu virtual
seperti yang dikatakan Ignacio. Entah bagaimana, warisan kelas mungkin merupakan pendekatan yang lebih baik untuk menerapkan apa yang Anda inginkan.
class Animal:
def __init__(self,name,legs):
self.name = name
self.legs = legs
def getLegs(self):
return "{0} has {1} legs".format(self.name, self.legs)
def says(self):
return "I am an unknown animal"
class Dog(Animal): # <Dog inherits from Animal here (all methods as well)
def says(self): # <Called instead of Animal says method
return "I am a dog named {0}".format(self.name)
def somethingOnlyADogCanDo(self):
return "be loyal"
formless = Animal("Animal", 0)
rover = Dog("Rover", 4) #<calls initialization method from animal
print(formless.says()) # <calls animal say method
print(rover.says()) #<calls Dog says method
print(rover.getLegs()) #<calls getLegs method from animal class
Hasilnya harus:
I am an unknown animal
I am a dog named Rover
Rover has 4 legs
Sesuatu seperti metode virtual di C ++ (implementasi metode panggilan dari kelas turunan melalui referensi atau penunjuk ke kelas dasar) tidak masuk akal di Python, karena Python tidak memiliki pengetikan. (Saya tidak tahu bagaimana metode virtual bekerja di Java dan PHP.)
Tetapi jika yang Anda maksud dengan "virtual" adalah memanggil implementasi paling bawah dalam hierarki pewarisan, maka itulah yang selalu Anda dapatkan dengan Python, seperti yang ditunjukkan beberapa jawaban.
Hampir selalu ...
Seperti yang ditunjukkan dplamp, tidak semua metode dalam Python berperilaku seperti itu. Metode Dunder tidak. Dan menurut saya itu adalah fitur yang tidak begitu terkenal.
Pertimbangkan contoh buatan ini
class A:
def prop_a(self):
return 1
def prop_b(self):
return 10 * self.prop_a()
class B(A):
def prop_a(self):
return 2
Sekarang
>>> B().prop_b()
20
>>> A().prob_b()
10
Namun, pertimbangkan yang satu ini
class A:
def __prop_a(self):
return 1
def prop_b(self):
return 10 * self.__prop_a()
class B(A):
def __prop_a(self):
return 2
Sekarang
>>> B().prop_b()
10
>>> A().prob_b()
10
Satu-satunya hal yang kami prop_a()
ubah adalah membuat metode yang konyol.
Masalah dengan perilaku pertama adalah Anda tidak dapat mengubah perilaku prop_a()
di kelas turunan tanpa memengaruhi perilaku prop_b()
. Ini sangat bagus bicara oleh Raymond Hettinger memberikan contoh untuk kasus penggunaan di mana ini tidak nyaman.