Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
hey mom its 420
May 12, 2007

Yeah I agree, Python is by far my favourite language. It's concise yet readable. It's just a joy to work in, I love how the modules work, the duck typing is great, all in all I really like it. Well, everything except the GIL in CPython, which basically prevents Python from running on multiple cores concurrently. However, there's a great module called Parallel Python which lets you do just that.

Adbot
ADBOT LOVES YOU

hey mom its 420
May 12, 2007

Yeah, the CPython implementation has the GIL. It was discussed in the beginning of the thread.
Basically good solutions if you want real threading are to use either ironpython or jython or a module like parallel python (which I really like and you should try it).

hey mom its 420
May 12, 2007

Haha, found this PEP on reddit, laffed.
http://www.python.org/dev/peps/pep-3117/

hey mom its 420
May 12, 2007

I'm getting into pygame right now and I think it's pretty cool, although does anyone else think that the documentation is lacking? It just seems that the function descriptions aren't as clear as they could be and there's never any example of usage.
For instance, there are key constans listen in the documentation for pygame.key but it doesn't say anywhere in exactly which namespace they are. I looked everywhere through the pygame.key namespace only to see that they're defined in the main module namespace.

hey mom its 420
May 12, 2007

Here's a good post from a guy who extended a function in C and got it to run from 30 seconds to 0.7 seconds. Pretty cool.
http://www.ginstrom.com/scribbles/2007/12/02/extending-python-with-c-a-case-study/

hey mom its 420
May 12, 2007

Here's an interesting one.
Do you guys think there's a way to pass data from decorators to the functions they're decorating without using those functions' call arguments or keyword arguments? I've given this some thought and I think there is no way, but if anyone can prove me wrong that sure would be great. If you could somehow manipulate the function's namespace before calling it or something, hmmm.

Here's an example of what I'm trying to do.
code:
>>> def clown_decorator(func):
...     def inner(*args, **kwargs):
...             return func(clowns=5, *args, **kwargs)
...     return inner
...
>>> @clown_decorator
... def bar(clowns):
...     print "There are %d clowns!" % clowns
...
>>> bar()
There are 5 clowns!
Here I pass the number of clowns via the function's arguments, but I'm wondering if there's a way to do it without having to place the `clowns` argument in the function definition for `bar`.

I'm not trying to solve a particular problem here (although it would come in handy with something I'm working on, but it's fine without it too), I'm just generally wondering if there's a way to do that in the language. My bets are on "no".

hey mom its 420
May 12, 2007

Yay, I found the answer!
Just do
code:
>>> def clown_decorator(func):
...     def inner(*args, **kwargs):
...             func.func_globals['clowns'] = 5
...             return func(*args, **kwargs)
...     return inner
...
Man, Python is awesome.

hey mom its 420
May 12, 2007

Haha! Yes, clown coding is the best coding.

Eh, it seems that this func_globals is not gonna work since it pollutes the global namespace and I don't want that.
code:
>>> def foo():
...     print clowns
...
>>> dir()
['__builtins__', '__doc__', '__name__', 'foo']
>>> foo.func_globals['clowns'] = 5
>>> dir()
['__builtins__', '__doc__', '__name__', 'clowns', 'foo']

I wonder if there's a way to just affect a function's local namespace?

hey mom its 420
May 12, 2007

Thanks guys, I'm glad we had this talk about clowns! :)

hey mom its 420
May 12, 2007

The reason I started thinking about this is because in a Django project I'm working on, I have this decorator which has really proven to be useful.
code:
def check_project_permissions(*args):
    """ 
    This function returns a decorator that checks if the user has all the permissions in *args.
    It is to be used to decorate views so that they require certain permissions to be accessed.
    Example usage:

        @check_permissions('view_issues')
        def issue_detail(request, slug ...

    Also, it can be given multiple permissions to check.
        
        @check_permissions('view_project','view_issues')
        def ...

    If the user doesn't have all the permissions listed in *args, a 403 error is returned and
    403.html is loaded as the template.
    Note that the use of this decorator mandates that the view receives the slug of the project
    as a keyword argument, not just a normal argument. That means that the urlconf must call it as
    ?P<slug>
    """
    required_permissions = args
    def the_decorator(func):
        from hgfront.project.models import Project
        from django.shortcuts import get_object_or_404
        from django.http import HttpResponseForbidden
        from django.template.loader import Context, render_to_string
        def inner(*args, **kwargs):
            request = args[0]
            project_permissions = get_object_or_404(Project, name_short=kwargs['slug']).get_permissions(request.user)
            for permission in required_permissions:
                if not getattr(project_permissions, permission):
                    return HttpResponseForbidden(render_to_string('403.html'))
            return func(*args, **kwargs)
        return inner
    return the_decorator
Basically each project is tied to members via the permissions they have in that project.
Now the thing is sometimes the view has to know what the permissions are (so for instance you don't see an `add issue` link if you don't have that permission) and so the database is queried twice for the same data, once in the decorator and once in the view. That's not a problem really because everything is properly indexed and runs fine and dandy, so it's more curiosity than anything else.

hey mom its 420
May 12, 2007

Does anyone know if there's any plan to implement proper closures in Python? I don't follow python-dev or anything, maybe someone here is more into that scene. I've been playing around with Ruby and while I generally like how Python does stuff (list comprehensions, less syntax, functions are objects, everything is visible) better, I really like the closures in Ruby.

I've noticed that closures in Ruby usually achieve three things, which are:
1. Iterators
2. Doing preliminary actions before a block and clean-up actions after it (for instance, opening and closing a file)
3. Passing behavior to functions (for instance, telling buttons what to do)

And I can't shake the feeling that Python should have gotten something very, very similar. It's true that Python supports all these three things, but it uses three different language constructs to do so and passing behavior to functions is not really elegant.

It does iterators with generators, so in Ruby you'd do, for instance
code:
some_collection.each {|item| puts item}
Whereas in Python you'd do
code:
for item in some_collection: print item
Then you have preliminary and clean-up actions. A Ruby example:
code:
File.open('myfile.txt').each_line { |line| puts line}
And in Python you'd do:
code:
with open('myfile.txt') as f:
  for line in f.readlines():
    print line
Keep in mind that you could emulate the with statement in Ruby
code:
def with var
  begin
    var.__enter__
    yield var
  ensure
    var.__exit__
end
And then there's passing of behavior and such. In Ruby, you'd do, say:
code:
click_counter = 0
button = Button.new('button_name') { click_counter += 1 }
Whereas in Python, now is the time when things get a bit messy.
code:
click_counter = [0]
def inner():
  click_counter[0] += 1
button = Button('button_name', inner)
Because a function can only change its own namespace, we had to wrap the click_counter in a mutable object and change the object. Then we had to define a function (and pollute the namespace) just so we can pass it to the button.

Now notice that Ruby achieves all these three things with a single language construct whereas Python uses three and the last one is a bit wonky. But there's a problem, because if you introduced closures like in Ruby, you'd have several ways of implementing with statements and iterators and that would be unpythonic or something. But the usefulness is evident and it would be really nice to have closures for doing stuff like in the third example.

EDIT: Maybe something like
code:
click_counter = 0
button = Button('button_name') do:
  click_counter +=1
Internally, the block would be called with something similar to the yield statement.

hey mom its 420 fucked around with this message at 11:49 on Jan 15, 2008

hey mom its 420
May 12, 2007

Well, if I had everything figured out on this would it would already be submitted as a PEP :D

You're right, there are tricks and things to watch out for with implementing closures like that, but I still feel it would be worth thinking out.

You say that a whole slew of helper functions are involved in Ruby's closures, could you elaborate on that? I thought that some_collection.each in Ruby just iterates through the elements of the collection and yields the supplied block for every element, passing the element to the block.

Also, what do you mean when you say that you don't know the underlying control flow? The block you supply to the function will be yielded once or many times, that's it. It's the same with Python's generators, it will yield the values it goes through but you don't know what control flow it uses to get those values. Personally I don't think we you should care about what kind of control flow the internals of a function use, I just want it properly encapsulated and to do what it says in the documentation.

There's a PEP (342) that I'm going through and trying to wrap my head around, it seems to put on a whole bunch of methods to generators and makes yield behave differently depending on context (also it seems strange to me that in python, something that's called like 'yield val' and not 'yield(val)' returns a value) to achieve coroutines, anyone got any comments on this PEP?

hey mom its 420
May 12, 2007

bitprophet: Yo that's way cool! Will it be aimed at intermediate or beginner users? If you ever need to test the book out on someone or something like that, let me know!

A note to anyone who is using Mediatemple hosting - they're developing Django support right now and are looking for people who have gridserver accounts there to test it out. I have an account there so I signed up.

hey mom its 420
May 12, 2007

In the app I'm working on, we got it organized like this
code:
myproject/
  app1/
    /package_1
    /package_2
    /package_3
    /templates
      /base.html
      /package_1
        /modelname_detail.html
        /modelname_list.html
        /modelanem_create.html
        /modelname_something_or_other.html
      /package_2
        /modelname_detail.html
        /modelname_list.html
        /modelanem_create.html
        /modelname_something_or_other.html
      /package_3
        /modelname_detail.html
        /modelname_list.html
        /modelanem_create.html
        /modelname_something_or_other.html

hey mom its 420
May 12, 2007

That's a cool solution!
I also had a similar problem where we were filtering issues in a bug tracking system and at first also has a big if tree, but then I refactored it into this bit of code:
code:
    #check if we're filtering the issues by completed and if we are, filter the selection
    if request.GET.has_key('completed'):
        issues = issues.filter(finished_date__isnull = False if request.GET['completed']=='yes' else True)

    #modify the querydict so it doesn't have completed and page in it
    GET_copy = request.GET.copy()
    if GET_copy.has_key('completed'):
        del GET_copy['completed']
    if GET_copy.has_key('page'):
        del GET_copy['page']

    #filter the issues by what's left
    issues = issues.filter(**dict([(str(key),str(value)) for key,value in GET_copy.items()]))
There are two special values, which are pages (which is for the page you're on) and completed, because we aren't using a completed boolean field in the database but rather we check if finished_date is null or not.
The magic is in the last line, which takes the querystring, turns it into a dict and uses it as arguments for the filter method. So you can do any kind of filtering you want off the bat, for example: ?page=1&issue_type__slug=bug&issue_status__slug=accepted&completed=no

hey mom its 420
May 12, 2007

Also, does anyone know how to switch databases on the fly in Django? Or if that's even possible.
I need that because when unit testing, I supply a JSON fixture that the tests use as sample data. When the tests are run, a temporary database is created and used and destroyed after the tests are done. But I'd like to pull some data from the regular database in the tests. That's because we've moved some setting values from settings.py (in order not to clutter it up too much) to the database and it would be cool to get those settings in the tests because they reference folders on your machine and I want the tests to be portable across machines.

hey mom its 420
May 12, 2007

How exactly is that variable global? Can someone please explain to me? I would have thought `value` is not put in the global namespace when doing
code:
self.value = value = self.value + 1
but in the method's namespace.

hey mom its 420
May 12, 2007

No Safe Word: Umm, could you perhaps provide a working example of how that works?
Here's what my interpreter says:
code:
>>> class Moo:
...   def __init__(self):
...     self.value = 0
...   def incme(self):
...     self.value = value = self.value + 1
...
>>> t = Moo()
>>> t.incme()
>>> value
5
>>> t.value
1
>>> t.incme()
>>> t.value
2
I'm pretty sure that
code:
self.value = value = self.value +1
creates a variable called `value` in the method's namespace that overshades the one in the global.

hey mom its 420
May 12, 2007

Ah yeah, glad we got this cleared up. I knew about accessing variables from parent namespaces.

They're planning to implement a keyword called nonlocal, which would allow you to alter parent namespaces, which I think is pretty cool but isn't as cool as real closures.

hey mom its 420
May 12, 2007

Use r'\bword\b' or '\\bword\\b'

hey mom its 420
May 12, 2007

Here's a cool thing I've just found out while doing some stuff for school. The zip function works as its own inverse. So you can do stuff like this
code:
>>> a = [1,2,3,4,5]
>>> b = ['a','b','c','d','e']
>>> zipped = zip(a, b)
>>> zipped
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')]
>>> c, d = zip(*zipped) #this is the magic
>>> c
(1, 2, 3, 4, 5)
>>> d
('a', 'b', 'c', 'd', 'e')
I was kind of racking my brain about why this works actually, but then I thought about how it's best to imagine zip works. If you have two collections, we'll name them collections 1 and 2
code:
1: A B C D E
2: a b c d e
and when you zip that, zip just flips it about, so you end up with collections 1, 2, 3, 4 and 5
code:
1: A a
2: B b
3: C c 
4: D d
5: E e
So zipping that up again gives you back the original. So zip is its own inverse. f(x) = f^-1(x)

hey mom its 420 fucked around with this message at 17:45 on Mar 14, 2008

hey mom its 420
May 12, 2007

Habnabit posted:

code:
'' if c > 0x99 else '0'
v:shobon:v

Yeah, that is the prefered usage but I don't think Jython supports that yet.

Does anyone know if they'll be changing yield to a function in Py3k? It seems kind of silly not to, because they're already changing print to a function and now yield can give you a return value so writing foo = (yield value) instead of foo = yield(value) just seems kind of hackish and like it doesn't go along with the rest of Python.

hey mom its 420
May 12, 2007

If you make helper functions just so they're used once, you can always cram them in a lambda if you want stuff in one line. So your example can become:
code:
def convert(self, data, offset, size):
	return 'buffer db \n\t' + '\n\t'.join( \
        (lambda seq, length:[seq[i:i+length] for i in range(0, len(seq), length)]) \
        (', '.join([ '0%02Xh' % (c & 0xFF) for c in (list(data))[offset:offset + size]]), 60))

hey mom its 420
May 12, 2007

Yeah, I'm all for readability and I'd suggest going that way too. It's the most important characteristic of code, apart from elegance. Make the code so people can read it first, then for computers.

But he mentioned that he wants the code to be as short as possible, so that's why I posted that solution. Although that presents the question, why would anyone want shortness of code over readability, apart from maybe limited storage space, but I doubt that's the issue..

hey mom its 420
May 12, 2007

Ech. Performance, schmerformance!

hey mom its 420
May 12, 2007

I don't know if you're allowed to use it, but you can do this:
code:
>>> a = 11010 #binary equivalent to 26
>>> int(str(a), 2) #the second argument is the base
26
Also what do you mean use division to substring them? Can you provide an example of your desired result on a certain string?

hey mom its 420
May 12, 2007

Aha, well if you're doing that with a string, you can do it like this.
code:
>>> st = "9876"
>>> print ', '.join(st)
9, 8, 7, 6
Or if you have an integer and you want to get the digits without converting it into a string, keep in mind that
code:
>>> 9876 % 10
6

hey mom its 420
May 12, 2007

Here's an interesting way to split an integer into digits without converting to strings.
code:
def split_to_digits(n):
  return [n] if n < 10 else split_to_digits(n/10) + [n%10]

hey mom its 420 fucked around with this message at 12:22 on Apr 3, 2008

hey mom its 420
May 12, 2007

lst :science:

hey mom its 420
May 12, 2007

Doing stuff like that is generally not cool. You're using exec, polluting your global namespace, etc. I don't know what you ultimately achieve here since you only gave us a part of the code, but why not use a dict? A dict is used to map keys to values and it seems like that's what you're doing here.

So I'd prefer
code:
enums = {}
for i, id in enumerate(enumIDs):
  enums[id] = i
Or more tersely:
code:
import itertools
enums = dict(zip(enumIDs, itertools.count()))
And then you access it like so
code:
>>> enums['ID_NEWPROJECT']
0
Also, why are you storing numbers as strings? It's generally better to store them purely as numbers because if you need them in string form at some point, you can always just do str(x) later.

hey mom its 420
May 12, 2007

Ah, yeah, right, the str is for the exec.

Anyway, if all the data that goes into exec is from within your system, you're technically safe. In your case, it's right there in the same script, hardcoded by you, so it comes from within your system. If data you put in exec comes from some untrusted source (like the user), then it's a vulnerability.
The thing why it's bad to use exec generally is because you may one day decide that something that you hardcoded previously should come from the user and you may not notice that it later gets fed into exec.

Putting stuff like that into the global namespace is not considered good practice, since that can easily lead to name mix-ups and it's best to have everything in the smallest scope that you need. True, the namespace is represented as a dict, but it's important what's in which dict and it's nice to have stuff nicely scoped.

But if you really want to put those names in the global namespace, you could achieve the same functionality without using exec like so:
code:
for i, id in enumerate(enumIDs):
  globals()[id] = i
That would make it behave like the example you previously posted, only without the pesky exec.

hey mom its 420
May 12, 2007

The thing with for loops is that you specify which variable you want each element of the list you're iterating over bound too. So you could just as well do
code:
for snoop_dogg_and_dr_dre in shoplist:
    print snoop_dogg_and_dr_dre,
It would work just nicely, only it's not very descriptive.

hey mom its 420
May 12, 2007

Yeah, he was on spot. Python has drivers for mostly any kind of SQL database and can interact with them easily. Also Django is a web framework for Python, which makes it really easy to make web sites and web applications that use databases and all the Python knowledge you have is of course of great use with Django.

Python is so widespread and generally useful that you pretty much can't miss with Python for any kind of use, but especially for web and databases.

Also Google's App Engine is Python. It's a hosting environment for web Python program's by Google, also very cool and hip right now.

hey mom its 420
May 12, 2007

try
code:
dict(((x,y),data[x][y]) for x in range(0,10) for y in range(0,10))
You can pass a generator expression (that's like a list comprehension only in parens but it creates a generator) to the dict function. For instance, dict((x,x*2) for x in range(0,4)) will return {0: 0, 1: 2, 2: 4, 3: 6}. dict([(x,x*2) for x in range(0,4)]) would produce an equivalent result, only it would be less efficient. Also dict([(0,0),(1,2),(2,4),(3,6)]) is equivalent to the previous ones.

Also, it's not cool to use dict as a variable name, since the aforementioned function is named that way.

hey mom its 420 fucked around with this message at 23:08 on May 14, 2008

hey mom its 420
May 12, 2007

Yeah it's really easy to make really powerful one liners with Python, especially with generator expressions and the itertools module. I admit I submit to the urge a bit too often. But when you're just out to quickly make some code to one-tiem calculate something you need, it's great.
For instance, I had a file that had 1 line for every hour in year 2007 and each line had the level of the tide on the Adriatic sea coast at that hour. It took me just 5 lines to read the file and get a list that has 24 values, each representing the average tide level for the hour over a year.

hey mom its 420
May 12, 2007

Yeah it's good practice to maximize generator use and minimize lists. Of course it's cool to use lists for stuff you know will be small, but it doesn't cost you anything to use generators and generator expressions, but you will save on memory space when the data sets get big.

hey mom its 420
May 12, 2007

sum is a function that takes anything you can iterate over and gives you the sum of all the elements. You can iterate over a list, a generator, a file or something completely different.

You could do this
code:
digit_generator = (int(x) for x in str(123456789))
sum(digit_generator)
When doing something in the form of F(x) for x in blah without the angled brackets, that creates a generator. A generator is much like a list, but instead of storing all those list elements in memory, it will calculate one element at a time and return them to you as you ask for them. Also you can do stuff like:
code:
>>> digit_generator = (int(x) for x in str(123456789))
>>> digit_generator
<generator object at 0x7ff2910c>
>>> digit_generator.next()
1
>>> digit_generator.next()
2
>>> digit_generator.next()
3
The second code you provided is much more traditional, if you will. You make a variable to hold the sum, go over all the elements and add the value of each one to the sum.

hey mom its 420
May 12, 2007

As far as I understand it, % is not going away, but there will be a sort of templating mini language available for more advanced stuff. Although from my usage, I've never caught myself saying "Gee golly, I wish there was something more advanced than the % operator built right into Python!" because it, along with regexes, has suited all my string manipulating needs so far.

hey mom its 420
May 12, 2007

Well you seem to have it solved quite nicely, maybe you could rewrite it like this
code:
def dictref(d, keys):
  return dictref(d[keys.pop(0)],keys) if keys else d
You could make it a complete one liner using a lambda, but it's generally not a good idea to use recursion with lambdas because it uses the local scope of its definition instead of its own scope for recursing. So stuff like this can happen.
code:
>>> take = lambda lst, n: lst[:1] + take(lst[1:],n-1) if n else []
>>> take([1,2,3,4],2)
[1, 2]
>>> fake_take = take
>>> del take
>>> fake_take([1,2,3,4],2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
NameError: global name 'take' is not defined

Adbot
ADBOT LOVES YOU

hey mom its 420
May 12, 2007

Whoops, my bad! It seems that deleting normal functions also exhibits this behavior. I don't know why, but I thought that inside a function, the function name overshadowed the function name in the parent namespace or was set if it wasn't present. Most interesting indeed. Anyone have any ideas on how to get around this problem in normal functions? Something like
code:
arguments.callee
that javascript has, maybe.

So anyway yeah, you could make this a lambda then, like so
code:
dictref = lambda d, keys: dictref(d[keys.pop(0)], keys) if keys else d

  • Locked thread