2016-03-06 43 views
15

Xuất phát từ Java, tôi đang gặp khó khăn trong việc nhận thừa kế, lớp trừu tượng, phương thức tĩnh và khái niệm tương tự về lập trình OO bằng Python.Python 3: super() tăng TypeError bất ngờ

Tôi có một thực hiện của một lớp cây biểu thức, nhất định (giản thể) bởi

# Generic node class 
class Node(ABC): 
    @abstractmethod 
    def to_expr(self): 
     pass 

    @staticmethod 
    def bracket_complex(child): 
     s = child.to_expr() 
     return s if isinstance(child, Leaf) or isinstance(child, UnaryOpNode) else "(" + s + ")" 


# Leaf class - used for values and variables 
class Leaf(Node): 
    def __init__(self, val): 
     self.val = val 

    def to_expr(self): 
     return str(self.val) 


# Unary operator node 
class UnaryOpNode(Node): 
    def __init__(self, op, child): 
     self.op = op 
     self.child = child 

    def to_expr(self): 
     return str(self.op) + super().bracket_complex(self.child) 


# Binary operator node 
class BinaryOpNode(Node): 
    def __init__(self, op, lchild, rchild): 
     self.op = op 
     self.lchild = lchild 
     self.rchild = rchild 

    def to_expr(self): 
     return super().bracket_complex(self.lchild) + " " + str(self.op) + " " + super().bracket_complex(self.rchild) 


# Variadic operator node (arbitrary number of arguments) 
# Assumes commutative operator 
class VariadicOpNode(Node): 
    def __init__(self, op, list_): 
     self.op = op 
     self.children = list_ 

    def to_expr(self): 
     return (" " + str(self.op) + " ").join(super().bracket_complex(child) for child in self.children) 

Phương pháp to_expr() hoạt động tốt khi kêu gọi các trường hợp Leaf, UnaryOpNodeBinaryOpNode, nhưng đặt ra một TypeError khi kêu gọi một thể hiện của VariadicOpNode:

TypeError: super(type, obj): obj must be an instance or subtype of type 

tôi đang làm gì sai ở chỗ lớp cụ thể mà super() là đột nhiên không wo rking?

Trong Java, phương pháp tĩnh sẽ được kế thừa vì vậy tôi thậm chí sẽ không cần cuộc gọi siêu, nhưng trong Python, điều này có vẻ không phải như vậy.

+0

bạn đang sử dụng Python2 hay 3? https://docs.python.org/2/library/functions.html#super – Jasper

+0

@Jasper Vì anh ấy đang sử dụng 'super' mà không có đối số, anh ta đang sử dụng python3.3 + Tôi tin. – Bakuriu

+0

Tắt chủ đề: tại sao bạn sử dụng 'super()' trong 'to_expr' để gọi' bracket_complex'? Bạn nên sử dụng 'self', nếu không bạn có nguy cơ giới thiệu các vấn đề trong các lớp con ghi đè' bracket_complex' –

Trả lời

12

Bạn đang sử dụng super() không có đối số trong biểu thức trình tạo. super() là phép thuật - nó dựa trên thông tin trong khung người gọi. Vì biểu thức trình tạo ra một hàm bổ sung, super() không có đối số không hoạt động ở đó. Tuy nhiên kể từ khi cha của bạn là không thể xảy ra để thay đổi ở giữa thực hiện một phương pháp, bạn có thể di chuyển nó ra khỏi khái niệm máy phát điện - điều này cũng nên điều tốc độ lên:

def to_expr(self): 
    bracket_complex = super().bracket_complex 
    return (" " + str(self.op) + " ").join(bracket_complex(child) for child in self.children) 

Tuy nhiên như các phương pháp tĩnh là " được kế thừa "bằng Python, bạn có thể gọi phương thức siêu thông qua self miễn là bạn không ghi đè lên nó trong một lớp con. Như vậy trong trường hợp đơn giản này, bạn có thể viết:

def to_expr(self): 
    return (" " + str(self.op) + " ").join(self.bracket_complex(child) for child in self.children) 

Các chi tiết thi hành là nếu không có đối số được cung cấp, các đối số đầu tiên sẽ là giá trị mà là trong __class__ tế bào của khung người gọi, và thứ hai sẽ là đối số đầu tiên được đưa ra cho hàm người gọi. Thông thường bạn chỉ nhận được một SystemError khi sử dụng super ở một vị trí sai, nhưng biểu thức máy phát điện được bao bọc bên trong một hàm tạo ngầm ẩn tạo ra một khung gọi khác. Thật không may chức năng này được một đối số, dẫn các super() để khiếu nại với ngoại lệ này.

Vì vậy, thông thường super() sẽ được thông qua Foo ở đó làm đối số đầu tiên, nhưng trong biểu thức máy phát điện, một đối tượng máy phát đã được truyền - và do đó rõ ràng là cần phải tăng số lượng TypeError.

+0

Điều này đã khắc phục sự cố, chúc mừng! –

9

Trả lời câu hỏi ngụ ý của bạn:

Trong Java phương pháp tĩnh sẽ được thừa hưởng vì vậy tôi sẽ thậm chí không cần cuộc gọi siêu, nhưng trong Python này dường như không phải là trường hợp.

staticmethod s thừa hưởng:

class A: 
    @staticmethod 
    def a(): 
     print('Hello') 

class B(A): 
    def b(self): 
     self.a() 

b = B() 
b.a() 
b.b() 

kết quả đầu ra:

Hello 
Hello 

Lưu ý rằng bạn không thể chỉ đơn giản viết:

class B(A): 
    def b(self): 
     a() 

Python sẽ không bao giờ giải quyết một tên đơn giản cho một phương thức/staticmethod; đối với Python a()phải là cuộc gọi hàm, cục bộ hoặc toàn cục. Bạn phải tham chiếu cá thể bằng cách sử dụng self.a hoặc lớp học bằng cách sử dụng B.a.

Trong trăn selfrõ ràng làm tham chiếu lớp hiện tại. Đừng nhầm lẫn với ẩn số this của Java.

+0

Ah, đủ công bằng, điều đó có ý nghĩa. –

+0

Upvoted: D khi gỡ lỗi lý do đằng sau hiện tượng này, tôi không thấy rằng 'super()' là không cần thiết –

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