473,414 Members | 1,723 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,414 software developers and data experts.

Portrait of a "real life" __metaclass__

I guess this sort of falls under the "shameless plug" category, but
here it is: Recently I used a custom metaclass in a Python program
I've been working on, and I ended up doing a sort of write-up on it,
as an example of what a "real life" __metaclass__ might do for those
who may never have seen such a thing themselves.

http://markshroyer.com/blog/2007/11/...ass-windmills/

So what's the verdict? Incorrect? Missed the point completely?
Needs to get his head checked? I'd love to hear what
comp.lang.python has to (anthropomorphically) say about it.

--
Mark Shroyer
http://markshroyer.com/
Nov 10 '07 #1
3 1744
On Nov 9, 7:12 pm, Mark Shroyer <usenet-m...@markshroyer.comwrote:
I guess this sort of falls under the "shameless plug" category, but
here it is: Recently I used a custom metaclass in a Python program
I've been working on, and I ended up doing a sort of write-up on it,
as an example of what a "real life" __metaclass__ might do for those
who may never have seen such a thing themselves.

http://markshroyer.com/blog/2007/11/...ass-windmills/

So what's the verdict? Incorrect? Missed the point completely?
Needs to get his head checked? I'd love to hear what
comp.lang.python has to (anthropomorphically) say about it.
Kinda wordy. Let me see if I got the point:

- You already had a bunch of classes that did age matching on date
time objects.

- You were building a class that matched emails.

- You wanted to reuse the code for age matching to do email matching
(based on the message's age)

- So you wrote a metaclass that replaced the match() method with a
proxy that would either dispatch to the old match() method (if it was
a datetime object) or dispatch to the new match() method (which
matched based on the message's date.)

Sounds Java-y, if that's even a word. Too many classes, not enough
functions. You can tell you are doing Java in Python when you feel the
urge to give everything a name that is a noun, even if it is
completely based of a verb, such as "matcher". My opinion is that if
you want to talk about doing something in Python such as matching,
starting writing functions that match and forget the classes. Classes
are for real nouns, nouns that can do several distinct things.

What would I have done? I wouldn't have had an age matching class. I
would have had a function that, given the datetime and a range
specification, would return true or false. Then I would've written
another function for matching emails. Again, it takes a specification
and the email and returns true or false.

If I really wanted to pass around the specifications as objects, I
would do what the re module does: have one generic object for all the
different kinds of age matching possible, and one generic object for
all the email objects possible. These would be called,
"AgeMatchSpecification", etc... These are noun-y things. Here,
however, they are really a way of keeping your data organized so you
can tell that that particular dict over there is an
AgeMatchSpecification and that one is an EmailMatchSpecification. And
remember, the specifications don't do the matching--they merely tell
the match function what it is you wanted matched.

Now, part of the email match specification would probably include bits
of the date match specification, because you'd want to match the
various dates attached to an email. That's really not rocket science
though.

There wouldn't be any need to integrate the classes anymore if I did
it that way. Plus, I wouldn't have to remember a bunch of class names.
I'd just have to remember the various parameters to the match
specification for age matching and a different set of parameters for
the email matching.

Nov 10 '07 #2
On 2007-11-10, Jonathan Gardner <jg**************************@gmail.comwrote:
On Nov 9, 7:12 pm, Mark Shroyer <usenet-m...@markshroyer.comwrote:
>I guess this sort of falls under the "shameless plug" category, but
here it is: Recently I used a custom metaclass in a Python program
I've been working on, and I ended up doing a sort of write-up on it,
as an example of what a "real life" __metaclass__ might do for those
who may never have seen such a thing themselves.

http://markshroyer.com/blog/2007/11/...ass-windmills/

So what's the verdict? Incorrect? Missed the point completely?
Needs to get his head checked? I'd love to hear what
comp.lang.python has to (anthropomorphically) say about it.

Kinda wordy.
Yeah, my fingers sort of latch onto the keyboard sometimes and just
won't let go. Sorry about that ;)
Let me see if I got the point:

- You already had a bunch of classes that did age matching on date
time objects.

- You were building a class that matched emails.

- You wanted to reuse the code for age matching to do email matching
(based on the message's age)

- So you wrote a metaclass that replaced the match() method with a
proxy that would either dispatch to the old match() method (if it was
a datetime object) or dispatch to the new match() method (which
matched based on the message's date.)
Close, but not quite. The proxy *always* dispatches to
AgeSpec.match(), but if the result of that method is an AgeSpec
itself, then the proxy wraps the result back up in a Matcher, which
works out rather conveniently for the rest of the application.
Sounds Java-y, if that's even a word.
Yeah, you pretty much nailed my original background right there. On
the other hand, I've also done a lot of work in Perl and C, and
pride myself on striving not to resort to OO patterns where they
aren't really useful. So let me try to defend my reasoning, if it
is in fact defensible...
Too many classes, not enough functions. You can tell you are doing
Java in Python when you feel the urge to give everything a name
that is a noun, even if it is completely based of a verb, such as
"matcher". My opinion is that if you want to talk about doing
something in Python such as matching, starting writing functions
that match and forget the classes. Classes are for real nouns,
nouns that can do several distinct things.

What would I have done? I wouldn't have had an age matching class. I
would have had a function that, given the datetime and a range
specification, would return true or false. Then I would've written
another function for matching emails. Again, it takes a specification
and the email and returns true or false.
There isn't much difference between

match_calendar_month(2007, 11, message)

and

m = CalendarMonthMatcher(2007, 11)
m.match(message)

so of course you're right that, were that all I'm doing with these
matchers, it would be a waste to implement them as classes. But
take for example two of my app's mailbox actions -- these aren't
their real names, but for clarity let's call them ArchiveByMonth and
SaveAttachmentsByMonth. The former moves messages from previous
months into an archival mbox file ./archives/YYYY/MM.mbox
corresponding to each message's month, and the latter saves message
attachments into a directory ./attachments/YYYY/MM/. Each of these
actions would work by using either match_calendar_month() or
CalendarMonthMatcher().match() to perform its action on all messages
within a given month; then it iterates through previous months and
repeats until there are no more messages left to be processed.

In my object-oriented implementation, this iteration is performed by
calling m.previous() on the current matcher, much like the
simplified example in my write-up. Without taking the OO approach,
on the other hand, both types of actions would need to compute the
previous month themselves; sure that's not an entirely burdensome
task, but it really seems like the wrong place for that code to
reside. (And if you tackle this by writing another method to return
the requisite (year, month) tuple, and apply that method alongside
wherever match_calendar_month() is used... well, at that point
you're really just doing object-oriented code without the "class"
keyword.)

Furthermore, suppose I want to save attachments by week instead of
month: I could then hand the SaveAttachmentsByPeriod action a
WeekMatcher instead of a MonthMatcher, and the action, using the
matcher's common interface, does the job just as expected. (This is
an actual configuration file option in the application; the nice
thing about taking an OO approach to this app is that there's a very
straightforward mapping between the configuration file syntax and
the actual implementation.)

It could be that I'm still "thinking in Java," as you rather
accurately put it, but here the object-oriented approach seems
genuinely superior -- cleaner and, well, with better encapsulated
functionality, to use the buzzword.
If I really wanted to pass around the specifications as objects, I
would do what the re module does: have one generic object for all the
different kinds of age matching possible, and one generic object for
all the email objects possible. These would be called,
"AgeMatchSpecification", etc... These are noun-y things. Here,
however, they are really a way of keeping your data organized so you
can tell that that particular dict over there is an
AgeMatchSpecification and that one is an EmailMatchSpecification. And
remember, the specifications don't do the matching--they merely tell
the match function what it is you wanted matched.
Oddly enough, the re module was sort of my inspiration here:

my_regex = re.compile("abc")
my_regex.match("some string")

(Sure, re.compile() is a factory function that produces SRE_Pattern
instances rather than the name of an actual class, but it's still
used in much the same way.)
Now, part of the email match specification would probably include bits
of the date match specification, because you'd want to match the
various dates attached to an email. That's really not rocket science
though.

There wouldn't be any need to integrate the classes anymore if I did
it that way. Plus, I wouldn't have to remember a bunch of class names.
I'd just have to remember the various parameters to the match
specification for age matching and a different set of parameters for
the email matching.
You're sort of missing the bigger picture of this application,
although that's entirely not your fault as I never fully described
it to begin with. The essence of this project is that I have a
family of mailbox actions (delete, copy, archive to mailbox, archive
by time period, ...) and a family of email matching rules (match
read messages, match messages with attachments, match messages of a
certain size, match messages by date, ...) of which matching by date
is only one subtype -- but there are even many different ways to
match by date (match by number of days old, match by specific
calendar month, match by specific calendar month *or older*, match
by day of the week, ...); not to mention arbitrary Boolean
combinations of other matching rules (and, or, not).

My goal is to create a highly configurable and extensible app, in
which the user can mix and match different "action" and "matcher"
instances to the highest degree possible. And using class
definitions really facilitates that, to my Java-poisoned mind. For
example, if the user writes in the config file

actions = (
(
# Save attachments from read messages at least 10 days old
mailbox =(
path ='/path/to/maildir',
type ='maildir',
),
match =(
type =And,
p =(
type =MarkedRead,
state =True,
),
q =(
type =DaysOld,
days =10,
),
),
action =(
type =SaveAttachments,
destination ='/some/directory/',
),
),
)

(can you tell I've been working with Lighttpd lately?)

then my app can easily read in this dictionary and map the
user-specified actions directly into Matcher and Action instances;
and this without me having to write a bunch of code to process
boolean logic, matching types, action parameters, and so on into a
program flow that has a structure needlessly divergent from the
configuration file syntax. It also means that, should a user
augment the program with his own Matcher or Action implementation,
as I intend to make it easy to do, then those implementations can be
used straightaway without even touching the code for the
configuration file reader.

As for the decision to use a metaclass proxy to my AgeSpec classes,
I'm fully prepared to admit wrongdoing there. But I still believe
that an object-oriented design is the best approach to this problem,
at least considering my design goals. Or am I *still* missing the
point?

Thanks for your input!
Mark

--
Mark Shroyer
http://markshroyer.com/
Nov 10 '07 #3
On Sat, 10 Nov 2007 03:12:25 +0000, Mark Shroyer wrote:
I guess this sort of falls under the "shameless plug" category, but here
it is: Recently I used a custom metaclass in a Python program I've been
working on, and I ended up doing a sort of write-up on it, as an example
of what a "real life" __metaclass__ might do for those who may never
have seen such a thing themselves.

http://markshroyer.com/blog/2007/11/...ass-windmills/

So what's the verdict? Incorrect? Missed the point completely? Needs
to get his head checked? I'd love to hear what comp.lang.python has to
(anthropomorphically) say about it.
Without having read the whole thing (I just looked at the metaclass
itself): it looks like for every subclass of AgeSpec you want to create
an associated (wrapper of some sort) class as well. Perfectly reasonable
usage as far as I'm concerned.

The only suggestion I have is to avoid "helpfully" binding values in the
user's namespace. It might seem helpful for your intended use, but
automatically binding names on the user's behalf is one of those things
that can suddenly become decidedly unhelpful when a user wants to use the
code in a way other than originally intended.

Instead, make the wrapper class an attribute of the main class. For
example:

def __init__(cls, name, bases, dict):
"Initialize new AgeSpecMatcher subclass."
# Let type.__init__() do the heavy lifting...
super(MetaAgeSpec, cls).__init__(cls, name, bases, dict)
print "MetaAgeSpec.__init__(%s, ...)" % cls.__name__
try:
# We want to build wrapper classes for all AgeSpec
# subclasses, but not for AgeSpec itself
if issubclass(cls, AgeSpec):
cls.Matcher = cls.wrapper_class()
except NameError:
pass
Then, whereever you would have used:

MonthAgeSpecMatcher()

you'd use

MonthAgeSpec.Matcher()

instead. Namespaces are one honking great idea--use them. At the very
least, give the user an option not to bind the additional name.

Carl Banks
Nov 10 '07 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Silas | last post by:
Hi, I use view to join difference table together for some function. However, when the "real" table fields changed (e.g. add/delete/change field). The view table still use the "old fields". ...
1
by: VB Programmer | last post by:
I have a usercontrol that contains a dropdownlist that is populated dynamically from a database (Page_Load of usercontrol). How long will the uc "retain" the "life" of that dropdownlist if no...
0
by: Simon Verona | last post by:
I have some Windows Forms software that I'm developing that uses a remote server (called using remoting) to provide the business rules and dataaccess. For development purposes the client and...
0
by: David Garamond | last post by:
I want to know how functional indexes are used "in the real world". Here are the common uses: * non-unique index on the first parts of a longish text field (SUBSTRING(field)) to save disk space,...
5
by: playagain | last post by:
Please help me to build a list of examples of stack and queue in real life situation... Conditions: The object concerned must only one object. And the object must be tangible. Example: Queue...
1
by: Tyno Gendo | last post by:
Hi everyone I need to move on a step in my PHP... I know what classes are, both in PHP4 and 5 and I'm aware of "patterns" existing, but what I'm looking for are some real world projects eg....
71
by: Jack | last post by:
I understand that the standard Python distribution is considered the C-Python. Howerver, the current C-Python is really a combination of C and Python implementation. There are about 2000 Python...
0
by: Ignacio Machin ( .NET/ C# MVP ) | last post by:
The difference between compile & runtime. CreateInstance works at runtime, you can pass ANY string to it (even an incorrect one like "123123123123") and it will compile Only at runtime you will...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.