2012-09-30 7 views
13

Khi tìm hiểu về mô hình dữ liệu của Python, tôi đang chơi với việc tạo các đối tượng từ các đối tượng hiện có bằng cách sử dụng phương thức __new__. Dưới đây là một số ví dụ mà tạo ra các đối tượng mới các loại:Đối tượng Python từ các đối tượng hiện có bằng cách sử dụng __new__

x = 2;  print type(x).__new__(x.__class__) 
x = {}; print type(x).__new__(x.__class__) 
x = [1,2]; print type(x).__new__(x.__class__) 
x = 2.34; print type(x).__new__(x.__class__) 
x = '13'; print type(x).__new__(x.__class__) 
x = 1.0j; print type(x).__new__(x.__class__) 
x = True; print type(x).__new__(x.__class__) 
x = (1,2); print type(x).__new__(x.__class__) 

Tuy nhiên, ba thí nghiệm sau cho tôi lỗi:

x = None;   print type(x).__new__(x.__class__) 
x = lambda z: z**2; print type(x).__new__(x.__class__) 
x = object;   print type(x).__new__(x.__class__) 

Các lỗi là (theo thứ tự):

TypeError: object.__new__(NoneType) is not safe, use NoneType.__new__() 
TypeError: Required argument 'code' (pos 1) not found 
TypeError: type() takes 1 or 3 arguments 

Tại sao ba ví dụ này không hoạt động? (Lưu ý: đối với ví dụ lambda, có vẻ như tôi phải chuyển đoạn mã khi tôi gọi phương thức __new__ nhưng tôi không biết cách thực hiện điều đó.) Tôi đang sử dụng Python 2.6. Xin lưu ý rằng tôi nhận ra điều này không nhất thiết là cách bạn muốn tạo các đối tượng mới bằng mã thực, nhưng mục đích của tôi là không thực tế, thay vào đó, nó là để hiểu cách thức các phương thức đối tượng cấp thấp hoạt động như thế nào. Các tính năng chính

+1

Và lỗi chính xác nói gì sẽ mang lại lợi ích cho chúng tôi .. –

+0

Đã thêm tin nhắn , Rohit. Cám ơn vì sự gợi ý. – rlandster

Trả lời

14

Không có gì quá đặc biệt, chỉ vì một số loại có đối tượng "trống" mặc định thuộc loại đó, trong khi đối tượng khác không có. Ví dụ làm việc của bạn về cơ bản tương đương với:

int() 
dict() 
list() 
float() 
str() 
complex() 
tuple() 

. . . tất cả đều hoạt động. Ba ví dụ cuối cùng của bạn về cơ bản là cố gắng tạo các phiên bản mới của NoneType, functiontype.

  1. NoneType không thành công vì lý do duy nhất, vì Không có gì là đơn lẻ --- loại NoneType chỉ có thể có một trường hợp, cụ thể là đối tượng Không có. (Thông báo lỗi cụ thể bạn nhận được hơi lạ, nhưng nếu bạn thực hiện types.NoneType() bạn sẽ nhận được thông báo trực tiếp hơn cho biết "Không thể tạo trường hợp NoneType".)
  2. function không thành công vì, như bạn thấy, nó yêu cầu đối số và bạn không cung cấp. Những gì bạn cần là một đối tượng mã, mà bạn có thể nhận được từ một hàm hiện có hoặc từ hàm compile. (Nó cũng đòi hỏi một đối số globals, mà chỉ có thể là một dict.)
  3. type không thành công vì bạn không đưa ra đủ đối số. Bạn có thể làm type(foo) để nhận loại foo hoặc type(name, bases, dict) để tạo loại mới (nghĩa là một lớp học).

Lưu ý rằng trong ví dụ cuối cùng của bạn, bạn đang sử dụng loại object, đây là một loại. Nếu bạn làm x = object() thay vào đó (tạo x là một đối tượng riêng lẻ thay vì kiểu đối tượng) thì nó sẽ hoạt động và tạo một đối tượng "trống".

Điều cần nhớ là gọi __new__ không thực sự huyền diệu. Nó chỉ là những gì sẽ xảy ra khi bạn trực tiếp cố gắng để nhanh chóng loại bằng cách làm someType(). Nếu kiểu đó yêu cầu đối số, gọi __new__ sẽ không thành công, giống như bất kỳ lệnh gọi hàm nào khác sẽ thất bại nếu bạn không cung cấp cho đối số đúng, bởi vì type(x).__new__ chỉ là một hàm giống như bất kỳ hàm nào khác.Bạn có thể thấy điều này với lớp do người dùng xác định:

>>> class Foo(object): 
...  pass 
>>> x = Foo();   print type(x).__new__(x.__class__) 
<__main__.Foo object at 0x00EB0370> 
>>> class Foo(object): 
...  def __init__(self, someArg): 
...   pass 
>>> class Foo(object): 
...  def __new__(cls, someArg): 
...   return super(Foo, cls).__new__(cls) 
>>> x = Foo(2);   print type(x).__new__(x.__class__) 
Traceback (most recent call last): 
    File "<pyshell#32>", line 1, in <module> 
    x = Foo(2);   print type(x).__new__(x.__class__) 
TypeError: __new__() takes exactly 2 arguments (1 given) 

Thành công trong trường hợp đầu tiên, vì lớp của tôi không yêu cầu đối số; nó không thành công trong lớp thứ hai, bởi vì lớp thứ hai không yêu cầu đối số.

__new__ không bị lỗi vì bất kỳ lý do bảo mật nào; nó chỉ thất bại vì kiểu bạn đang cố gắng khởi tạo đòi hỏi các đối số để xây dựng một cá thể. (Trường hợp None là trường hợp duy nhất khác ở đây; trường hợp đó không có lý do đặc biệt, bởi vì None là một đối tượng đặc biệt bằng Python.)

+0

Rất rõ ràng giải thích +1 – JamesSwift