0

Inside a python class the with open line gets:

Traceback (most recent call last):   
File "c:\Users\anonymous\Desktop\checker.py", line 54, in <module>
    print(main.check("fubk"))   
File "c:\Users\anonymous\Desktop\checker.py", line 13, in check
    with open(f"{self.BASE_DIR}\\wordlist.txt", "r") as words: 
AttributeError: 'str' object has no attribute 'BASE_DIR'
class main:
    BASE_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))

    def __init__(self, string, similarity: float = 0.76, BASE_DIR =  BASE_DIR):
        self.string = string
        self.similarity = similarity
        self.BASE_DIR = BASE_DIR
        print(self.DATADIR)

    def check(self):
        with open(f"{self.BASE_DIR}\\wordlist.txt", "r") as words:
            badwords = words.read().splitlines()
Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
Walker
  • 3
  • 2
  • 1
    Please [edit] to include the other parts of the error message, specifically the part that shows the exact line that is raising the error. Also, include how you are using and instantiating this `main` class. – Gino Mempin Jul 25 '21 at 05:13
  • I suggest *not* using the same name `BASE_DIR` for both the class variable and the instance variable, to avoid confusion. – Gino Mempin Jul 25 '21 at 05:17
  • 1
    Edited, but `with open` should accept string right? – Walker Jul 25 '21 at 05:19
  • Yes, it should. But it seems you are using the class incorrectly. You are calling the method `main.check("fubk")` but your `check` method is not accepting any arguments. And you should call `check` on an *instance* of `main`, not on `main` itself. – Gino Mempin Jul 25 '21 at 07:05

1 Answers1

0

You are using classes incorrectly. I recommend going through the tutorials on classes (again, even if you already have), such as this one from the Python docs: A First Look at Classes.

How to Fix

Basically, you are making 2 mistakes:

  1. Calling check on the main class directly, not on an instance of main
  2. Defining check without the correct parameters, but still passing "fubk" when calling it

1st, change check to be a proper instance method:

def check(self, word):
    print(word)
    with open(f"{self.BASE_DIR}\\wordlist.txt", "r") as words:
        badwords = words.read().splitlines()
    if word in badwords:
        ...

An instance method's 1st parameter should be the instance object itself (self). So if you want to pass some argument to your function, you need to add it to your function definition (ex. word).

2nd, you need to instantiate an object of main. Then call check on it.

main_obj = main("string", similarity=0.5)
main_obj.check("fubk")

Here, the check method will receive the instance object as self (so it has access to all the self.string, self.BASE_DIR, etc. instance attributes) and the input "fubk" as word. (I don't know what the string parameter is for).

What did the original error mean?

Your original error:

    print(main.check("fubk"))   
File "c:\Users\anonymous\Desktop\checker.py", line 13, in check
    with open(f"{self.BASE_DIR}\\wordlist.txt", "r") as words:
AttributeError: 'str' object has no attribute 'BASE_DIR'

is because check received "fubk" as self when it was called. You can see it if you printed out self.

    def check(self):
        print(self)
        ...

main.check("fubk")

which would print out fubk. Your original code was trying to do:

# {self.BASE_DIR}
"fubk".BASE_DIR

which leads to "'str' object has no attribute 'BASE_DIR'".

Again, this error is avoidable if you instantiate your objects and define your instance methods properly. In Python, self has a "special" meaning: see What is the purpose of the word 'self'?.

In addition, to avoid confusion, don't give your class variables and your instance variables the same name. It can lead to some confusing behavior that you'll have to debug later (example: python class instance variables and class variables).

class main:
    # class variable
    DEFAULT_BASE_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))

    # rename BASE_DIR function parameter
    def __init__(self, string, similarity: float = 0.76, custom_base_dir = None):
        ...
        # use parameter if provided or class default 
        self.BASE_DIR = custom_base_dir or DEFAULT_BASE_DIR

    def check(self):
        with open(f"{self.BASE_DIR}\\wordlist.txt", "r") as words:
            badwords = words.read().splitlines()
Gino Mempin
  • 25,369
  • 29
  • 96
  • 135