1

Suppose I import the following two modules as follows:

from sympy import *
from numpy import *

both modules have an exp() function defined. How does python pick which one to use? Is there a way to distinguish these functions after the modules have been imported as above? What mechanism exists to warn the user when this is the case? Consider the following set of commands in IDLE

=============================== RESTART: Shell ===============================
>>> from sympy import *
>>> from numpy import *
>>> exp(5)
148.4131591025766
>>> c = symbols('c')
>>> exp(c)
Traceback (most recent call last):
  File "<pyshell#162>", line 1, in <module>
    exp(c)
AttributeError: 'Symbol' object has no attribute 'exp'
>>> 
=============================== RESTART: Shell ===============================
>>> from sympy import *
>>> c = symbols('c')
>>> exp(c)
exp(c)

It appears that by default python uses the exp() definition in numpy however when it is called on an object type recognized by sympy it throws an error which renders the sympy.exp() function unuseable.

For this case, I know that the functions exist in both packages but what if I don't? There ought to be some mechanism that warns the user to avoid really confusing situations.... How does the python community deal with this issue?

user32882
  • 5,094
  • 5
  • 43
  • 82
  • you need to use import as – Sugumar Venkatesan Aug 04 '17 at 08:45
  • About the errors that you are seeing: NumPy's `exp` is being used in all cases. The errors come from the fact that the function expected an array or array-like object as a parameter; at some point, NumPy's `exp` calls the `exp` method on the passed parameter, which causes an error because SymPy's `Symbol`s, as indicated, do not have such method. – jdehesa Aug 04 '17 at 08:49

2 Answers2

7

It doesn't "pick". When you do from sympy import * it imports all names from sympy into the current namespace; and when you do from numpy import * it does the same thing. Anything that is previously defined is overwritten. This is exactly the same as if you did:

foo = 'bar'
foo = 'baz'

Clearly, foo now has the value "baz" even though you initially defined it as "bar".

The solution is not to do this; you should import the things you need explicitly:

from sympy import exp, ....
from numpy import ....
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • But what if I want to use the `exp` command from *both* libraries? In this case it would still get overwritten, i.e `from sympy import exp; from numpy import exp` – user32882 Aug 04 '17 at 08:48
  • 3
    So just do `import sympy; import numpy`; then you can do `sympy.exp(foo)` and `numpy.exp(foo)`. Or, do `from sympy import ext as sympy_ext` etc. – Daniel Roseman Aug 04 '17 at 08:50
  • 1
    You should probably read [the effbot's classic guide to importing](http://effbot.org/zone/import-confusion.htm); it's old but still perfectly valid. – Daniel Roseman Aug 04 '17 at 08:51
  • @user32882 If what you want is to have an `exp` function that works the same for NumPy as SymPy (e.g. to write a mathematical function that works with both kinds of objects), then there is just no automatic way to do that. You would need to write your own `exp` function, dynamically detect if the parameter is a SymPy or NumPy (or NumPy [array-like](https://stackoverflow.com/questions/40378427/numpy-formal-definition-of-array-like-objects)) object and call the right function. However, getting the type detection completely right can be tricky and hard to maintain. – jdehesa Aug 04 '17 at 08:55
  • Ok I would like to accept your answer but it does not yet explain how the user can know such clashes exist. When using packages that I haven't used before I like to import their contents rather than import the module as a whole. There could be hundreds of clashes like this! Python couldnt possible rely on the user being aware of each and every one of them? That would imply the user would have to memorize every single name in every single module. Or only import the contents of ONE module but import all other modules as a whole. – user32882 Aug 04 '17 at 09:36
  • 1
    But you don't need to know if you follow good practice, as recommended in that piece I linked, and import the module rather than `*`. In any case, if you don't know what you're importing, how do you know what you can call? Surely it makes sense to just explicitly import the things you need. – Daniel Roseman Aug 04 '17 at 09:42
0

As far as I know and according to your code, the numpy's exp() would be added to your namespace as it's the last module which was imported. So, in this case, the last one wins the race! To fix this just use :

from toys import yo-yo as yo-yo1
Ubdus Samad
  • 1,218
  • 1
  • 15
  • 27