1

I am trying to access a function from within a class that is within a different file.

My layout is:

Directory
   -> ClassFile.py
   -> _AFile.py

in ClassFile:

class TestClass:

    from ._AFile import test_1, test_2, test_3

    def __init__(self):


    def RunAllTests(self):
        self.test_1()
        self.test_2()
        self.test_3()


    @staticmethod
    def __DoSomething(a, b):
        return a + b

in _AFile:

def test_1(self):
    self.__DoSomething

def test_2(self):
    self.__DoSomething

def test_3(self):
    self.__DoSomething

This is what I want to do but cannot as I get: AttributeError: 'TestClass' object has no attribute '__DoSomething'

How can I access the static method from TestClass within AFile?

6
  • 1
    Can you include the complete definition of _AFile, atleast the member listing? Commented Jul 15, 2020 at 12:02
  • 1
    Okay, I have done now Commented Jul 15, 2020 at 12:05
  • It is because test_1 exists in _AFile, there is no __DoSomething in _AFile. You'll have to import TestClass in _AFile. Also you'll have to call it as TestClass.__DoSomething as it is static. Commented Jul 15, 2020 at 12:11
  • 1
    If I try from .ClassFile import TestClass and use TestClass.__DoSomething() I get: ImportError: cannot import name 'TestFeaturesClass' from partially initialized module 'Test.Tests_Features.test_features' (most likely due to a circular import) Commented Jul 15, 2020 at 12:13
  • 1
    You're imagining things the wrong way around. I think you're picturing TestClass importing AFile, and so when the functions of AFile are invoked they do so "inside" TestClass, so self refers to TestClass. This isn't correct. If you import a module, self will always refer to its own class (it's not clear here if AFile has a class). What you need to do is think of it the other way around: in AFile import TestClass, and in AFile call TestClass.DoSomething() (Don't forget the parentheses) Commented Jul 15, 2020 at 12:14

2 Answers 2

2

Methods which start with __ are class-private and they are mangled and so you cant access them when importing form a different file.

Official Docs:

__*

Class-private names. Names in this category, when used within the context of a class definition, are re-written to use a mangled form to help avoid name clashes between “private” attributes of base and derived classes. See section Identifiers (Names).

Fix

Change __DoSomething to _DoSomething

You are spreading the implementation of class TestClass into two files ClassFile.py and _AFile.py. In such a case you need to put __init__.py (empty file) inside the module.

Fix

Your directory structure should look like below

mymodule
   --> __init__.py
   --> ClassFile.py
   --> _AFile.py

ClassFile.py

class TestClass:

    from ._AFile import test_1, test_2, test_3

    def __init__(self):
        pass


    def RunAllTests(self):
        self.test_1()
        self.test_2()
        self.test_3()


    @staticmethod
    def _DoSomething(a, b):
        result = a+b
        print (result)
        return result

_AFile.py

def test_1(self):
    self._DoSomething(1,2)

def test_2(self):
    self._DoSomething(2,3)

def test_3(self):
    self._DoSomething(4,5)

Testing:

from mymodule.ClassFile import TestClass
test = TestClass()
test.RunAllTests()

Output:

3
5
9
Sign up to request clarification or add additional context in comments.

Comments

2

You are calling a private method from outside its class declaration, and it happens that python is doing some transformations under the hood.

As explained in the link above, the private attributes and methods of a python class are modified under the form _ClassName__attributename. This is a protection to avoid collision with subclasses defining potentially the same attributes or methods.

As a result, to make your import work as you want, you have two possibilities:

  • keep the method private, but use the generated method name from python
  • Use protected methods to use in your secondary file.

The following files will show you both possibilities:

_AFile.py

def test_1(self):
    # Express which private method you want to use
    self._TestClass__DoSomething()

def test_2(self):
    # Use a protected attribute only
    self._do_another_thing()

ClassFile.py

class TestClass:

    from _AFile import test_1, test_2

    def __init__(self):
        pass

    def RunAllTests(self):
        self.test_1()
        self.test_2()

    @staticmethod
    def __DoSomething():
        print("done something")

    @staticmethod
    def _do_another_thing():
        print("done another thing")

Execution:

>>> from ClassFile import TestClass
>>> TestClass().RunAllTests()
done something
done another thing

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.