2013-04-17 23 views
7

tôi đi qua sau trong python docs:Làm thế nào để python ngăn chặn một lớp được phân lớp?

bool ([x])

Chuyển đổi một giá trị cho một Boolean, sử dụng các thủ tục kiểm tra thật chuẩn. Nếu x là false hoặc bị bỏ qua, điều này trả về False; nếu không nó trả về True. bool cũng là một lớp, là một lớp con của int. Lớp bool không thể được phân lớp thêm. Các trường hợp duy nhất của nó là False và Đúng.

Tôi chưa bao giờ trong đời tôi muốn phân lớp bool, nhưng tự nhiên tôi ngay lập tức đã thử nó, và đủ chắc chắn:

>>> class Bool(bool): 
    pass 

Traceback (most recent call last): 
    File "<pyshell#2>", line 1, in <module> 
    class Bool(bool): 
TypeError: Error when calling the metaclass bases 
    type 'bool' is not an acceptable base type 

Vì vậy, câu hỏi: Làm thế nào là thực hiện? Và tôi có thể áp dụng cùng một kỹ thuật (hoặc một kỹ thuật khác) để đánh dấu các lớp của riêng tôi là final, tức là, để giữ cho chúng không bị phân loại?

+1

Tại sao bạn sẽ không muốn phải phân lớp 'bool'? Bạn có thể tạo các lớp con '10' để biểu diễn mỗi trạng thái boolean có thể có. – jamylak

+0

Cảm ơn @Martijn, trông giống như một câu hỏi liên quan chặt chẽ. Nó không xuất hiện trong quá trình tìm kiếm SO của tôi (tôi đã nghĩ nên thêm "final" vào các từ tìm kiếm). – alexis

Trả lời

13

Loại bool được xác định trong C và vị trí cố định tp_flags không bao gồm Py_TPFLAGS_BASETYPE flag.

Loại C cần đánh dấu chính mình là rõ ràng là làm lớp con.

Để làm điều này cho các lớp học tùy chỉnh Python, sử dụng một metaclass:

class Final(type): 
    def __new__(cls, name, bases, classdict): 
     for b in bases: 
      if isinstance(b, Final): 
       raise TypeError("type '{0}' is not an acceptable base type".format(b.__name__)) 
     return type.__new__(cls, name, bases, dict(classdict)) 

class Foo: 
    __metaclass__ = Final 

class Bar(Foo): 
    pass 

cho:

>>> class Bar(Foo): 
...  pass 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 5, in __new__ 
TypeError: type 'Foo' is not an acceptable base type 
+0

Cảm ơn, điều đó bao gồm nó! – alexis

+0

Trên phản ánh thêm, tôi có một câu hỏi: Có mục đích nào để kiểm tra 'isinstance (b, Final)'? Ý tôi là, '__new__' này sẽ chỉ được gọi bởi một lớp kế thừa từ 'Final', vậy tại sao không chỉ tăng ngay lập tức nếu' cls! =' Final''? – alexis

+0

@alexis: Có, bởi vì bạn cần phải đặt tên cho baseclass mà bạn đang cố gắng kế thừa từ đó. 'Bar' không phân lớp' Final', nó phân lớp 'Foo', đó là lý do tại sao phép thử' isinstance (b, Final) 'trả về' True' cho lớp đó. Nếu có nhiều lớp cơ sở được sử dụng, bạn muốn nói với người dùng cuối rằng một trong những cơ sở đó không thể kế thừa từ đó. –

Các vấn đề liên quan