Perché non posso sottoclasse datetime.date?
Domanda
Perché non i seguenti lavori (Python 2.5.2)?
>>> 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)
Ho voluto creare una classe che era proprio come datetime.date
, ma con una funzione __init__
diversa. A quanto pare la mia funzione non viene mai chiamato. Invece il datetime.date.__init__
originale si chiama e non riesce perché si aspetta 3 argomenti e sto passando in uno.
Che cosa sta succedendo qui? Ed è questo un indizio?
>>> datetime.date.__init__
<slot wrapper '__init__' of 'object' objects>
Grazie!
Soluzione
Per quanto riguarda diverse altre risposte, questo non ha nulla a che fare con date in corso di attuazione in C per sé. Il metodo __init__
non fa nulla perché sono immutabili oggetti, quindi, il costruttore (__new__
) dovrebbe fare tutto il lavoro. Si potrebbe vedere lo stesso comportamento int sottoclassi, str, ecc.
>>> import datetime
>>> class D(datetime.date):
def __new__(cls, year):
return datetime.date.__new__(cls, year, 1, 1)
>>> D(2008)
D(2008, 1, 1)
Altri suggerimenti
Si prega di leggere il riferimento di Python su Modello di dati , in particolare circa la __new__
speciale metodo .
Estratto da quella pagina (il corsivo è mio):
__new__()
destinato principalmente a consentire sottoclassi di immutabile tipo (come int, str o tupla) a personalizzare creazione dell'istanza . E 'anche comunemente ignorata in metaclassi personalizzati in modo da personalizzare la creazione di classe.
datetime.datetime
è anche un tipo immutabile.
PS Se si pensa che:
- un oggetto implementato in C non può essere derivata o
-
__init__
non viene chiamato per C implementato oggetti, solo__new__
quindi si prega di provare:
>>> 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
>>>
Ecco la risposta, e una possibile soluzione (utilizzare una funzione o strptime invece di subclassing)
http://www.mail-archive.com /python-list@python.org/msg192783.html
Non Sei funzione non viene bypassato; Python ottiene appena mai al punto in cui sarebbe chiamarlo. Poiché datetime è implementato in C, fa il suo inizializzazione datetime.__new__
non datetime.__init__
. Questo perché datetime è immutabile. Si potrebbe presumibilmente aggirare questo sovrascrivendo __new__
invece di __init__
. Ma, come altre persone hanno suggerito, il modo migliore è probabilmente non sottoclasse datetime a tutti.
Probabilmente è meglio usare una funzione di fabbrica invece di creare una sottoclasse:
def first_day_of_the_year(year):
return datetime.date(year, 1, 1)
È possibile avvolgere e aggiungere funzionalità estesa al vostro involucro.
Ecco un esempio:
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)
Ed ecco come funziona:
>>> 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'
>>>
Si noti che dir()
non elenca gli attributi datetime.date
s.