HN2new | past | comments | ask | show | jobs | submit | mcdonc's commentslogin

But it has Zope in its name!!!111!! ;-)


It's best to keep object records small when using ZODB. This does mean you need to do some planning about object structure. Objects that inherit from "persistent.Persistent" are kept as separate records in ZODB, so you can break up a large object into several smaller ones by attaching persistent attributes to another object. If you just make a big structure out of nonpersistent objects, ZODB will have all the downsides of plain old pickle (like slow loading time for large objects) indeed, but its entire purpose is to allow you to not do this.


It does not unpickle every time you get something from cache. It maintains a first-level in-memory LRU per-thread object cache which is the actual Python object (not its pickle representation). In practice, that means you don't need to maintain your own results cache (with e.g. redis or memcached) as you do with most SQL-based systems. If it's slow for you, it's probably not due to its cache.

Write conflicts are indeed hairy to deal with. Using a BTree in places where you might instead use a dictionary usually makes this a lot better.

It sounds like you got burned by using it without understanding it very well.



Well, the author has direct experience porting and maintaining (very popular, well-written, well-tested) Python libraries, so I think it bears more weight than the platitudes I hear from "the other side" of "it will all work out in the end, it's just a matter of time." I think the latter line of reasoning is going to fail without any specifics of how it's really meant to "all work out" if issues like the ones he's given examples of in the blog post aren't treated seriously (particularly the straddling-2-and-3-issues).


2to3 isn't perfect but I've made it work for SQLAlchemy and Mako - the Mako port was very easy. SQLAlchemy was trickier, largely because we still support all the way back to Python 2.4 (we're moving to 2.5 for 0.8).

When I wrote Alembic just recently, I ran 2to3 on it and it literally needed two "file()" calls to be changed to "open()" and that's it.

The contradiction in Armin's post is that he starts off with "we don't like Python because its perfect, we like it because it always does a pretty good job, etc. etc.". Aside from Armin's very specific issues with codecs (I've never used codecs that way) and with the filesystem (OK, he's convinced me work is needed there), I don't quite see how 2to3 is any different than "not perfect, but does the job at the end of the day".

Also, we really shouldn't be fixating on 2to3 very much - it is already deprecated. We should be thinking/worrying very, very, much about 3to2. Since we really should be shooting to have our source in all Python 3 within a couple more years.


It may just be anecdotal at this point, but several highprofiles libraries have given up on 2to3 entirely and use the 2/3 common codebase approach: Jinja, django, ply. For a library, that's the approach that I find more practical.

I have a hard time seeing how one can use 2to3 on an everyday basis: it makes testing, distribution, etc... that much more painful because it is so slow (2to3 takes as much time as compiling all the C code from numpy, for example). It also removes one of the big plus of a language like python (modify code - see the result right away).


Amen, 2to3 in practice for anything but the smallest library is effectively unusable due to speed. Even if it weren't, I'm not much of a fan of maintaining generated code. That's an imposition I'm not really willing to put up with.


Using a Jenkins server with continuous integration makes Py3K testing pretty painless.

I really don't want projects to go back to maintaining two source trees, that was a disaster.


Just to further this sentiment, and perhaps even more worrisome, is how easily a language, even one as well established as Python, might fall out of favor. The fact that JavaScript usage is becoming ubiquitous as a scripting language was an example mitsuhiko was using of the challenges Python faces. Sure, the Python team can't stop that from happening, but they can stop pretending Python 3 is going to work just as soon as everyone gets on board with it. Hint: developers will adopt it when there are good reasons to use it and here the argument is that doing things more correctly (and consequently making life harder) is not a good enough reason when it comes to real world applications (Jinja2, Werkzeug, Flask, etc)


My objection to the idea that JS will so easily replace Python is that if you apply the same degree of analysis to JS that is causing you to reject Python, JS fares far worse. At least Python addresses the encoding issue, JS strings are far stupider, more dangerous, and require you to do a lot more of the paperwork if you can't assume an external environment that takes care of it for you (the browser, in this case). The next generation of JS fares somewhat better, if it is implemented according to the spec (and there quite a gulf betwixt a spec and an implementation), but when will you start being able to use that?

Try implementing even a medium-sized project in both Python and JS and tell me JS is a serious replacement, let alone for the large ones.


Armin mentioned JS as an example of a language that could come and be favorable to developers contra Python.

Like clojure, or something else. Indeed, as a newcomer to Python I wanted to pick up python 3 from the start, but went back to python 2 becuase of poor library support.

If in the future people still decide to go with what works, they might as well go with a completley different language, that just works, not becuase it is the correct way.


I doubt JS will ever replace Python and I doubt that is what Armin believes. That doesn't mean it cannot hurt Python significantly in terms of popularity and market share.


If JS gets to improve in the future, so does Python. Again, apply the same standards in both cases, which is my real point. Ranting about "accounting only the positives of one alternative and only the negatives of the other" is a bit of a hobby of mine. You can make anything look good or bad that way, but that appearance has no relationship to truth. You can't make good decisions that way, but people do it surprisingly often.

Also, encoding was one example. I could rant for hours about the ways in which Python is more suitable than JS(-of-today) for medium-or-greater sized projects.


I am certainly not denying that there are issues or saying that his issues don't need to be addressed.

However I'm a big proponent of 'breaking with the past' once in a while, to fix issues that have snuck into the language/library/system, and to clean up the cruft. Yes it will bring some frustrating porting, but the end result will be a cleaner more focused language.


Your original post (and to an extent your reply above) was a bit dismissive, I think. Dismissiveness is not really a unique sentiment here; I see a lot of posts along the lines of "well yes he's complaining but it's a break with the past and its for the better, it's just a matter of time, and it will all work out in the end, yada yada"..

My point is that for this to actually be true (as opposed to just being wishful thinking, which there's a lot of right now), people are going to have to not only port their libraries but they will also need to maintain the resulting code. If the library is at all popular already, the resulting code will, for some open-ended period of time (perhaps "forever") need to work on both Python 2 and Python 3. And right now, though producing a port isn't monstrously hard, maintaining the resulting code across the 2/3 straddle is just no fun. The code looks bad, it's harder to read, it's harder to maintain, it's just less fun overall. Basically, maintaining a Python 3 port just takes some of the fun and aesthetic out of maintaining an open source library. It's an imposition to those folks who want their code to be popular, forward-compatible, and beautiful due to the need to straddle.

IMO, I'm not sure that a Python 2.8 helps much here, but a more backwards compatible Python 3.3 would. For example: match py3 bytes behavior with py2 string behavior, add u'' literals back in, maybe readd iteritems/iterkeys/itervalues on dict as aliases so we can use a common API for dicts, add the print keyword back in maybe, and other minor things that are really easy to do and don't have much defensibility other than "it's cleaner to not have to have bw compat here".


Yes, a backward compatibility mode that could re-add those things would be nice (which could be enabled by adding a pragma "from __past__ import old_unicode_literals", for example). It would allow for a more gradual transition.


The pragma wouldn't really work. It'd have to work in all old versions of Python to make any sense, and it doesn't. For unicode literals in particular, it should just be true in Python 3.3+ that u'' = '' out of the box.


Breaking stuff is worthwhile if it brings other things in exchange. Cleaner is almost never a good enough reason in my experience. New features is what makes people willing to upgrade. People will evaluate whether porting is worth the pain over this feature vs effort line. Armin is not the only one who wonders whether it really is worths it.


But as more and more new features are being added to 3.x and not to 2.x (and assuming 3.x won't break compatibility with itself), won't there automatically be a point in which the features are worth the pain?

Even if not, the python devs are not trying to define this point for anyone, you can stay with 2.7 the rest of your life if you want to. I don't think a "2.x will no longer be maintained even for bugfixes" date has been established.


There may be a point at which the features may worth it, I don't see why it should be automatic.

Python 2.x is not going away, but staying at 2.7 is not a long term solution either.


It's not splitting hairs at all. It's the definition of the pattern. The pattern was created for stateful UI systems, and it can't be emulated with request-response frameworks without UI state kept on the client side.

But that said, the fact that Rails (and Pylons, etc) called themselves MVC has rendered any definition meaningless, so it just kind of doesn't matter. Truth be told, it was already getting there long before web frameworks entered the picture when Java coopted the term to mean something it didn't in the 90s.

I prefer to use different terminology to avoid confusion, but if you wanna keep using "MVC" for your own stuff, I'm not going to fight city hall.


this ^^



Seems pretty defensive to me. How does, say, separating out the route and the view declarations help your application? Code like this:

   config = Configurator()
   config.add_route('hello', '/hello/{name}')
   config.add_view(hello_world, route_name='hello')
is really just boilerplate, which is better done as a decorator. Count how many times the word 'hello' appears in that snippet above. And this is just for a hello world program. Once you start on a real app, that's only going to multiply.


In a more traditional Pyramid app it would be done more like:

    from pyramid.view import view_config
    from pyramid.response import Response
    from paste.httpserver import serve
    
    @view_config(route_name='hello')
    def hello_world(request):
        return Response('Hello %(person)s' % request.matchdict)
    
    if __name__ == '__main__':
        config = Configurator()
        config.add_route('hello', '/hello/{person}')
        config.scan()
        serve(config.make_wsgi_app())
The config.scan() bit causes the @view_config decorators to be picked up. So we do have some decorators, although they don't populate an external registry (by design).

The rationale for putting the route ordering in imperative code instead of using decorator declaration order is in the document I linked. I'm not particularly interested in crippling Pyramid for larger apps to race to the bottom of the LOC count. It's succinct enough and works for truly large apps too.


The ordering of your patterns matters, so that is done at config time. However it's very common to want to have unrelated code executed depending on the type of request to a URL. Pyramid will do this lookup for you, rather than polluting a gigantic view function with multiple code-paths for distinct functionality.

    @view_config(route_name='hello', request_method='GET')
    def get_hello(request):
        return Response('a GET request for %s' % request.matchdict['name'])

    @view_config(route_name='hello', request_method='POST')
    def post_hello(request):
        return Response('stored info')

    config = Configurator()
    config.add_route('hello', '/hello/{name}')
    config.scan()
    app = config.make_wsgi_app()


Bottle and Flask actually allow for this too. Bottle's variant:

   @route('/hello/:name', method='GET')
   def hello_get(name):
       return 'Hello %s' % name

   @route('/hello/:name', method='POST')
   def hello_post(name):
       return 'Hello %s' % name
Pyramid permits a larger variety of predicates (including custom ones), however: https://docs.pylonsproject.org/projects/pyramid/1.2/narr/vie...


Yes but while implicit route ordering works a lot of the time, I'll gladly keep Pyramid's concept of explicit ordering, which is the main source of verbosity in the Pyramid setup which separates routes from views.


The order the decorators are run at import time is explicit. Everybody loves module-scope programming and import-time side-effects! What's wrong with you man? ;-)


Comments with critical, dogmatic hyperboles in them like this drive me nuts in general. Here are the hyperboles in this comment with the translations to normal English.

- "saddled with any dependency baggage" == "has no dependencies"

- "beating on Flask" == "using Flask"

- "shrug" == "i didn't spend a lot of time on this"

- "Flask was completely unsuitable for that" == "I was unwilling to ask for help from the people who use Flask"

Additionally, Flask is also "easy to understand" and has "sane defaults", and it doesn't "require any boilerplate code" either. The context of the comment makes it seem like it's subpar on these things.

I'm all for people pointing out fitness of purpose for various frameworks, but this comment might have been better phrased as "I use Windows. I happened to find a recipe that let me run Bottle as a Windows service. That made it easier for me to use Bottle. Also, I like being able to deploy without the use of packaging tools."


You're right, I indulged in too much purple prose there. Sorry.

Would you expand on what you meant by:

> The context of the comment makes it seem like it's subpar on these things.

What I intended to get across was that Bottle, being a single file at ~2700 lines, makes it convenient to scan the code to see exactly what it is doing (or not). It also doesn't require a lot of typing to wire a function to a URL and offers some nice syntactic sugar while doing so: you don't have to @route things you can @get them or @post them (it's probably my Java background that makes me think in terms of separate code paths for the different HTTP verbs).

My take on a more detailed (and hopefully hyperbole-free) summation of my original post is:

"Because this was a short timeframe prototype, they had no Linux VM available in the lab so I had to use Windows. I found a recipe that let me run Python stuff as a service which I was able to wrap around Bottle more quickly than I was able to with the other frameworks I tried. Because I was working on a machine that had no access out to the internet, I had no virtualenv and had to instead bundle all my stuff up by hand."


Wow, great way to take criticism! Thank you.


Still a troll.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: