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.