Monkey patching 'datetime' produces strange results - python

I'm trying to make one of my libraries compatible with Python 2.6. It uses the method datetime.timedelta.total_seconds which was added in 2.7, so to make it work with 2.6, I wanted to monkey patch it into timedelta like this:
import datetime
if not hasattr(datetime.timedelta, 'total_seconds'):
class timedelta(datetime.timedelta):
def total_seconds(self):
return self.days * 86400.0 + self.seconds + self.microseconds * 1e-6
datetime.timedelta = timedelta
This does actually work in some cases, e.g. if I create a timedelta variable, it does have this method. But if a new timedelta object is produced by subtracting two datetime.datetime values, the method is missing from the resulting object.
What's going wrong and how do I fix this?

The datetime module is written entirely in C.
This includes the function that subtracts one datetime.datetime object from another. That function -- called new_delta() -- directly instantiates PyDateTime_DeltaType, which is the original datetime.timedelta class (written in C). It won't notice that you've rebound datetime.timedelta to your own class in Python-land.
I don't see any easy workarounds.

Related

Python - Datetime module, constructors and variable type

I am trying to get Python, especially how it works. I was digging into datetime module, and classes, that are part of it - date, datetime, timedelta etc. There are few question, that I don't catch. Lets base on below example:
import datetime
object1 = datetime.date.today()
object2 = datetime.date(2020, 8, 19)
print(object1, object2)
2022-02-12 2020-08-19
print (type(object1), type(object2))
<class 'datetime.date'> <class 'datetime.date'>
print (object1 - object2)
542 days, 0:00:00
The first question is - how it is possible to create object in two ways - first is (as I assume) by using __ init __ constructor (object2), and the second is by ... - there comes a question. How calling method today() directly from class datetime.date is able to create new instance of this class?
My second question is - before, when I was dealing with classes, there wasnt any exact value of object, that I had to use, I was only looking at methods and variables inside this object. The return value of instructions (constructors?) date.today and date(y, m, d) is datetime.date class. But what is the exact type of value, that object1 and object2 contains - how I am able to add them, generally to make any mathematical operation on it with sense.

Python: when is it necessary to prefix a module name?

I'm literally days-new to Python programming after years of C++ and C programming, and am trying to get a feel for the grammar.
In the following very-beginner code:
from datetime import datetime
from datetime import date
print( datetime.now() )
# print( now() ) # NameError: name 'now' is not defined
print( date(2005, 2, 27) )
# print( datetime.date(2005, 2, 27) ) # TypeError: descriptor 'date' requires a 'datetime.datetime' object but received a 'int'
...why is it necessary to scope now() in datetime but apparently incorrect to do so with date(...)?
The learning material I'm referencing said the two import statements mean I'm "importing the date and datetime classes from the datetime standard module." Possibly biased from my C++ background, I'm equating module with namespace and would have thought this meant (1) you'd need to explicitly scope functions and classes with the module they came from (like std::sort()), or (2) not need explicit scoping because the from/import clause is akin to CC++'s using clause. So the grammar of the above looks odd to me because it looks like I'm using two "things" that come from the datetime "namespace," and I must scope one thing but not the other.
FWIW, I use vim as my editor - I wonder: would something about this have been more transparent with a a graphical/autosuggest-enabled editor?
To any answerers, I'd be grateful if you could explain how an experienced Python programmer would go about finding out the answer to a question like this. What I mean is: in C/C++, I'd look up whatever .h I #include to find out what's what - how do you go about "looking up" the datetime "module"?
You're correct - you don't need to scope! This is a slightly confusing situation because the datetime module has a class which is also called datetime.
So what's happening in each of these:
print(datetime.now()) # Call the now() class method of the datetime class and print its output
print(now()) # now() is not defined in the namespace, hence the error
print(date(2005, 2, 27)) # Instantiate a date object and print its representation
print(datetime.date(2005, 2, 27)) # This is trying to call the date() method of the datetime class, which doesn't exist, hence the error.
With the last case, if you had just done import datetime, the whole datetime module would have been imported. In that case, you can instantiate a date class object by doing datetime.date(2005, 2, 27).
Hope that makes a tiny bit of sense!
The importing in python ist simple. When you import
from datetime import datetime
then you have from modul datetime only import the class / function datetime. (In this case a class). Your interpreter don't know the function "now" but you can access to it when you take the loop over that what you imported.
datetime.now()
after your second import
from datetime import date
your compiler knows the classes date and datetime. When you try
print( datetime.date(2005, 2, 27) )
then it is not that what you expect. You try to call from class datetime the function date which have other parameters as the class date from modul datetime.
The problem with the modul datetime is that it contains a class with datetime so it is a little bit confusing.

use method of library imported in another module

In first.py, I imported the datetime library and called a method which is written in second.py. The method works well without importing the datetime libirary in second.py.
first.py
from datetime import datetime
import second
def method1(time):
return datetime.strptime(time,"%Y/%m/%d")
a = method1("2019/08/01")
b = second.method2(a)
second.py
def method2(para1):
return para1.second
Output
0
Should second.py import datetime so that para1.second can work? Can someone help explain the rationale behind?
You only need to import modules explicitly when you need to use their names. In first.py, for example, you're using things in the datetime module directly, and referring to it by name. So, you do import datetime, and then call datetime.strptime() on that module you imported.
In second.py, however, you don't have to do import datetime. This is because of how python handles attributes - when you do para1.second, python doesn't need to know exactly what type of variable para1 is - it just checks to see whether it has a field called second. And it does, so it returns that. Nowhere in second.py are you referring to datetime directly - only indirectly, via a variable that was defined from it.
Also consider that the datetime module does a lot of stuff on its own, and almost certainly imports other dependencies that you're not aware of and you're not importing yourself. But you can still use the datetime module, because you don't need to explicitly refer to those modules it's using behind the scenes. They're still in memory somewhere, and if you call certain methods from datetime, that code will still get executed, but you don't need to be directly aware of it.
Python usually uses duck typing1. This means that instead of requiring a particular type for an object, it looks at the actual attributes it has.
What this means in your case is that method2 does not care in the slightest whether you pass in a datetime object or not. All that's required is that the input para1 have a second attribute.
Importing datetime into second.py would be counter-productive. It wouldn't affect the operation of your method in any way, but it would polute your namespace and set up an implication that isn't necessarily true.
1 A notable counterexample is a sum of strings, e.g. sum(['a', 'b'], ''). Aside from that, your own code can choose what to do as you see fit if course.

Generating current time in a chosen time zone

I'm trying to perform a, to me, simple task of generating a current date/time combo at a speficic time zone. All I see is suggestions to use pytz even though datetime includes the tzinfo class to deal with timezones. However, if I try to use tzinfo, it does not work:
>>> from datetime import datetime, tzinfo
>>> d = datetime.now(tzinfo.tzname("EDT"))
TypeError: descriptor 'tzname' requires a 'datetime.tzinfo' object but received a 'str'
The docs say you can use a time zone name like "EDT" or "GMT". What's wrong with this?
The function tzinfo.tzname does the opposite of what you think it does.
It takes a datetime object and returns a string indicating the time zone.

Syntax for importing function from object in class (Python 2)

I want to be able to access the strptime function directly (no datetime.datetime.strptime() or datetime.strptime().)
I can do this:
from datetime import datetime
strptime = datetime.strptime
But is there a way to accomplish the same thing on the import line?
Also, can you do multiple items on one line?
Here's pseudocode of what I really want to do:
from datetime.datetime import strftime, strptime
Datetime is just the example case, a similar thing would be useful for importing class methods in other libraries.
Those are methods of the datetime type and can't be imported directly. You can't directly import anything below the top-level namespace of a module. From the documentation:
The from form does not bind the module name: it goes through the list of identifiers, looks each one of them up in the module found in step (1) [i.e., the module being imported], and binds the name in the local namespace to the object thus found.
That is, the imported names must be names in the module namespace. They can't be any more deeply nested than that. So you can't, as you apparently want to do, import just certain methods of classes in the module.
The answer to the question "Can I do this on the import line?" is no.
See the definition of the import statement in Python 2. The statement imports things from modules. There is a datetime class inside the datetime module. The best you can do is
from datetime import datetime
You already understand well what this does, as you used it perfectly in your question. It looks like you wanted to do
from datetime import datetime.strptime
but that is a syntax error because datetime.strptime is not an indentifier.
You can't say
from datetime.datetime import strptime
either because Python would look for a module named datetime.datetime.
The import statement just doesn't work the way you want it to.
Note that the author of the datetime module chose to make strptime a classmethod (using #classmethod) rather than a function. So if you want to use strptime without the class qualifier you will have to do what you did, namely assign to a variable named strptime.

Categories