2012-06-29 13 views
6

digression Bắt đầuĐiều gì là sai với metaclass python đơn giản này?

Tôi chỉ học được những gì metaclasses là bằng Python. Tôi không nghĩ rằng những người sáng tạo của python muốn mọi người sử dụng chúng. Tôi có nghĩa là tên một cái gì đó một metaclass mà có thể không phải là một lớp học trong nhiều trường hợp là đủ để chuyển hướng hầu hết mọi người đi từ khái niệm này!

digression cuối

On cho câu hỏi của tôi. Tôi đã viết metaclass đơn giản này để thêm một chuỗi tài liệu mặc định cho tất cả các lớp được tạo ra trong mô-đun. Nhưng nó không làm việc:

def metest(cls,name,bases,dict): 
    cls.setattr(cls,'__doc__',"""Default Doc""") 
    return type(cls,(),{}) 

__metaclass__=metest 

class test(object): 
    pass 

print test.__doc__ 

t=test() 

print t.__doc__ 

Output:

None 
None 

Tôi đang làm gì sai?

Trả lời

3

tôi làm ví dụ công việc của bạn:

def metest(name, bases, dict): 
    print name, bases, dict 
    dict['__doc__'] = """New Doc""" 
    cls = type(name+"_meta", bases, dict) 
    return cls 

class Test(object): 
    "Old doc" 
    __metaclass__ = metest 

print Test 
print Test.__doc__ 

t = Test() 

print t.__doc__ 
  1. Tận dụng tối "class meta" được sử dụng.
  2. Sửa chữ ký của "chức năng tạo lớp". cls sẽ do chúng tôi tạo.
  3. Có chuỗi tài liệu "cũ" và "mới" để phân biệt.
+0

Nó _is_ có thể sử dụng một metaclass toàn cầu, chỉ cần không kế thừa từ 'object' –

+0

Ai không nên kế thừa từ đối tượng? Metaclass hoặc TẤT CẢ các lớp trong module? – ritratt

2

Xem câu trả lời này: Python metaclass and the object base class

Cung cấp các lớp object cơ sở đè metaclass mô-đun cấp và thay thế nó bằng type (các metaclass của object).

Ngoài ra, metaclass của bạn bị lỗi và sẽ không hoạt động ngay cả khi bạn áp dụng nó (bằng cách đặt __metaclass__ bên trong lớp học). Nó chỉ nên chấp nhận ba đối số. Bạn thường thấy các ví dụ chấp nhận bốn, nhưng đó là vì metaclass thường là, hãy đoán xem, một lớp , vì vậy nó chấp nhận đối số "tự" bổ sung (theo quy ước được gọi là cls cho metaclasses).

4

Tôi không hoàn toàn quen thuộc với cách tiếp cận toàn cầu mà bạn đang làm, thiết lập __metaclass__ như thế. Đối với tất cả tôi biết, một phong cách hợp lệ của nó.

Nhưng tôi sẽ cung cấp một ví dụ về những gì tôi làm quen với:

class MeTest(type): 
    def __new__(cls,name,bases,dict): 
     dict['__doc__'] = """Default Doc""" 
     return type.__new__(cls,name,bases,dict) 

class Test(object): 
    __metaclass__ = MeTest 
+0

Tôi muốn thực hiện bằng chức năng như metaclass. – ritratt

1

Có thể đây là những gì bạn muốn. Kế thừa từ object sẽ làm cho metaclass type, vì vậy bạn không thể làm điều đó nếu bạn muốn sử dụng một metaclass toàn cầu

def metest(name, bases, dct): 
    dct['__doc__'] = """Default Doc""" 
    return type(name, bases, dct) 

__metaclass__=metest 

class test: 
    pass 

print test.__doc__ 

t=test() 

print t.__doc__ 
+0

Nhưng không nên metaclass nhất thiết phải là một loại? Bởi vì từ những gì tôi đã hiểu, tất cả các lớp trong Python là các đối tượng của lớp 'type'. Vì vậy, nếu tôi muốn thay đổi tất cả các lớp sau đó tôi cần phải ghi đè lên 'loại' đó là những gì' metaclass' nào. Vậy tại sao tôi KHÔNG nên kế thừa từ 'loại'? Có phải vì nó kế thừa từ lớp 'loại' không bị ghi đè không? Tôi bị bối rối. : S – ritratt

+0

@ritratt, 'metest' là hàm _returns_ một lớp _inherits từ type_. '__metaclass __ = metest' toàn cục chỉ hoạt động cho các lớp cổ điển. Một khi bạn kế thừa từ 'object', bạn sẽ đặt metaclass trở lại thành' type' trừ khi lớp đó ghi đè lên metaclass một lần nữa –

1

bạn metaclass mô-đun cấp được ghi đè, cũng giống như đã nêu ở trên bởi BrenBarn. Để khắc phục điều này, hãy cố gắng mã hóa nó thành trả lại cls thay vì đặt nó làm phiên bản lớp.