pills
pills

Reputation: 766

Using value overriden by child in a parent function

I have defined a base class that handles generic content, and children classes that are more specific in which content (object type) they accept. However, when calling the function defined in the parent class, the parent variables are used instead of the child variables. How do I get Python to use the child variable inside the parent functions ?

Example code :

class BaseField(object):
    __accepted_types = (object,)

    def __init__(self, description=""):
        self.content = None
        self.description = description

    def set(self, content):
        if isinstance(content, self.__accepted_types):
            print(type(content), self.__accepted_types)
            print(type(self))
            self.__set(content)
        else:
            raise ValueError("wrong type")

    def __set(self, content):
        pass

class StringField(BaseField):
    __accepted_types = (basestring,)

    def __init__(self, description=""):
        super().__init__(description)
        print(self.__accepted_types)

if __name__ == '__main__':
    x = StringField("a test field")
    x.set(3)

I expect this code to raise a ValueError (I'm trying to pass an int to a class that only accepts str), however I get the following result:

(<class 'str'>,)
<class 'int'> (<class 'object'>,) <class '__main__.StringField'>

Note that the function correctly returns that it's within "StringField" but uses the "BaseField" value for __accepted_types. The behavior is the same if I declare __accepted_types as an instance variable.

Upvotes: 2

Views: 228

Answers (2)

Rick
Rick

Reputation: 45231

As a followup to the other answer, I highly recommend watching this talk from PyCon 2013, in which the purpose and use of the Python name-mangling paradigm is discussed.

To summarize, using double underscore for your object variables it not a way to keep them "private". In fact, private variables in Python are not "a thing"; when coming from other languages, using Python effectively requires a shift in thinking on this and other topics.

The purpose of name-mangling it to prevent parent and child classes from falling into the trap of namespace wars, in which, for example, some child class is using an attribute name for a different purpose than the parent class.

For further reading, see these other questions and answers:

Underscore vs Double underscore with variables and methods

What is the meaning of a single- and a double-underscore before an object name?

Upvotes: 1

Dimitris Fasarakis Hilliard
Dimitris Fasarakis Hilliard

Reputation: 160397

You're falling victim to name mangling; the names are getting mangled inside the class body and self.__accepted_types get's transformed to _BaseField__accepted_types inside set.

Change all occurrences of __accepted_types to accepted_types and it'll work just fine.

p.s If you're indeed using Python 3, basestring doesn't exist, use str.

Upvotes: 2

Related Questions