Bir sınıfın diğerinin alt sınıfı olup olmadığını nasıl kontrol edebilirim (çalışma zamanında)?


197

Diyelim ki bir takım elbisem ve dört takım elbisem var: Heart, Spade, Diamond, Club.

class Suit:
   ...
class Heart(Suit):
   ...
class Spade(Suit):
   ...
class Diamond(Suit):
   ...
class Club(Suit):
   ...

Bir örnek, bir sınıf nesnesi olan bir parametre olarak bir takım alır bir yöntem var. Daha doğrusu, dört değerden sadece birini alabilir: Kalp, Maça, Elmas, Kulüp. Böyle bir şeyi sağlayan bir iddiayı nasıl yapabilirim? Gibi bir şey:

def my_method(suit):
   assert(suit subclass of Suit)
   ...

Python 3 kullanıyorum.


1
@Leopd: Gerçekten net değil mi? my_methodParametreler olarak alabilecek olası dört değerin tam olarak ne olduğunu söyledim : "dört değerden sadece birini alabilir: Kalp, Maça, Elmas, Kulüp". Bu değerler sınıf örnekleri değil, sınıf nesnesidir. Benim için oldukça açık görünüyor, ancak muğlaklık konusunda haklı olduğunu düşünüyorum, çünkü cevaplar her iki olasılığı da kapsıyor. Daha net bir ibadetiniz varsa soruyu düzenlemekten memnuniyet duyarız. Yorum için teşekkürler.
snakile

@snakile evet belli değil. Kimsenin kendini ifade etmesinin doğruluğuna güvenmesi nedeniyle bu konuda ince buz var. Pek çok yeni gelen, python'da bir nesne olan her şeyi elde edemez, bir şeyi ifade edebilir, başka bir şeyi düşünebilir. Bu bir gerçeklik ve saflık bir yana, bu davranışı yeni gelenlerden beklemek oldukça mantıklı. İtibar puanları sadece doğrudan bırakarak ipucu ifadeniz burada doğrudur, yoksa "doğruluk açısından" derler gerekip gerekmediğini. Bilginizi dikkate alma arzusunu anlıyorum ve sürekli yenilenen yeni gelenleri hesaba katmamak hala mantıksız.
n611x007

1
O @snakile ve şey böyle parametre adları soneklerden bir adlandırma kuralı kullanmak mantıklı olabilir _classgibi bunları yaparken, suit_class. Ben önerdi böyle bir adlandırma kuralı alakalı sorulardan .
n611x007

Örnek koduna dört satır eklemenizi my_method(Heart) my_method(Spade)
Bob Stein

Test edilen değişkenin bir sınıf olduğu garanti edilmediğinde, sınıf dışı geçilirse bir hata oluşturacağından Python 3'te bir koşul ekleyebilir inspect.isclassveya isinstance(myvar, type)Python 3'te kullanabilirsiniz issubclass. Bu cevaba bakınız . Aşağıdaki cevap hakkında yorum yapardım, ama gün ışığını asla göremezdim.
totalhack

Yanıtlar:


225

Sen kullanabilirsiniz issubclass()böyle assert issubclass(suit, Suit).


55
"Ama neden böyle bir şey yapmak istesin?" - çünkü homojen olduğundan emin olmanız gereken bir kap sınıfınız var ve bunu yapmanın tek yolu kesici uç üzerine tipi kontrol etmektir?
Adam Parkin

140
Yığın Taşması üzerinde sabit olan bir şey varsa, isinstance veya issubclass anlamına gelen herhangi bir soruya ördek yazmayla ilgili dersler de eşlik edecek!
Ben Roberts

26
Numpy dtype'imin bir görüntü işleme uygulaması için bir float veya int olup olmadığını nasıl anlayacağımı anlamaya çalışırken bu soruya rastladım. Eğer bir şamandıra ise, kural 0.0 ile 1.0 arasında normalleşmektir, eğer int ise konvansiyon 0 ila 255'tir. Görüntüyü çakmak için denemek için her türlü bükülmeden geçebilirim, ancak "ördek misin" diye sor ve operasyonlarımı buna göre ölçeklendir.
Omegaman

28
Alt sınıf testi, özellikle Django'nun modelleri olmak üzere birçok şeyin birim testini kolaylaştırır. "Python Java değil." Python programcılarının neden omuzlarında bu tür çipler olması gerekir?
Michael Bacon

20
Sonunda hayal gücünden yoksun ve oldukça kibirli bir söz nedeniyle yukarı doğru değil. Birinin bunu yapması gerekmeyebileceğine dair bir açıklama daha dostça ve daha yararlı olacaktır.
Michael Scheper


26

Sen kullanabilirsiniz isinstanceEğer bir örneğini varsa ya issubclasssen bir sınıf varsa. Normalde bunun kötü bir fikir olduğunu düşündüm. Normalde Python'da, bir nesne bu şeyi yapmaya çalışarak bir şey yapabiliyorsa çalışırsınız.


Ya o şeyi onunla yapamayacağını öğrenirsen? Bir istisna yakalayıp başka bir şey deniyor musunuz?
yanlış kullanıcı adı

2
@ yanlış kullanıcı adı: Bu 'Pitonik' yol, evet. Ben bu özel liyakat olduğunu düşünüyorum, bu yüzden sürece benim kod açık tutar takip. Burada bu konuda iyi bir tartışma var: stackoverflow.com/questions/7604636/…
Michael Scheper

8
@Michael Scheper: Şunu söylemeliyim ki, eğer bu pythonic bir yolsa, o zaman pythonic bir yoldan gerçekten nefret ederim. IMO, kontrol akışı için ASLA istisnalar kullanılmamalıdır. Bir hatanın oluşabileceğini düşünüyorsanız, buna karşı koruyun ... bir GOTO gibi davranmayın. Yine de yayınladığınız ilginç bağlantı
leviathanbadger

@ aboveyou00: Bahsettiğiniz davalar 'kodumu açık tuttuğu sürece' ihlal ediyor gibi görünüyor. Yine de birçok Pythonic geleneğinin hayranı değilim, çünkü birçok insan EAFP ilkesini kötüye kullanıyor ve bulunması zor hatalar oluşturuyor.
Michael Scheper

Bu kontrol, sözleşmeleri tanımlarken kullanışlı olur. Örneğin, bir nesneyi alan bir kurucu: alınan nesnenin belirli bir sınıfın örneği olduğunu iddia etmek istiyoruz ve böylece kod okuyucusuna kurucunun ne beklediğini bildiririz.
mastropi

21

issubclass(sub, sup)Verilen alt sınıf ise boole fonksiyonu true döndürür subgerçekten üst sınıf bir alt sınıfıdır sup.


9
Yanlış yönlendirilmiş ders olmayan cevap +1.
Gringo Suave

2

issubclass minimal çalıştırılabilir örnek

İşte bazı iddialarla daha eksiksiz bir örnek:

#!/usr/bin/env python3

class Base:
    pass

class Derived(Base):
    pass

base = Base()
derived = Derived()

# Basic usage.
assert issubclass(Derived, Base)
assert not issubclass(Base, Derived)

# True for same object.
assert issubclass(Base, Base)

# Cannot use object of class.
try:
    issubclass(derived, Base)
except TypeError:
    pass
else:
    assert False

# Do this instead.
assert isinstance(derived, Base)

GitHub akış yukarı .

Python 3.5.2'de test edilmiştir.


1

Yerleşik issubclass'ı kullanabilirsiniz. Ancak yazım denetimini kullanabileceğiniz için tür denetimi genellikle gereksiz olarak görülür.


1

İssubclass kullanmak loglevels yazmak için temiz bir yol gibi görünüyordu. Bunu kullanmak biraz garip geliyor ... ama diğer seçeneklerden daha temiz görünüyor.

class Error(object): pass
class Warn(Error): pass
class Info(Warn): pass
class Debug(Info): pass

class Logger():
    LEVEL = Info

    @staticmethod
    def log(text,level):
        if issubclass(Logger.LEVEL,level):
            print(text)
    @staticmethod
    def debug(text):
        Logger.log(text,Debug)   
    @staticmethod
    def info(text):
        Logger.log(text,Info)
    @staticmethod
    def warn(text):
        Logger.log(text,Warn)
    @staticmethod
    def error(text):
        Logger.log(text,Error)

0

Göre Python doc , biz de kullanabilir class.__mro__Özellik veya class.mro()yöntem:

class Suit:
    pass
class Heart(Suit):
    pass
class Spade(Suit):
    pass
class Diamond(Suit):
    pass
class Club(Suit):
    pass

>>> Heart.mro()
[<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>]
>>> Heart.__mro__
(<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>)

Suit in Heart.mro()  # True
object in Heart.__mro__  # True
Spade in Heart.mro()  # False

-5
#issubclass(child,parent)

class a:
    pass
class b(a):
    pass
class c(b):
    pass

print(issubclass(c,b))#it returns true

1
Yalnızca kod yanıtları SO'da takdir edilmez, koda her zaman açıklayıcı bir metin eklemelisiniz. Ancak, bu cevap gereksizdir: önceki cevaplarda daha önce belirtilmemiş hiçbir bilgi eklemez.
PM 2Ring
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.