2012-11-01 47 views
8

Tôi đã mã sau:staticmethod và đệ quy?

class Foo(object): 
    def __init__(self): 
     baz=self.bar(10) 

    @staticmethod 
    def bar(n): 
     if n==0: 
      return 'bar' 
     else: 
      return bar(n-1) 

bar() là một hàm đệ quy nó cần tham chiếu đến chính nó. Tuy nhiên, thanh() nằm trong một lớp và gọi return bar(n-1) sẽ không hoạt động, gọi NameError: global name 'bar' is not defined. Làm thế nào tôi có thể đối phó với loại tình huống này? Tôi có nên thay đổi thanh() thành một lớp hoặc phương pháp thể hiện, cho phép truy cập vào self hoặc cls không?

+1

Gọi điện thoại 'Foo.bar (n-1) 'trong trợ giúp gọi đệ quy? – inspectorG4dget

Trả lời

4

Một thay thế cho việc sử dụng một phương pháp lớp học hoặc gọi lớp theo tên (như thể hiện bởi những người khác) được sử dụng một đóng cửa để giữ tham chiếu đến các chức năng:

class Foo(object): 
    def bar(): 
     def bar(n): 
      if n == 0: 
       return "bar" 
      return bar(n-1) 
     return bar 
    bar = staticmethod(bar()) 

The (nhỏ) lợi thế là điều này hơi dễ bị phá vỡ khi tên thay đổi. Ví dụ: nếu bạn có một tham chiếu đến Foo.barbên trongbar, điều này phụ thuộc vào Foo tiếp tục là tên chung cho lớp mà bar được xác định. Thông thường đây là trường hợp nhưng nếu không, thì cuộc gọi đệ quy nghỉ giải lao.

Cách tiếp cận classmethod sẽ cung cấp phương pháp có tham chiếu đến lớp học, nhưng lớp học không cần thiết trong phương pháp, điều này có vẻ không phù hợp. Việc sử dụng đóng cũng sẽ nhanh hơn một chút vì nó không thực hiện tra cứu thuộc tính trên mỗi cuộc gọi.

16

Bạn có thể tham khảo bar bằng cách đặt trước nó với tên lớp:

class Foo(object): 
    def __init__(self): 
     baz=self.bar(10) 

    @staticmethod 
    def bar(n): 
     if n==0: 
      return 'bar' 
     else: 
      return Foo.bar(n-1) 

phương pháp tĩnh là gì, nhưng các chức năng thường xuyên chứa trong namespace của một lớp sau khi tất cả.

Ngoài ra, xác định bar như một chức năng thường xuyên thay vì:

def bar(n): 
    if n==0: 
     return 'bar' 
    else: 
     return bar(n-1) 

class Foo(object): 
    def __init__(self): 
     baz=bar(10) 

mà tránh toàn bộ vấn đề hoàn toàn.

+0

@senderle: vâng, chỉ là lỗi c & p về phía tôi. Bạn cũng cần nó trong Python 3. –

+0

Thực ra mã chạy đúng mà không có nó trong Python 3 - ít nhất là khi được gọi từ chính 'Foo'. (Nhưng tôi thấy rằng nó không hoạt động khi được gọi từ một cá thể 'Foo'.) – senderle

+3

@senderle Nó hoạt động trong Python 3 bởi vì không có hàm bao hàm" unbound method "nào yêu cầu' isinstance (self, DefiningClass) 'khi gọi phương pháp. Một thứ chỉ hoạt động với '@ staticmethod' là gọi phương thức trên một cá thể (' Foo(). Bar (1) '). – delnan

7

Điều gì về điều đó?

class Foo(object): 
    def __init__(self): 
     baz = self.bar(10) 

    @classmethod 
    def bar(cls, n): 
     if n == 0: 
      return 'bar' 
     else: 
      return cls.bar(n-1) 
2

Bạn có thể xác định thanh() bên ngoài Foo và sau đó đưa nó vào như một staticmethod để bạn có được tất cả lợi ích của nó là một phương thức của lớp trong khi không phải đóng hoặc tham chiếu lớp đó. Tôi cần một cái gì đó như thế này vì lý do thừa kế lớp.

def bar(n): 
    if n==0: 
     return 'bar' 
    else: 
     return bar(n-1) 

class Foo(object): 
    bar = staticmethod(bar) 
    def __init__(self): 
     baz=self.bar(10)