EB2127
EB2127

Reputation: 1858

Python OOP: how to use a flag parameter to access methods?

It's unclear to me how one accomplishes this in Python, though I am confused about the fundamentals of OOP:

Let's say I create a Shape class, and use this as an example.

class Shape:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def area(self):
        return self.x * self.y

    def perimeter(self):
        return 2 * self.x + 2 * self.y

    def scaleSize(self,scale):
        self.x = self.x * scale
        self.y = self.y * scale

In my case, I must create a Class which inputs a file whereby there are only two types, file_typeA and file_typeB. For the user, it would be exceptionally cumbersome to use a Class for Type A and a Class for Type B.

## use case for an a "read in file name" class `filename`
foo = filename(path = "path/to/file.txt", file_type = "TypeA")

My question is, how do I restrict the "Type A" methods for a file initialized with flag file_type="TypeA", and restrict the methods for a file initialized with flag file_type = "TypeB"?

Let's try the Shape class again, whereby the two types are Square and Triangle. The wrong way to code this is something like this:

class Shape:
    def __init__(self, x, y, type):
        self.x = x
        self.y = y
        self.type = type

    if type == "Square":

        def area(self):
            return self.x * self.y

        def perimeter(self):
            return 2 * self.x + 2 * self.y

        def scaleSize(self,scale):
            self.x = self.x * scale
            self.y = self.y * scale

    elif type == "Triangle":

        def hooray(self):
            print("HOORAY! It's hip to be a triangle!")

    else:
        print("'type' must be either Circle or Triangle")

 ## example Class instantiation
 bar = Shape(2, 3, type="Square")

For such a class, how do I create it such that the method area cannot be used for a Shape of type=="TypeB"?

Upvotes: 0

Views: 1265

Answers (2)

kindall
kindall

Reputation: 184171

That's not how you OOP! OOP helps to eliminate those kinds of conditionals. You should create a Shape base class, then use that to define subclasses for each individual kind of shape. The subclasses should include the methods needed for that kind of shape.

If you want the caller to be able to specify a shape using a string, for example because they are using data from a file or the user, you can write a factory method to do that. You can actually ask Python for the subclasses of your class; no need to list them out! DRY

class Shape(object):
     __subs = {}

     @classmethod
     def of_type(cls, name, *args, **kwargs):
         """Factory method that instantiates Shape subclasses given their name as a string"""
         lname = name.lower()
         subs = cls._Shape__subs
         if cls is Shape:
             if not subs:        # build subclass dictionary
                 subs.update({c.__name__.lower(): c for c in cls.__subclasses__()})
             if lname in subs:   # instantiate the named subclass
                 return subs[lname](*args, **kwargs)
             raise NameError("invalid shape name: %s" % name)
         raise TypeError("of_type() may be called only on Shape base class")

class Square(Shape):
     pass

class Triangle(Shape):
     pass

# set tri to an instance of type Triangle
tri = Shape.of_type("Triangle")

Note that the factory method passes through any arguments given after the name. Class names are case-insensitive.

Upvotes: 1

Jean-François Fabre
Jean-François Fabre

Reputation: 140168

I think you need to define a mother class:

class Shape:
   pass

then sub-classes

class Triangle(Shape):
   # whatever methods there are

What you're describing is a factory function which creates the proper object according to some parameter:

def create(type):
   if type=="Triangle":
       return Triangle()
   elif type=="Square":
       return Square()

but it's not very useful since the caller has to pass the name of the class instead:

c = create("Triangle")

instead of just doing:

c = Triangle()

Well, it may have its interest when saving/restoring a program state from a text file containing the type(s) of the objects in the program memory when saved (if you don't want to use pickle).

Upvotes: 3

Related Questions