Virtual classes: doing it right?
Solution 1
I would prefer doing it with a factory:
def factory(description):
if description == "It's flat": return Line(description)
elif description == "It's spiky": return Triangle(description)
elif description == "It's big": return Rectangle(description)
or:
def factory(description):
classDict = {"It's flat":Line("It's flat"), "It's spiky":Triangle("It's spiky"), "It's big":Rectangle("It's big")}
return classDict[description]
and inherit the classes from Shape
class Line(Shape):
def __init__(self, description):
self.desc = description
def number_of_edges(self, parameters):
return 1
Solution 2
I agree with TooAngel, but I'd use the __new__ method.
class Shape(object):
def __new__(cls, *args, **kwargs):
if cls is Shape: # <-- required because Line's
description, args = args[0], args[1:] # __new__ method is the
if description == "It's flat": # same as Shape's
new_cls = Line
else:
raise ValueError("Invalid description: {}.".format(description))
else:
new_cls = cls
return super(Shape, cls).__new__(new_cls, *args, **kwargs)
def number_of_edges(self):
return "A shape can have many edges…"
class Line(Shape):
def number_of_edges(self):
return 1
class SomeShape(Shape):
pass
>>> l1 = Shape("It's flat")
>>> l1.number_of_edges()
1
>>> l2 = Line()
>>> l2.number_of_edges()
1
>>> u = SomeShape()
>>> u.number_of_edges()
'A shape can have many edges…'
>>> s = Shape("Hexagon")
ValueError: Invalid description: Hexagon.
Solution 3
Python doesn't have virtual classes out of the box. You will have to implement them yourself (it should be possible, Python's reflection capabilities should be powerful enough to let you do this).
However, if you need virtual classes, then why don't you just use a programming language which does have virtual classes like Beta, gBeta or Newspeak? (BTW: are there any others?)
In this particular case, though, I don't really see how virtual classes would simplify your solution, at least not in the example you have given. Maybe you could elaborate why you think you need virtual classes?
Don't get me wrong: I like virtual classes, but the fact that only three languages have ever implemented them, only one of those three is still alive and exactly 0 of those three are actually used by anybody is somewhat telling …
xApple
Updated on June 08, 2022Comments
-
xApple almost 2 years
I have been reading documentation describing class inheritance, abstract base classes and even python interfaces. But nothing seams to be exactly what I want. Namely, a simple way of building virtual classes. When the virtual class gets called, I would like it to instantiate some more specific class based on what the parameters it is given and hand that back the calling function. For now I have a summary way of rerouting calls to the virtual class down to the underlying class.
The idea is the following:
class Shape: def __init__(self, description): if description == "It's flat": self.underlying_class = Line(description) elif description == "It's spiky": self.underlying_class = Triangle(description) elif description == "It's big": self.underlying_class = Rectangle(description) def number_of_edges(self, parameters): return self.underlying_class(parameters) class Line: def __init__(self, description): self.desc = description def number_of_edges(self, parameters): return 1 class Triangle: def __init__(self, description): self.desc = description def number_of_edges(self, parameters): return 3 class Rectangle: def __init__(self, description): self.desc = description def number_of_edges(self, parameters): return 4 shape_dont_know_what_it_is = Shape("It's big") shape_dont_know_what_it_is.number_of_edges(parameters)
My rerouting is far from optimal, as only calls to the number_of_edges() function get passed on. Adding something like this to Shape doesn't seam to do the trick either:
def __getattr__(self, *args): return underlying_class.__getattr__(*args)
What I am doing wrong ? Is the whole idea badly implemented ? Any help greatly appreciated.
-
TooAngel almost 14 yearsnice - I also thought about something like that, but didn't know the python syntax for it
-
Stefan almost 14 years@Daniel: I don't think so. Metaclasses usually change the way a class works. In Objective-C this would be called a Class Cluster. I'm not sure what the proper name for it is in Python.
-
xApple about 13 yearsI implemented this solution and discovered that is suffers from a flaw: the init method of the class Shape will be called twice when creating an instance.
-
xApple about 13 yearsI can confirm this solution is not appropriate. To fix it see stackoverflow.com/questions/5953759.
-
Jörg W Mittag about 8 yearsInteresting! I didn't know that. Do you have a link where I can read up on virtual classes in C++? According to Wikipedia, in C++, nested classes are static members of the enclosing class. In other words: they aren't actually true nested classes (which are members of an enclosing instance of the enclosing class). And considering that virtual classes are a special case of true nested classes (namely true nested classes which be overridden in a subclass just like any other virtual member), this seems to preclude C++ from having virtual classes.
-
user1717828 about 8 yearsMmm, AFAIK C++ sort of defines what virtual classes are, because the language is so popular and make such heavy use of them. A virtual/abstract class cannot be instantiated, only inherited, so in a way it's more like a template for other classes to feed off of.
-
Jörg W Mittag about 8 yearsI'm not sure what you mean. The term virtual class is well-defined and has a precise meaning that is unrelated to C++ or any other language in particular. What you describe has absolutely nothing to do with virtual classes. What you describe is an abstract base class. Google has exactly 0 hits for virtual classes in C++. There are virtual base classes in C++, which are related to virtual inheritance, but none of them are related to virtual classes. Like I said: a virtual class is a class that is a member of an instance and can be overridden in a subclass, just like a virtual method …
-
Jörg W Mittag about 8 years… is a member of an instance and can be overridden in a subclass. In fact, in a language like Python, where classes are first-class objects, you can implement virtual classes by using methods which return classes. I believe you when you say that C++ has virtual classes, I don't know enough about C++ to judge that, but neither your example nor your link show virtual classes in C++, there are no Google hits about virtual classes in C++, and the Wikipedia article on C++ says that nested classes are static members, which conflicts with virtual classes where nested classes are non-static members.
-
user1717828 about 8 yearsIt appears you're right; I never knew I was mixing up those two concepts. Thanks for the catch.
-
Jim Oldfield over 6 yearsYour second factory function constructs an object of every type every time it's called, even though you only return one of them. Better to store classes in the dictionary than objects:
class_dict = {"It's flat": Line, ...}
thenreturn class_dict[description](description)
.