Python just got cooler for me

Being the Functional Programming fan i am, the following goes against every best functional programming practice. Fortunately, it's still good code :).

I'm trying to get some code with a few ugly 'global' objects in python to be reduced to something a bit more modular. Sometimes code is clearer than words:

>>> def foo():
... print foo.a
...
>>> foo.a = 1
>>> foo()
1
>>> foo.a
1
>>> foo.a = 2
>>> foo()
2

In otherwords, I have some value I need persistent between function calls. However, there's only one function that needs that value. I can store it in the function itself, and have it available.

The only unfortunate tragedy is that code like this still fails epically:

>>> 0.15 * 6
0.89999999999999991

7 flames:

Unknown zei

Not sure I'd actually want to do this myself in cases where a Class foo() wasn't just as easy, but very neat.

There may be some form of abuse with closures to be had, though I don't know presently what :)

Yankee zei

That class would be a singleton, not a normal class. Singletons are sometimes hackish, though python's gotten better with class properties and class methods.

Anoniem zei

Good one!

This is a neat trick if we want to change a function's behavior for particular instances in time (actually point in the sequence of execution).

Can also be useful if we want to change the behavior of a function that we passed to someone (of course that function should not depend on the function that it received not changing its behavior).

In most normal cases, if we want to parameterize a function with some value (which can be anything, including another function), the typical way in Python is to use a dumb old function-returning-nested function**.

>>>def mkfoo(a):
  def f():
    print a
  return f

>>> foo1 = mkfoo(1)
>>> foo1()
1
>>> foo2 = mkfoo(2)
>>> foo2()
2
>>> foo1()
1
>>>foo2()
2

This has the additional advantage that you can use the resulting function at any time, but if you change the one and only function object itself, it changes for all and becomes very dependent on the order in which you call it.

It depends on what you want to do with it.

**: of course pompous people will call it higher-order-functions instead :-)

Yankee zei

Yup, this is a completely different case though.

In my case, one function was appending and removing information from a global variable. Another function was using the global to render a prompt on screen. This was getting ugly.

I decided the modifier would have the 'canonical' version of the prompt data. It would then pass it to the renderer every time it needed to be drawn on screen.

Unknown zei

The thing is that your approach causes foo to become a global variable, which I suppose isn't *entirely* awful. The proper way to do it would be to create a class with a __call__() method and use the Borg pattern.

And just for kicks...

>>> from decimal import Decimal
>>> Decimal('0.15')*Decimal('6')
Decimal("0.90")

It's not Python's fault that IEEE 754 is lacking.

Anoniem zei

Sorry for not being clear:

Class ClassName:
blah

inst = X()

ClassName.foo = Z

not a singleton, but a scoped class variable.

Either way, I really do like the idea, for when you need to change the behavior of some code on an event without the code needing to be aware of it.

Yankee zei

All of these are great alternatives, but they suffer one major problem. They are too complicated. Once we call this a design pattern, we get caught up in some complicated syntax to make it more 'uniform' to other programmers who are also fans of Design Patterns.

I am not a fan of design patterns. I am a fan of code that is easy to read without any need to fit it in any 'pattern' in one's head. Any 'pattern' that has to override a method like __call__ or __new__ defeats that purpose because it creates a certain amount of line noise. There's always a trade off between how complex you want the code, for benefit down the road, or how readable you want the base code.

In this case a global variable is the answer, because it represents a global state in the program. Functional programming gets around this by using a Monad, which restricts access to the state to only functions that are also Monadic. In my case, I wanted to restrict access to a single function, so I made it a private data member of the function. Using a design pattern would just obfuscate this decision.