2013-07-11 16 views
16

Tôi đã thấy hai đối tượng Python khác nhau được sử dụng để nhóm dữ liệu tùy ý với nhau: các lớp và chức năng trống.Tại sao các lớp và hàm rỗng của Python hoạt động như các thùng chứa dữ liệu tùy ý, nhưng không phải là các đối tượng khác?

def struct(): 
    pass 

record = struct 
record.number = 3 
record.name = "Zoe" 


class Struct: 
    pass 

record = Struct() 
record.number = 3 
record.name = "Zoe" 

Ngay cả khi lớp học không trống, nó có vẻ hoạt động miễn là được xác định khi chạy.

Nhưng khi tôi đã tự mãn và cố gắng làm điều này với các hàm hoặc lớp được cài sẵn, nó không hoạt động.

record = set() 
record.number = 3 
AttributeError: 'set' object has no attribute 'number' 

record = pow 
pow.number = 3 
AttributeError: 'builtin_function_or_method' object has no attribute 'number' 

Có sự khác biệt cơ bản giữa các lớp và chức năng được cài sẵn và "tùy chỉnh" có tính đến hành vi này không?

+0

Có một lỗi trong ví dụ đầu tiên của bạn: nó nên được 'kỷ lục = struct' withouth các'() ', nếu không 'record' sẽ là' None' và dòng tiếp theo sẽ ném một ngoại lệ. Ngoài ra, cần lưu ý rằng việc sử dụng các hàm chỉ hoạt động vì hàm do người dùng định nghĩa chỉ là một đối tượng khác trong python, nghĩa là bạn có thể gán các thuộc tính tùy ý. Nếu hàm trống hoặc không có gì để làm với nó. Nhưng trong khi bạn có thể sử dụng điều này cho một số ma thuật lập trình siêu năng động, tôi không thể nghĩ ra lý do tại sao sử dụng một chức năng như một thùng chứa lưu trữ sẽ thích hợp hơn một lớp ... – l4mpi

+0

@ l4mpi Tôi nghĩ rằng nó hữu ích nếu bạn muốn mô phỏng các bao đóng mà "ghi" vào phạm vi kèm theo của chúng trong Python 2.x, trước 'nonlocal'. Bạn sử dụng các thuộc tính ad-hoc của đối tượng hàm cục bộ thay vì các vars cục bộ. – millimoose

+0

Rất tiếc, bạn nói đúng về ví dụ đầu tiên. –

Trả lời

6

Sự khác biệt là cả hai đối tượng chức năng và đối tượng Struct của bạn có thuộc tính __dict__, nhưng set trường hợp và chức năng tích hợp không:

>>> def struct(): 
...  pass 
... 
>>> record = struct 
>>> record.number = 2 
>>> struct.__dict__ 
{'number': 2} 
>>> class Struct: 
...  pass 
... 
>>> record = Struct() 
>>> record.number = 3 
>>> record.__dict__ 
{'number': 3} 
>>> record=set() 
>>> record.__dict__ 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'set' object has no attribute '__dict__' 
>>> pow.__dict__ 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'builtin_function_or_method' object has no attribute '__dict__' 

Bạn có thể bắt chước các behavour sử dụng khe cắm (mặc dù chỉ có trên các lớp học kiểu mới):

>>> class StructWithSlots(object): 
...  __slots__ = [] 
... 
>>> record = StructWithSlots() 
>>> record.number = 3 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'StructWithSlots' object has no attribute 'number' 
>>> record.__dict__ 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'StructWithSlots' object has no attribute '__dict__' 
2

Một số bản dựng sẵn có thể hạn chế hơn. Ngoài ra, các lớp được triển khai với các vị trí sẽ không chấp nhận các thuộc tính tùy ý.

3

Các loại được cài sẵn được viết bằng C và không thể sửa đổi được như vậy. Nhưng sau khi type/class unification được giới thiệu trong py2.2, bây giờ bạn có thể kế thừa từ một kiểu được tích hợp sẵn và ghi đè hoặc thêm các thuộc tính của riêng bạn vào lớp con đó.

Bạn có thể sử dụng gói forbiddenfood thêm các thuộc tính để tích hợp trong các loại:

Dự án này nhằm mục đích cung cấp cho bạn cách để tìm thiên đàng trong các thử nghiệm, nhưng nó có thể dẫn bạn đến địa ngục nếu bạn sử dụng nó trên mã sản xuất.

>>> from forbiddenfruit import curse 
>>> def words_of_wisdom(self): 
...  return self * "blah " 
>>> curse(int, "words_of_wisdom", words_of_wisdom) 
>>> assert (2).words_of_wisdom() == "blah blah " 

Và tất nhiên nếu bạn đang tự mãn đủ thì bạn có thể tạo ra các loại của riêng bạn trong C và thêm các tính năng như vậy với nó.

+4

Chắc chắn người ta có thể tạo ra một loại trong C mà có thể được sử dụng như thế? – delnan

+0

@delnan Ví dụ: loại 'đối tượng'. Nó có thể là thú vị để đi sâu vào nguồn Python mà một trong những trường hợp đặc biệt - cho phép expando đối tượng hoặc ngăn chặn chúng. – millimoose

+0

@delnan Nhưng tôi sẽ không gọi nó là kiểu tích hợp, bởi vì bạn đang viết loại của riêng bạn trong C (không phải từ thư viện chuẩn). Câu hỏi đặt ra là về các lớp được xây dựng và tùy chỉnh. –

1

Nếu bạn muốn bảo vệ mô phỏng trong lớp của riêng mình, bạn có thể sử dụng phương thức __setattr__().

class TestClass(object): 
    # Accept the attributes in this list 
    __valid_attributes = ["myattr1", "myattr2"] 

    def __setattr__(self, name, value): 
     if not name in TestClass.__valid_attributes: 
      raise AttributeError(
       "{0} has no attribute '{1}'".format(self.__class__.__name__, name)) 
     self.__dict__[name] = value 

Bây giờ bạn có thể làm một cái gì đó như thế này:

t = TestClass() 
t.noattr = "test" # AttributeError: TestClass has no attribute 'noattr' 

Nhưng "thuộc tính hợp lệ" vẫn có thể được thiết lập:

t = TestClass() 
t.myattr1 = "test" 
print(t.myattr1) # test 
+2

Xin chúc mừng, bạn vừa mới phát minh lại bánh xe ['__slots__'] (http://docs.python.org/2/reference/datamodel.html#slots). – RoadieRich

+0

không biết về __slots__, cảm ơn nhận xét của bạn – joente

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