2008-12-29 30 views
18

Tại sao không thực hiện công việc sau (Python 2.5.2)?Tại sao tôi không thể phân lớp datetime.date?

>>> import datetime 
>>> class D(datetime.date): 
     def __init__(self, year): 
      datetime.date.__init__(self, year, 1, 1) 
>>> D(2008) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: function takes exactly 3 arguments (1 given) 

Tôi muốn tạo ra một lớp học mà là giống như datetime.date, nhưng với một __init__ chức năng khác nhau. Rõ ràng chức năng của tôi không bao giờ được gọi. Thay vào đó, datetime.date.__init__ ban đầu được gọi và không thành công vì điều đó dự kiến ​​3 đối số và tôi chuyển vào một đối số.

Điều gì đang xảy ra ở đây? Và đây có phải là một đầu mối không?

>>> datetime.date.__init__ 
<slot wrapper '__init__' of 'object' objects> 

Cảm ơn!

+0

xem thêm http://stackoverflow.com/questions/309 129/why-cant-i-inherit-from-dict-và-exception-in-python – hop

Trả lời

34

Về một số câu trả lời khác, điều này không liên quan gì đến các ngày đang được triển khai trong C. Phương thức __init__ không làm gì vì chúng là các đối tượng không thay đổi, do đó hàm tạo (__new__) nên thực hiện tất cả công việc. Bạn sẽ thấy cùng một int hành vi subclassing, str vv

>>> import datetime 
>>> class D(datetime.date): 
     def __new__(cls, year): 
      return datetime.date.__new__(cls, year, 1, 1) 


>>> D(2008) 
D(2008, 1, 1) 
+0

Tôi hy vọng bạn sẽ không quan tâm một chút nhấn mạnh tôi đã thêm – tzot

+0

Câu trả lời hay, tôi đã thực sự không rõ ràng về điều này trước đây nhưng bây giờ nó làm cho cảm giác hoàn hảo – Kiv

4

Dưới đây là câu trả lời, và một giải pháp khả thi (sử dụng một chức năng hoặc strptime thay vì subclassing)

http://www.mail-archive.com/[email protected]/msg192783.html

+0

Cảm ơn bạn, liên kết đến vấn đề là đúng về tiền, nhưng không có lời giải thích __why__ nó không hoạt động. Nguyên nhân của vấn đề là gì và nó có thể vượt qua được không? – Arkady

0

Bạn có lẽ nên sử dụng một chức năng nhà máy thay vì tạo một lớp con:

def first_day_of_the_year(year): 
    return datetime.date(year, 1, 1) 
+0

Vâng, đó là mát mẻ, nhưng tôi tò mò là tại sao subclassing không hoạt động (làm thế nào nó là một lớp mở rộng làm cho sự khác biệt) và cho dù điều này có thể được khắc phục ... – Arkady

2

Chức năng của bạn không bị bỏ qua; Python không bao giờ đến được điểm mà nó sẽ gọi nó. Kể từ khi datetime được thực hiện trong C, nó khởi tạo của nó trong datetime.__new__ không datetime.__init__. Điều này là do datetime là không thay đổi. Bạn có thể lấy được điều này bằng cách ghi đè __new__ thay vì __init__. Nhưng như những người khác đã đề xuất, cách tốt nhất có lẽ không phải là phân lớp datetime ở tất cả.

+1

@ Benjamin: Vui lòng kiểm tra câu trả lời của tôi, và xem xét điều chỉnh của bạn, vì nó được bình chọn nhiều nhất cho đến nay; về cơ bản, chỉ câu cuối cùng của bạn mới có thể được coi là hữu ích; những người khác bị hiểu sai/ing. Ngoài ra, hãy sửa "của bạn" → "của nó" và "(Không" → "(Lưu ý". – tzot

0

Bạn có thể quấn và thêm chức năng mở rộng vào trình bao bọc của bạn.

Dưới đây là một ví dụ:

class D2(object): 
    def __init__(self, *args, **kwargs): 
     self.date_object = datetime.date(*args, **kwargs) 

    def __getattr__(self, name): 
     return getattr(self.date_object, name) 

Và đây là cách hoạt động:

>>> d = D2(2005, 10, 20) 
>>> d.weekday() 
3 
>>> dir(d) 
['__class__', '__delattr__', '__dict__', '__doc__', '__getattr__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__new__', 
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 
'__weakref__', 'date_object'] 
>>> d.strftime('%d.%m.%Y') 
'20.10.2005' 
>>> 

Lưu ý rằng dir() không liệt kê datetime.date s thuộc tính.

+0

@ ΤΖΩΤΖΙΟΥ: Bạn nói đúng. Nó thực sự là phân lớp. Tôi sẽ quay lại tài liệu và tìm hiểu nơi tôi đã tạo Trong khi đó tôi đang sửa chữa câu trả lời Cảm ơn bạn – muhuk

10

Xin vui lòng đọc các tài liệu tham khảo Python trên Data model, đặc biệt là về __new__special method.

Trích từ trang đó (in nghiêng của tôi):

__new__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.

datetime.datetime cũng là một loại không thay đổi.

PS Nếu bạn nghĩ rằng:

  • một đối tượng thực hiện trong C không thể được subclassed, hoặc
  • __init__ không nhận được gọi cho C triển khai các đối tượng, chỉ __new__

sau đó xin vui lòng hãy thử:

>>> import array 
>>> array 
<module 'array' (built-in)> 
>>> class A(array.array): 
    def __init__(self, *args): 
     super(array.array, self).__init__(*args) 
     print "init is fine for objects implemented in C" 

>>> a=A('c') 
init is fine for objects implemented in C 
>>> 
+0

Upvoted, bởi vì điều này có vẻ là câu trả lời duy nhất trên SO với một liên kết tài liệu, nhưng ví dụ của bạn bị hỏng, nó chỉ hoạt động vì bộ khởi tạo là một đối số tùy chọn Hãy thử 'a = A ('c', [], 5,8)'! – mkiever

+0

' >>> a = array.array ('c', [], 5, 8) Traceback (cuộc gọi gần đây nhất): Tệp "", dòng 1, trong LoạiError: array() mất nhiều nhất 2 đối số (4 đã cho) >>> a = A ('c', [], 5, 8) Lần truy nguyên (cuộc gọi gần đây nhất): Tệp "", dòng 1, trong LoạiError: array() nhận tối đa 2 đối số (4 đã cho) ' Ví dụ không bị hỏng là gì? @mkiever – tzot

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