Making an existing function accessible from within a class

I understand this is the correct way to include a function inside a class, but feels overly complicated and awkward to have to rename existing functions:

from numpy import sin, cos, tan

class Foo1:
    def my_sin(self, x):
        return sin(x)

    def my_cos(self, x):
        return cos(x)

    def my_tan(self, x):
        return tan(x)

a1 = Foo1()
print(a1.my_sin(2))
print(a1.my_cos(2))
print(a1.my_tan(2))

In contrast, this works just as well, and feels neater.

class Foo2:
    from numpy import sin, cos, tan


a2 = Foo2()
print(a2.sin(2))
print(a2.cos(2))
print(a2.tan(2))

Why is this wrong, assuming I will only use those functions inside this class? Why does it even work?

(I’ve redacted my example heavily from my original text to keep it focused.)

Answer

It’s important to put all your imports at the top of the file so someone else or future-you can immediately see your file’s dependencies. Your import statement in Foo2 basically adds a module to sys.modules and assigns a few functions to class attributes. We can make class attributes like this:

import numpy as np

## other code that can bury Foo3 deeper into file

class Foo3:
    sin, cos, tan = np.sin, np.cos, np.tan

Has a repetition compared to the import, but it’s still more concise than making forwarding methods like in Foo1. If you planned on renaming the functions, then the repetition would be necessary anyway: from numpy import sin as s, cos as c, tan as t vs s, c, t = np.sin, np.cos, np.tan.

P.S. The other posts linked in comments and answers say that modules are almost always better than classes for putting static method-like functions in namespaces (and they are right), but maybe you want this class to have this class attribute so you can override in subclasses and play with duck-typing.