1

Thank you for helping me understand this error. I double checked all the parameters with the specific instructions. When I run Python 3.6 it gives me the following error NameError: name 'DEFAULT_STRING' is not defined. I reviewed all parts of the code and unable to understand why I am not able to run the code when it gives me NameError. Thank you again for helping me understand the error.

class TripleString:

    # intended class constants

    MIN_LEN = 1
    MAX_LEN = 50
    DEFAULT_STRING = "(undefined)"


# constructor method

def __init__(self, string1 = DEFAULT_STRING, string2 = DEFAULT_STRING,
            string3 = DEFAULT_STRING):

    # assigning default values to the variables first

    self.string1 = self.DEFAULT_STRING

    self.string2 = self.DEFAULT_STRING

    self.string3 = self.DEFAULT_STRING

    # setting values using setter methods,

    self.set_string1(string1)

    self.set_string2(string2)

    self.set_string3(string3)


# mutator ("set") methods

def set_string1(self, string1):
    if self.valid_string(string1):
        self.string1 = string1

        return True

    return False


def set_string2(self, string2):
    if self.valid_string(string2):
        self.string2 = string2

        return True

    return False


def set_string3(self, string3):
    if self.valid_string(string3):
        self.string3 = string3

        return True

    return False


# accessor ("get") methods

def get_string1(self):
    return self.string1


def get_string2(self):
    return self.string2


def get_string3(self):
    return self.string3


def to_string(self):
    return self.string1 + ", " + self.string2 + ", " + self.string3


# helper methods for entire class

def valid_string(self, the_str):
    if len(the_str) >= self.MIN_LEN and len(the_str) <= self.MAX_LEN:
        return True

    return False


# ------------- CLIENT --------------------------------------------------

# Create 4 TripleString objects and printing

triple_string_num_1 = TripleString()

print(triple_string_num_1.to_string())

triple_string_num_2 = TripleString("Alice")

print(triple_string_num_2.to_string())

triple_string_num_3 = TripleString("Bob", "Chris")

print(triple_string_num_3.to_string())

triple_string_num_4 = TripleString("Oliver", "Laurel", "Thea")

print(triple_string_num_4.to_string())

print("")

# mutating values using setter methods

triple_string_num_1.set_string1("Lance")

triple_string_num_2.set_string2("XYZ")

triple_string_num_3.set_string1("Bobby")

triple_string_num_4.set_string2("Felicity")

print(triple_string_num_1.to_string())

print(triple_string_num_2.to_string())

print(triple_string_num_3.to_string())

print(triple_string_num_4.to_string())

print("")

# testing if validation working properly

if triple_string_num_4.set_string2(""):

    print("successful in setting empty string for string2 of 4th object," + \
          "validation is not working properly")

else:

    print(
        "failed in setting empty string for string2 of 4th object," + \
        "validation is working properly")

    print("Value after setting: ", triple_string_num_4.get_string2())
4
  • you cannot use class members in default initialization. Just define DEFAULT_STRING = "(undefined)" outside the class, that'll work Commented May 26, 2018 at 18:53
  • You can use TripleString.DEFAULT_STRING to access it, if you want to define it inside the class. Commented May 26, 2018 at 18:57
  • no you cannot. the class name doesn't exist yet Commented May 26, 2018 at 18:57
  • As indented, __init__ is not a method, but a regular function trying to access a global name DEFAULT_STRING, not the variable that will become a class attribute in TripleString. Commented May 26, 2018 at 21:06

1 Answer 1

0

With proper indentation, you shouldn't get the name error you report:

class TripleString:

    MIN_LEN = 1
    MAX_LEN = 50
    DEFAULT_STRING = "(undefined)"

    def __init__(self, string1=DEFAULT_STRING, string2=DEFAULT_STRING,
                string3=DEFAULT_STRING):

        self.string1 = self.DEFAULT_STRING
        self.string2 = self.DEFAULT_STRING
        self.string3 = self.DEFAULT_STRING

        self.set_string1(string1)
        self.set_string2(string2)
        self.set_string3(string3)

    def set_string1(self, string1):
        if self.valid_string(string1):
            self.string1 = string1
            return True
        return False

    def set_string2(self, string2):
        if self.valid_string(string2):
            self.string2 = string2
            return True
        return False

    def set_string3(self, string3):
        if self.valid_string(string3):
            self.string3 = string3
            return True
        return False

    def get_string1(self):
        return self.string1

    def get_string2(self):
        return self.string2

    def get_string3(self):
        return self.string3

    def to_string(self):
        return self.string1 + ", " + self.string2 + ", " + self.string3

    def valid_string(self, the_str):
        if len(the_str) >= self.MIN_LEN and len(the_str) <= self.MAX_LEN:
            return True
        return False

The code could be written more cleanly using properties:

class TripleString:

    MIN_LEN = 1
    MAX_LEN = 50
    DEFAULT_STRING = "(undefined)"

    @property
    def string1(self):
        return self._string1

    @string1.setter:
    def string1(self, value):
        self._string1 = self._validate(value)

    @property
    def string2(self):
        return self._string2

    @string2.setter:
    def string2(self, value):
        self._string2 = self._validate(value)

    @property
    def string3(self):
        return self._string3

    @string3.setter:
    def string3(self, value):
        self._string3 = self._validate(value)

    def __init__(self, string1=DEFAULT_STRING, string2=DEFAULT_STRING, string3=DEFAULT_STRING):   
        self.string1 = string1
        self.string2 = string2
        self.string3 = string3

    def __str__(self):
        return ", ".join([self.string1, self.string2, self.string3)]

    def _validate(self, s):
        if s is not None and self.MIN_LEN <= len(s) <= self.MAX_LEN:
            return s
        else:
            return self.DEFAULT_STRING

It can be implemented even more cleanly by defining a custom property-like descriptor.

class StringProperty:
    MIN_LEN = 1
    MAX_LEN = 50
    DEFAULT = "(undefined)"

    def __init__(self):
        self._d = {}

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return self._d[id(obj)]

    def __set__(self, obj, value):
        self._d[id(obj)] = self._validate(value)

    def _validate(self, s):
        if s is not None and self.MIN_LEN <= len(s) <= self.MAX_LEN:
            return s
        else:
            return self.DEFAULT_STRING

 class TripleString:
     string1 = StringProperty()
     string2 = StringProperty()
     string3 = StringProperty()

     def __init__(self, s1=None, s2=None, s3=None):
         self.string1 = s1
         self.string2 = s2
         self.string3 = s3

All the logic involving the validation of such a property is encapsulated in the StringProperty class. A dictionary maps the identity of an object whose class has a StringProperty attribute to the value of the property in that object. All assignments are validated in-place.

>>> x = TripleString("foo", "bar")
>>> x.string1, x.string2, x.string3
('foo', 'bar', '(undefined)')
>>> x.string2 = 'baz'
>>> x.string2
'baz'

Accessing the value x.string1 is equivalent to TripleString.string1.__get__(x), while x.string2 = 'baz' is equivalent to TripleString.string2.__set__(x, 'baz').

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

Comments

Your Answer

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.