[Tutor] Store Class in Tuple Before Defining it ...

Lie Ryan lie.1296 at gmail.com
Sat Aug 29 21:11:32 CEST 2009


Damon Timm wrote:
> Hi Everyone - thanks for your responses.  Answered my direct questions:
> 
> [1] can't be done at the top and

actually you can, but it's opening a can of worms that I wouldn't dare 
to go near:

VIDEO_RE = {
     re.compile(r'regex here'): 'Youtube',
     re.compile(r'regex there'): 'Vimeo',
     re.compile(r'regex over here'): 'Blip',
)

or

VIDEO_TYPES = {
     'Youtube': re.compile(r'regex here'),
     'Vimeo': re.compile(r'regex here'),
     'Blip': re.compile(r'regex here'),
}

> [2] would have to move the tuple somewhere else
> 
> as well as gave me some new ideas about completely rethinking the
> design ... I love keeping the RE definitions with the child classes
> ... makes it easy just to add a child anywhere without having to fool
> with the original code.
> 
> One of my issues has been fixed using the @staticmethod decorator
> (which I did not know about).  Here is what I have now, and my final
> question (perhaps) follows.
> 
> ####
> #this is a django app, by the way
> 
> class Video(models.Model):
>     url             = models.URLField('Video URL')
>     # more fields and functions here
> 
>     def sync(self):
>         'Update videos external data - for children only'
>         pass

You may want to raise an exception or `assert False` here since 
Video.sync() should never be called (because children class must always 
override it). Alternatively, you can just not define sync so it raises 
AttributeError.

>     @staticmethod
>     def add_video(url):
>         'add a video only if it matches correct regex -- need ExceptionHandler'
>         for sc in Video.__subclasses__():
>             if sc.RE.match(url):
>                 return sc(url=url)
> 
> class YoutubeVideo(Video):
>     RE = re.compile(r'([^(]|^)http://www\.youtube\.com/watch\?\S*v=(?P<youtubeid>[A-Za-z0-9_-]+)\S*')
> 
>     def sync(self):
>         # do custom syncing here
>         print "am syncing a YOUTUBE video"
> 
> class ViemoVideo(Video):
>     RE = re.compile(r'([^(]|^)http://(www.|)vimeo\.com/(?P<vimeoid>\d+)\S*')
> 
>     def sync(self):
>         # do custom syncing here
>         print "am syncing a VIMEO video"
> ##############
> 
> So, this is *great* because now I can "add_video" without knowing the
> video url type at all.
> 
>>>> v = Video.add_video(url="http://www.youtube.com/watch?v=UtEg3EQwN9A")
>>>> v
> <YoutubeVideo: >
> 
> Perfect!  The last part is figuring out the syncing -- what I would
> like to do would be either:
> 
>>>> Video.sync_all_videos() #create another static method
> 
> Or, if I had to, create another function that did a:
> 
>>>> for video in Video.objects.all(): # object.all() is a django function that returns everything
> ...         video.sync()
> 
> However, I am not sure how to determine the "actual" class of a video
> when I am dealing only with the parent.  That is, how do I call a
> child's sync() function when I am dealing the parent object? 

Just run v.sync(); python's object model will determine the correct 
.sync() to call (i.e. v.sync() will call YoutubeVideo.sync(v) if 
isinstance(v, YoutubeVideo); OR ViemoVideo.sync(v) if isinstance(v, 
ViemoVideo); etc). This is known as `polymorphism`, in OOP terms.

> As
> suggested (in email below) I could re-run the regex for each parent
> video for each sync, but that seems like it could be an expensive
> operation (supposing one day I had thousands of videos to deal with).

You're on the right mindset. It's not just an expensive operation, 
rechecking the url type on every function calls defeats the whole 
purpose of OOP. Check the url type only once when you instantiate the 
video container class, and use polymorphism for the rest of the day.



More information about the Tutor mailing list