0

I'm sure there's an answer to this question somewhere on SO, but I can't seem to find the right search terms to ferret it out.

Source file layout:

./mycode.py
./protocols/__init__py (empty)
./protocols/prot1.py
./protocols/prot2.py
./protocols/prot3.py

./protocols/prot1.py:

class Prot1:
 @classmethod
 def getAddress(cls, data):
 return f(data)

Similar for Prot2 and Prot3, but the return value is calculated differently in each class.

mycode.py:

import protocols
self.protocolClasses = {
 "1" : Prot1,
 "2" : Prot2,
 "3" : Prot3
}
protocol = "1" # just for the example
f = self.protocolClasses[protocol].getAddress(somedata)

That seems right to me, but Python gives an error:

NameError: global name 'Prot1' is not defined

The line number referenced is:

 "1" : Prot1,

What am I missing?

Edit: If I use the following syntax:

"1" : protocols.prot1.Prot1,

I get:

AttributeError: 'module' object has no attribute 'prot1'

If I use:

"1" : protocols.Prot1,

I get:

AttributeError: 'module' object has no attribute 'Prot1'
asked Feb 26, 2018 at 21:50
2
  • 1
    what is Prot1? You mean protocols.prot1.Prot1. You can also go with from protocols.prot1 import Prot1 if you're going to use it in more places. Commented Feb 26, 2018 at 21:52
  • I meant the class Prot1, defined in the file ./protocols/prot1.py. Is the capitalization messing me up? Commented Feb 26, 2018 at 21:54

1 Answer 1

3

Having directory structure as yours you have to fix imports.

Here is what will work:

from protocols.prot1 import Prot1
from protocols.prot2 import Prot2
from protocols.prot3 import Prot3
self.protocolClasses = {
 "1" : Prot1,
 "2" : Prot2,
 "3" : Prot3
}
protocol = "1" # just for the example
f = self.protocolClasses[protocol].getAddress(somedata)

Or you can use ./protocols/__init__py and add next lines in it:

from prot1 import Prot1
from prot2 import Prot2 
from prot3 import Prot3

This way you will be able to do imports like:

from protocols import Prot1, Prot2, Prot3

Now why is that?

It's because protocols is a Python package (by having __init__.py file in it) and prot1, prot2, prot3 are Python modules. In those modules you have defined classes. That is why you need to use full namespace i.e. protocols.prot1.Prot1 or from protocols.prot1 import Prot1.

answered Feb 26, 2018 at 21:53
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! That nailed it. I wonder if I would have been better off not having the init.py file and just imported the file contents?
I'm not sure I understand your question, but if you remove protocols/__init__.py you will not be able to from protocols.prot1 import Prot1 at all. Alternative is to have protocols.py instead of directory, and have all classes defined in it.
I see. I really wanted to break them up into individual files because the amount of code was growing rapidly. So what I have now is working, and I'll stick with it. Thanks again!

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.