ludwigschuster
ludwigschuster

Reputation: 315

using import inside class

I am completely new to the python class concept. After searching for a solution for some days, I hope I will get help here:

I want a python class where I import a function and use it there. The main code should be able to call the function from the class. for that I have two files in the same folder.


Thanks to @cdarke, @DeepSpace and @MosesKoledoye, I edited the mistake, but sadly that wasn't it.

I still get the Error:

test 0
Traceback (most recent call last):
  File "run.py", line 3, in <module>
    foo.doit()
  File "/Users/ls/Documents/Entwicklung/RaspberryPi/test/test.py", line 8, in doit
    self.timer(5)
  File "/Users/ls/Documents/Entwicklung/RaspberryPi/test/test.py", line 6, in timer
    zeit.sleep(2)
NameError: global name 'zeit' is not defined


@wombatz got the right tip: it must be self.zeit.sleep(2) or Test.zeit.sleep(2). the import could be also done above the class declaration.


Test.Py

class Test:
    import time as zeit
    def timer(self, count):
        for i in range(count):
            print("test "+str(i))
            self.zeit.sleep(2)      <-- self is importent, otherwise, move the import above the class declaration
    def doit(self):
        self.timer(5)

and

run.py

from test import Test
foo = Test()
foo.doit()

when I try to python run.py I get this error:

test 0
Traceback (most recent call last):
  File "run.py", line 3, in <module>
    foo.doit()
  File "/Users/ls/Documents/Entwicklung/RaspberryPi/test/test.py", line 8, in doit
    self.timer(5)
  File "/Users/ls/Documents/Entwicklung/RaspberryPi/test/test.py", line 6, in timer
    sleep(2)
NameError: global name 'sleep' is not defined

What I understand from the error is that the import in the class is not recognized. But how can I achive that the import in the class is recognized?

Upvotes: 29

Views: 60519

Answers (7)

big meanie
big meanie

Reputation: 61

 import importlib



class importery():
    def __init__(self, y,z):
        self.my_name = y
        self.pathy = z
        self.spec = importlib.util.spec_from_file_location(self.my_name, self.pathy)
        x = importlib.util.module_from_spec(self.spec)
        self.spec.loader.exec_module(x)
        print(dir(x))
    
        root = x.Tk()
        root.mainloop()
    
    

pathy = r'C:\Users\mine\Desktop\python310\Lib\tkinter\__init__.py'

importery('tk', pathy)

There is a 'time and a place' to do this type of black magic, thankfully very rare times and places. Of the few I've found I've normally been able to use subprocess to get some other flavor of python to do my dirty work, but that is not always an option.

Now, I have 'used' this in blender when I've needed to have conflicting versions of a module loaded at the same time. This is not a good way to do things and really should be a last resort.

If you are a blender user and you happen to decide to commit this sin, I suggest doing so in a clean version of blender, install a like version of python next to it to use that to do your pip installs with, and please make sure you have added your config folder to your blender folder, else this black magic may come back to bite you in the arse later.

Upvotes: 0

Arnab De
Arnab De

Reputation: 462

It's probably a bit late, but I agree with idea of not polluting the module-level namespace (of course this can probably be remedied with a better design of a module, plus 'explicit is better than implicit' anyways).

Here is what I would do. The basic idea is this: import is an implicit assignment in which an entire module object gets assigned to a single name. Thus:

class Test:
    import time as zeit
    
    self.zeit = zeit # This line binds the module object to an attribute of an instance created from the class
    
    def timer(self, count):
        for i in range(count):
            print("test "+str(i))
            self.zeit.sleep(2) # This necessitates the `zeit` attribute within the instance created from the class
    
    def doit(self):
        self.timer(5)

Upvotes: 1

mb_atx
mb_atx

Reputation: 319

I agree with @Wombatz on his solution, but I do not have enough reputation to comment on his question

One use case that I have found for importing a module within a class is when I want to initialize a class from a config file.

Say my config file is

config.py

__all__ = ['logfile', ... ]
logfile = 'myevent.log'
...

And in my main module

do_something.py

class event():
    from config import *

    def __init__(self):
        try : self.logfile
        except NameError: self.logfile = './generic_event.log'

Now the advantage of this scheme is that we do not need to import logfile in the global namespace if it is not needed

Whereas, importing at the beginning of do_something.py, I will have to use globals inside the class, which is a little ugly in my opinion.

Upvotes: 1

Wombatz
Wombatz

Reputation: 5449

Everything defined inside the namespace of a class has to be accessed from that class. That holds for methods, variables, nested classes and everything else including modules.

If you really want to import a module inside a class you must access it from that class:

class Test:
    import time as zeit
    def timer(self):
        self.zeit.sleep(2)
        # or Test.zeit.sleep(2)

But why would you import the module inside the class anyway? I can't think of a use case for that despite from wanting it to put into that namespace.

You really should move the import to the top of the module. Then you can call zeit.sleep(2) inside the class without prefixing self or Test.

Also you should not use non-english identifiers like zeit. People who only speak english should be able to read your code.

Upvotes: 45

Moses Koledoye
Moses Koledoye

Reputation: 78556

sleep is not a python builtin, and the name as is, does not reference any object. So Python has rightly raised a NameEror.

You intend to:

import time as zeit

zeit.sleep(2)

And move import time as zeit to the top of the module.

The time module aliased as zeit is probably not appearing in your module's global symbol table because it was imported inside a class.

Upvotes: 4

Lee Dunham
Lee Dunham

Reputation: 117

You want time.sleep. You can also use;

from time import sleep

Edit: Importing within class scope issues explained here.

Upvotes: 3

AbrahamB
AbrahamB

Reputation: 1418

You're almost there! sleep is a function within the time module. This means that the name sleep doesn't exist unless its understood within the context of time, unless you define it on your own. Since you didn't define it on your own, you can access it by running time.sleep(2).

In your specific example, you used:

import time as zeit

you'll have to run:

zeit.sleep(2) 

Alternatively, you can import sleep directly from time, by running:

from time import sleep
sleep(2)

Good luck!

You can read more about the time module here: https://docs.python.org/2/library/time.html

You can learn more about imports here: https://docs.python.org/3/reference/import.html

and I highly recommend learning about namespace in python, here: https://bytebaker.com/2008/07/30/python-namespaces/

Upvotes: 2

Related Questions