Reputation: 1858
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
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
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