[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