On 24 апр, 07:27, Scott SA <[EMAIL PROTECTED]> wrote:
> Hi,
>
> I'm using the @classemethod decorator for some convenience methods and for
> some reason, either mental block or otherwise, can't seem to figure out how
> to elegantly detect if the call is from an instance or not.
>
> Here's the problem: Within the class definition, 'isinstance' has nothing to
> compare to because the class does not appear to exist.
>
> This is NOT a great example, but it outlines the the code:
>
> class RecipieClass:
> def __init__(self):
> pass
>
> @classmethod
> def get_ingrendients(self, recipie_list=None):
>
> if isinstnace(self,RecipieClass):
> return self.do_something_interesting()
> else:
> return do_something_boring(recipie_list)
>
> Yes, I can test to see if the param exists, but that makes the call exclusive
> i.e. I can _only_ call it as an instance or with a parameter.
>
> Why am I doing this?
>
> It is a series of convenience methods, in this case I'm interacting with a
> database via an ORM (object-relational model). I want the ability to call a
> class-ojbect and get related values, or pass some criteria and get related
> values for them without collecting the records first as instances, then
> iterating them. I need to call this from several places so I want to be DRY
> (don't repeat yourself).
>
> The easiest way to describe this as an analogy would be like having a recipie
> for cookies and wanting to know all of the ingredients ahead of time. Then,
> at another time, wanting to know what all the ingredients would be to make
> cookies, cake and bread (i.e. complete shopping list).
>
> cookie_recipie = RecipieClass.get_recipie('cookies')
> cookie_recipie.get_ingredients()
> 2C Flour
> 0.5 C Sugar
> ...
>
> RecipieClass.get_ingrendients(['cookies','cake','bread'])
> 8C Flour
> 2C Sugar
> ...
>
> Of course any suggestions on how this might be better approached would be
> interesting too.
>
> TIA,
>
> Scott
Hi,
It would make sense to separate instance-level and class-level
behaviour with additional 'objects' namespace. e.g.
cookie_recipie.get_ingredients() to get ingredients only for cookie
recipie and RecipieClass.objects.get_ingrendients([....]) to get all
the ingredients.
The elegant solution (AFAIK used by Django) would be to use metaclass
and the object with custom descriptor for class-object/table level
stuff.
Something like this:
class RecipieMetaclass(type):
def __new__(cls, bases, attrs):
new_cls = type.__new__(cls, name, bases, attrs)
new_cls.objects = IngredientsDescriptor(IngredientsManager())
return new_cls
class RecipieClass(object):
__metaclass__ = RecipieMetaclass
def get_ingredients(self, recipie_list=None):
return self.do_something_interesting(recipie_list)
class IngredientsManager(object):
def get_ingredients(self, recipie_list=None):
return do_something_boring(recipie_list)
class IngredientsDescriptor(object):
def __init__(self, ingredients_manager):
self.ingredients_manager = ingredients_manager
def __get__(self, instance, type=None):
if instance is not None:
raise AttributeError, "Access via %s instances is not
allowed" % type.__name__
return self.ingredients_manager
Then, "at another time, wanting to know what all the ingredients would
be to make cookies, cake and bread" you would call:
RecipieClass.objects.get_ingrendients(['cookies','cake','bread'])
Both Django and Google Apps Engine API use similar concepts and you
can learn much more interesting looking in their source code.
Regards,
--
Ivan
--
http://mail.python.org/mailman/listinfo/python-list