Understanding Python import priority - python

I need some clarification on how module and class level imports are handled when coexisting in the same namespace. See the following examples:
Works:
import datetime
print datetime.datetime.utcnow()
Fails:
from datetime import datetime
print datetime.datetime.utcnow()
Error: AttributeError: type object 'datetime.datetime' has no
attribute 'datetime'
Works:
from datetime import datetime # Is this ignored?
import datetime
print datetime.datetime.utcnow()
What exactly is happening in the 3rd example? Is the second module import replacing the class-specific first import? Does this mean that module and class level imports shouldn't be mixed in the same namespace?

There is no priority is such. The outcome is determined by the order in which import statements are executed, as follows.
If you try to import several things called X into your namespace, each import would rebind X to whatever it's importing.
Therefore at the end it will be last import that'll be in effect as far as the name X in concerned.
This is precisely what happens in your third example:
from datetime import datetime # This isn't ignored, but the name is immediately rebound
# by the next line
import datetime # Rebinds the name

Some of the IDE's that support python would give you the explanation, but yes, you're redefining (overwriting, replacing) the import in the 3rd example. Each name within a file is distinct. If you need access to a module and a class that share a name you need to use something like from datetime import datetime as dt.

An import is really just an assignment: it sets a name in your current namespace. So, in the third case, you set the name datetime as equal to the datetime class, then immediately reassign it to the datetime module.

There is no reason to do it like this:
from datetime import datetime
print datetime.datetime.utcnow()
this code, on the other hand, would do exactly what you want it to:
from datetime import datetime
print datetime.utcnow()

Your first example imports the datetime module and provides a datetime label in the local namespace representing it, then calls the utcnow() method of the datetime object belonging to the datetime module. The second adds the datetime.datetime object (not the module) to the local namespace with the label datetime, but the datetime object has no attribute datetime, so you get the exception. The third example assigns the datetime.datetime object to the label of that name in the namespace, then reassigns the label to the datetime module. So ignoring the mechanics of import that are irrelevant to this question (basically, adding modules to sys.modules if they are not there yet), what you have is equivalent to:
datetime = sys.modules['datetime']
datetime.datetime.utcnow()
then
datetime = sys.modules['datetime'].datetime
datetime.datetime.utcnow()
then
datetime = sys.modules['datetime'].datetime
datetime = sys.modules['datetime']
datetime.datetime.utcnow()

Related

Why does "from module import module" solve the no attribute problem?

I was tinkering around with a module called pixray.
import pixray
pixray.reset_settings()
The above code returned the error "module 'pixray' has no attribute 'reset_settings'"
But when I changed it to:
from pixray import pixray
pixray.reset_settings()
The code is able to run.
Not sure why this is the case.
Any and all explanations are welcome and appreciated!
This is easier to demonstrate with an example from within python's standard library - datetime!
import datetime
print(type(datetime)) # <class 'module'>
print(datetime.now())
# AttributeError: module 'datetime' has no attribute 'now'
print(datetime.datetime.now())
# no error
from datetime import datetime
print(type(datetime)) # <class 'type'>
print(datetime.now())
# no error
See, the module datetime exposes several objects: 'date', 'datetime', 'time', 'timedelta', 'timezone', 'tzinfo'. When you do import datetime, what you're doing is assigning the local name "datetime" to this module, which has those properties. Note that one of those properties is, in fact, also called "datetime".
Now, if you were to do from datetime import date, then what python would do is load the datetime module, retrieve the date object within, and then assign that to the local name "date", without also assigning the module datetime to any local variable.
Similarly, if you were to do from datetime import datetime, then python will load the datetime object from the datetime module, and assign that to the local name "datetime".
The same thing is likely happening in your case, except the name is pixray, not datetime. That is, the module pixray happens to contain an object, also called pixray, which has all the useful functionality. import pixray gives you the module, whereas from pixray import pixray gives you the object.

Date time Module

start_date=datetime.datetime.strptime(start_date,'%Y-%m-%d')
new_date=start_date+datetime.timedelta(days=1)
Given that I start my code by impoting datetime, why do I need to write datetime twice in the first line of code and only once in the second line?
This is how imports work in Python. By writing import datetime you are importing a module. This module in turn has classes datetime and timedelta.
It is pretty common for a module to have its most important class be called the same thing. Another way to import in Python makes the relationship between modules and their classes more clear:
from datetime import datetime
from datetime import timedelta
Then you can call the class directly like
new_date = start_date + timedelta(days=1)

Unable to use datetime.strptime with from datetime import datetime

I'm having some confusion on some of my code which was previously working (yesterday). Using python 2.7.6
I had
from datetime import datetime
openfor = (datetime.strptime(row[1],"%Y-%m-%d %H:%M:%S") - datetime.strptime(row[2], "%Y-%m-%d %H:%M:%S")).total_seconds()
and it returned the value that is required. As of this morning it is generating
AttributeError: 'module' object has no attribute 'strptime'
If I use the below, with or without the import it works.
openfor = (datetime.datetime.strptime(row[1],"%Y-%m-%d %H:%M:%S") - datetime.datetime.strptime(row[2], "%Y-%m-%d %H:%M:%S")).total_seconds()
It is no real big deal, because it works, but the code looks ugly and my curiosity is piqued.
So any suggestions on why this would stop working? And how to resolve?
Thanks
Per the comments, the import statement
from pylab import *
is the cause of the problem. This imports pylab and copies all the names in the pylab namespace into the global namespace of the current module. datetime is one of those names:
In [188]: import pylab
In [189]: 'datetime' in dir(pylab)
Out[189]: True
So datetime is getting reassigned to the module rather than the class.
Somewhere between
from datetime import datetime
and
openfor = (datetime.strptime(row[1],"%Y-%m-%d %H:%M:%S") - datetime.strptime(row[2], "%Y-%m-%d %H:%M:%S")).total_seconds()
datetime is getting redefined to equal the module datetime rather than the class datetime.datetime.
The cause of this problem is in code that you have not posted.
(But an import statement, import datetime, is likely the culprit. Also be careful not to use from module import *, as this could pollute the calling module's namespace with names from the other module. This could include datetime.)
By the way, some experts recommend never using
from module import function
and instead always importing modules only:
import module # or
import module as foo
While this may be a stylistic choice, adhering to this rule makes it extremely clear where everything is coming from.

How to get a dot notation of a python module?

I am writing a custom django model field which has serialize and unserialize operations, on unserialize, I am using the import_by_path to get the class and initialise an instance.
On the opposite, I need to serialize an instance to the database, in my case all I need to get the dot notation of the module.
What I am asking is, how I can, eg I have the datetime module
from datetime import datetime
how to output datetime in dot notation to string "datetime.datetime" ?
Not entirely clear on what you're asking, but dot notation is equivalent to your above example in Python, for instance:
import datetime
datetime.datetime
is the same as
from datetime import datetime
datetime
I hope that makes sense, let me know if you have any more questions.
Here's a better example:
>>> import datetime
>>> datetime
<module 'datetime' from '/path/to/python'>
>>> from datetime import datetime
>>> datetime
<type 'datetime.datetime'>
Edit: After seeing the clarification, this should be done with the python inspect module. Specifically, if you're trying to get the module that defines a particular class:
import inspect
import datetime
inspect.getmodule(datetime).__name__
or
def dot_notation(your_module):
return your_module.__module__ + "." + your_module.__class__.__name__
in a more general way, you can get the module
import inspect
from datetime import datetime
inspect.getmro(datetime)[0]
That should return 'datetime.dateime'

"import datetime" v.s. "from datetime import datetime"

I have a script that needs to execute the following at different lines in the script:
today_date = datetime.date.today()
date_time = datetime.strp(date_time_string, '%Y-%m-%d %H:%M')
In my import statements I have the following:
from datetime import datetime
import datetime
I get the following error:
AttributeError: 'module' object has no attribute 'strp'
If I change the order of the import statements to:
import datetime
from datetime import datetime
I get the following error:
AttributeError: 'method_descriptor' object has no attribute 'today'
If I again change the import statement to:
import datetime
I get the following error:
AttributeError: 'module' object has no attribute 'strp'
What is going on here and how do I get both to work?
Your trouble is that you have some code that is expecting datetime to be a reference to the datetime module and other code that is expecting datetime to be a reference to the datetime class. Obviously, it can't be both.
When you do:
from datetime import datetime
import datetime
You are first setting datetime to be a reference to the class, then immediately setting it to be a reference to the module. When you do it the other way around, it instead ends up being a reference to the class. Last assignment "wins."
You need to rename one of these references. For example:
import datetime as dt
from datetime import datetime
Then you can change references in the form datetime.xxxx that refer to the module to dt.xxxx.
Or else just import datetime and change all references to use the module name. In other words, if something just says datetime(...) you need to change that reference to datetime.datetime.
Python has a fair bit of this kind of thing in its library, unfortunately. If they followed their own naming guidelines in PEP 8, the datetime class would be named Datetime and there'd be no problem using both datetime to mean the module and Datetime to mean the class.
You cannot use both statements; the datetime module contains a datetime type. The local name datetime in your own module can only refer to one or the other.
Use only import datetime, then make sure that you always use datetime.datetime to refer to the contained type:
import datetime
today_date = datetime.date.today()
date_time = datetime.datetime.strptime(date_time_string, '%Y-%m-%d %H:%M')
Now datetime is the module, and you refer to the contained types via that.
Alternatively, import all types you need from the module:
from datetime import date, datetime
today_date = date.today()
date_time = datetime.strptime(date_time_string, '%Y-%m-%d %H:%M')
Here datetime is the type from the module. date is another type, from the same module.
datetime is a module which contains a type that is also called datetime. You appear to want to use both, but you're trying to use the same name to refer to both. The type and the module are two different things and you can't refer to both of them with the name datetime in your program.
If you need to use anything from the module besides the datetime type (as you apparently do), then you need to import the module with import datetime. You can then refer to the "date" type as datetime.date and the datetime type as datetime.datetime.
You could also do this:
from datetime import datetime, date
today_date = date.today()
date_time = datetime.strp(date_time_string, '%Y-%m-%d %H:%M')
Here you import only the names you need (the datetime and date types) and import them directly so you don't need to refer to the module itself at all.
Ultimately you have to decide what names from the module you need to use, and how best to use them. If you are only using one or two things from the module (e.g., just the date and datetime types), it may be okay to import those names directly. If you're using many things, it's probably better to import the module and access the things inside it using dot syntax, to avoid cluttering your global namespace with date-specific names.
Note also that, if you do import the module name itself, you can shorten the name to ease typing:
import datetime as dt
today_date = dt.date.today()
date_time = dt.datetime.strp(date_time_string, '%Y-%m-%d %H:%M')
The difference between from datetime import datetime and normal import datetime is that , you are dealing with a module at one time and a class at other.
The strptime function only exists in the datetime class so you have to import the class with the module otherwise you have to specify datetime twice when calling this function.
The thing here is that , the class name and the module name has been given the same name so it creates a bit of confusuion.
try this:
import datetime
from datetime import datetime as dt
today_date = datetime.date.today()
date_time = dt.strptime(date_time_string, '%Y-%m-%d %H:%M')
strp() doesn't exist. I think you mean strptime.
from datetime import datetime,timedelta
today=datetime.today()
print("Todays Date:",today)
yesterday=today-datetime,timedelta(days=1)
print("Yesterday date:",yesterday)
tommorrow=today+datetime.timedelta(days=1)
print("Tommorrow Date:",tommorrow)

Categories