Làm cách nào để kiểm tra (trong thời gian chạy) nếu một lớp là lớp con của lớp khác?


195

Hãy nói rằng tôi có một Bộ đồ lớp và bốn lớp phù hợp: Trái tim, Spade, Kim cương, Câu lạc bộ.

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

Tôi có một phương thức nhận một bộ quần áo làm tham số, đó là một đối tượng lớp, không phải là một thể hiện. Chính xác hơn, nó chỉ có thể nhận được một trong bốn giá trị: Heart, Spade, Diamond, Club. Làm thế nào tôi có thể đưa ra một khẳng định đảm bảo một điều như vậy? Cái gì đó như:

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

Tôi đang sử dụng Python 3.


1
@Leopd: Có thực sự không rõ ràng? Tôi đã tuyên bố chính xác bốn giá trị my_methodcó thể có thể nhận làm tham số là gì: "nó chỉ có thể nhận được một trong bốn giá trị: Heart, Spade, Diamond, Club". Các giá trị này là các đối tượng lớp, không phải là các thể hiện của lớp. Nó có vẻ khá rõ ràng đối với tôi, mặc dù tôi cho rằng bạn đúng về sự mơ hồ bởi vì các câu trả lời bao gồm cả hai khả năng. Bạn rất sẵn lòng chỉnh sửa câu hỏi nếu bạn có một câu nói rõ ràng hơn cho nó. Cảm ơn các bình luận.
snakile

@snakile vâng không rõ. Do dựa vào tính chính xác của biểu hiện bản thân của bất kỳ ai là băng mỏng trong chủ đề này. Nhiều người mới không thể có được thứ gì đó là vật thể trong một con trăn, có thể bày tỏ một điều nhưng lại nghĩ khác. Đó là một thực tế và, thuần túy sang một bên, thật hợp lý khi mong đợi hành vi này từ những người mới đến. Để lại danh tiếng của bạn chỉ là gợi ý trực tiếp duy nhất cho dù biểu hiện của bạn ở đây là chính xác hay tôi nên nói, "về mặt chính xác". Tôi hiểu mong muốn đưa kiến ​​thức của bạn vào tài khoản và vẫn không hợp lý nếu không tính đến những người mới luôn đổi mới.
n611x007

1
@snakile đó, và điều hợp lý là sử dụng quy ước đặt tên có hậu tố như vậy với tên tham số _class, làm cho chúng thích suit_class. Tôi đã đề xuất một quy ước đặt tên như vậy trong một câu hỏi có liên quan .
n611x007

Đề nghị thêm vào mã ví dụ bốn dòng my_method(Heart) my_method(Spade)...
Bob Stein

Đối với các trường hợp biến được kiểm tra không được đảm bảo là một lớp, bạn có thể thêm một điều kiện trên inspect.isclasshoặc chỉ đơn giản là sử dụng isinstance(myvar, type)trong Python 3, vì issubclasssẽ gây ra lỗi nếu nó vượt qua một lớp không. Xem câu trả lời này . Tôi đã nhận xét về câu trả lời dưới đây, nhưng nó sẽ không bao giờ nhìn thấy ánh sáng trong ngày.
Totalhack

Câu trả lời:


223

Bạn có thể sử dụng issubclass()như thế này assert issubclass(suit, Suit).


55
"Nhưng tại sao bạn lại muốn làm một việc như vậy?" - bởi vì bạn có một lớp container mà bạn cần đảm bảo là đồng nhất, và cách duy nhất để làm điều đó là kiểm tra loại khi chèn?
Adam Parkin

139
Nếu có một điều không đổi trên Stack Overflow, thì đó là bất kỳ câu hỏi nào có câu trả lời ngụ ý là đẳng cấp hoặc hiện tại cũng sẽ được kèm theo các bài giảng về cách gõ vịt!
Ben Roberts

26
Tôi đã bắt gặp câu hỏi này khi cố gắng tìm ra cách phát hiện xem dtype numpy của tôi là float hay int cho một ứng dụng xử lý ảnh. Nếu đó là một float, quy ước là bình thường hóa giữa 0,0 và 1,0, nếu đó là int thì quy ước là 0 đến 255. Tôi có thể trải qua tất cả các loại hình để thử và làm cho hình ảnh bị phá vỡ, nhưng nó thẳng hơn nhiều chỉ cần hỏi "bạn có phải là một con vịt" và mở rộng quy mô hoạt động của tôi cho phù hợp.
xông hơi

28
Kiểm thử phân lớp giúp kiểm thử đơn vị nhiều thứ, đặc biệt là các mẫu của Django, dễ dàng hơn nhiều. "Python không phải là Java." Tại sao các lập trình viên python phải có những con chip như vậy trên vai?
Michael Bacon

20
Không nâng cao, hoàn toàn là vì nhận xét không tưởng tượng và khá kiêu ngạo ở cuối. Một lời giải thích về lý do tại sao một người có thể không cần phải làm điều này sẽ thân thiện và hữu ích hơn.
Michael Scheper


26

Bạn có thể sử dụng isinstancenếu bạn có một thể hiện hoặc issubclassnếu bạn có một lớp. Thông thường nghĩ rằng đó là một ý tưởng tồi. Thông thường trong Python bạn làm việc nếu một đối tượng có khả năng làm điều gì đó bằng cách cố gắng làm điều đó với nó.


Điều gì nếu bạn phát hiện ra bạn không thể làm điều đó với nó? Bạn có bắt một ngoại lệ và thử một cái gì đó khác?
tên người dùng sai

2
@wrongusername: Đó là cách 'Pythonic', vâng. Tôi nghĩ rằng tùy chỉnh này có giá trị, vì vậy tôi tuân theo nó miễn là nó giữ cho mã của tôi rõ ràng. Có một cuộc thảo luận tốt về vấn đề này ở đây: stackoverflow.com/questions/7604636/
Kẻ

8
@Michael Scheper: Tôi phải nói rằng, nếu đó là cách pythonic, thì tôi thực sự ghét cách pythonic. IMO, ngoại lệ KHÔNG BAO GIỜ được sử dụng cho luồng điều khiển. Nếu bạn nghĩ rằng một lỗi có thể xảy ra, hãy bảo vệ chống lại nó ... đừng coi nó như một GOTO. Tuy nhiên, liên kết thú vị mà bạn đã đăng
leviathanbadger

@ trênyou00: Âm thanh giống như trường hợp bạn đang nói về việc vi phạm 'miễn là nó giữ cho mã của tôi rõ ràng'. Tuy nhiên, tôi không phải là người hâm mộ tất cả các phong tục của Pythonic, vì rất nhiều người lạm dụng nguyên tắc EAFP và cuối cùng tạo ra các lỗi khó tìm.
Michael Scheper

Kiểm tra này có ích khi xác định hợp đồng. Ví dụ, một hàm tạo nhận được một đối tượng: chúng tôi muốn khẳng định rằng đối tượng nhận được là một thể hiện của một lớp nhất định và bằng cách đó, chúng tôi thông báo cho người đọc mã những gì nhà xây dựng mong đợi.
mastropi

21

Hàm issubclass(sub, sup)boolean trả về true nếu lớp con đã cho subthực sự là lớp con của lớp cha sup.


9
Câu trả lời không có bài giảng sai.
Gringo Suave

2

issubclass ví dụ runnable tối thiểu

Dưới đây là một ví dụ đầy đủ hơn với một số xác nhận:

#!/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 ngược dòng .

Đã thử nghiệm trong Python 3.5.2.


1

Bạn có thể sử dụng lớp dựng sẵn. Nhưng kiểm tra kiểu thường được xem là không cần thiết bởi vì bạn có thể sử dụng gõ vịt.


1

Sử dụng ngay bây giờ có vẻ như là một cách sạch để viết loglevels. Nó cảm thấy kỳ lạ khi sử dụng nó ... nhưng nó có vẻ sạch hơn các tùy chọn khác.

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

Theo tài liệu Python , chúng ta cũng có thể sử dụng class.__mro__thuộc tính hoặc class.mro()phương thức:

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
Câu trả lời chỉ mã không được đánh giá cao trên SO, bạn nên luôn luôn thêm một số văn bản giải thích vào mã. Tuy nhiên, câu trả lời này là không cần thiết: nó không thêm thông tin nào chưa được đề cập trong các câu trả lời trước.
PM 2Ring
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.