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

Reply via email to