On 2 October 2010 12:32, Russell Keith-Magee <russ...@keith-magee.com> wrote:
> 2010/10/2 Łukasz Rekucki <lreku...@gmail.com>:
>> On 2 October 2010 10:34, Russell Keith-Magee <russ...@keith-magee.com> wrote:
>>>
>>> Another option would be to use copy-on-call, but raise an error if
>>> they provide any arguments to __init__(). This would be annoying and
>>> counter to Python idiom, but it strikes me as less fundamentally
>>> counterintuitive than prohibiting *any* use of self to store state.
>>>
>>> We could even wrap the "no args to __init__" error check in a method
>>> that enables it to be overridden and silenced in a subclass; that way,
>>> introducing the potentially un-threadsafe behavior would need to be an
>>> active action on the part of the developer. Then we can document the
>>> "feature" up the wahoo -- "If you *really* need arguments to your
>>> class-based view's constructor, you can get them, but here's the
>>> caveats... if you ignore these caveats, here's what will happen"
>>
>> Now you lost me. If we are discouraging people from using arguments to
>> __init__, why does the page list "You can't use arguments to init() to
>> instantiate a class view" as a drawback of the __new__ based approach
>> ?
>
> The difference is that __new__ doesn't *ever* allow for initialization
> arguments -- there is no way to pass an argument in. An "arguments
> disabled by default" __init__+copy implementation allows arguments as
> an opt-in.

This largely depends on what you mean by "initialization". There are
actually two levels of this: 1) per-request initialization based on
the request 2) per-view initialization on application startup.

The __init__ method in current implementation[1] falls in to the
second category (independently of the ability to pass in any arguments
as noted by Carl Meyer). This kind of settings should never mutate for
the reasons given by Vince Veselosky. Adding a rule: "don't mutate
objects assigned to self in __init__" doesn't really feel like a
normal use of a Python class.

I agree with you that, subclassing is the prefered way of customizing
views. The fact that class attributes are shared by instances should
be pretty clear to any Python programmer with OOP knowledge (same as
the fact that default arguments for functions are shared between
invocations).

To sum this up, I think the important questions are:

   1) Do View instances need to share anything ? I say: yes.

   2) What is the purpose of this shared objects ?
      I say: customization of *default* view settings (like default
redirect path, default template, default page size in pagination).

   3) How do we make this shared settings immutable between requests
(this has nothing to do with thread-safety) ?
      This is largely the topic of this thread. Deep copying it
everytime is surely the most secure option, but not very efficient.
Another way is to keep this settings as class attributes and assume
the user is sane enough not to share mutable object between class
instances.

>
> There's also the wierd behavior that __new__ requires. Consider:
>
> x = MyView()
>
> What is x? If you use the __init__+copy approach, x is an instance of
> MyView. If you use __new__, x is a HttpResponse. It's a minor thing,
> to be sure, but this is a bit of a code smell to me.

I don't consider this weird. The view's contract is: "give me a
request, I'll give you a response". In OOP terms, it's a just a
Factory of HttpResponses.

>
>> Anyway, using mutable arguments to view's __init__ is pretty much the
>> same as using mutable objects as default values for function
>> arguments. Doing:
>
> Yes - but that's something that is well known as a Python gotcha. The
> same restriction doesn't usually apply to just passing values to a
> constructor.

Same common knowledge exists concerning class attributes. Lets reuse that.

>>
>> def with_args(view_cls, **kwargs):
>>    return type(view_cls.__name__, (view_cls,), kwargs)
>>
>> # in urls.py:
>>
>>  (r'^somepath', with_args(MyView, option=False)),
>>  # or even
>>  (r'^somepath', MyView.with(option=False)),
>
> I can't deny this would work. It just doesn't feel very Pythonic to me.

I don't share your feeling about this. Django already uses a similar
idiom in ModelForms - you pass in a base form, some extra options and
get a new subclass. Also, I would consider this as a shortcut for
advanced users and advice beginners to use subclassing.

[1]: http://github.com/bfirsh/django-class-based-views

-- 
Łukasz Rekucki

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to