A per-activation "global" variable in Python? - python

This might seem like a rather weird thing to do, but I was curious if it was possible to implicitly pass a variable down a call chain in Python without passing it as an argument. To better illustrate here is an example:
Here is the "normal" way:
def three(something):
print(something)
def two(something):
# ...
three(something)
def one(something):
# ...
two(something)
And here is what I want to be able to do:
def three():
# something is defined implicitly
print(something)
def two():
# ...
three()
def one(something):
# somehow define something inside a context
# for this activation
two()
For the purpose of this, one, two and three are not in the same class or even the same module.

You don't want to do this.
If you are really convinced that you want to torture yourself, then you could create a separate thread and run the call to one() in that thread. Then just use threading.local for the shared state.
You really don't want to do this.
Here's how you can use thread local storage:
import threading
state = threading.local()
def three():
# something is defined implicitly
print(state.something)
def two():
# ...
three()
def one(something):
# somehow define something inside a context
# for this activation
def inner():
state.something = something
two()
t = threading.Thread(target=inner)
t.start()
t.join()
if __name__=='__main__':
one(42)
one(24)

If you must, you can assign values to the function object itself. Ideally, both three() and two() would perform checks that would raise better exceptions than an AttributeError if 'something' is not set correctly.
def three():
print(three.something)
def two():
three.something = two.something
three()
def one(something):
two.something = something
two()

You could take advantage of lexical closures - define two() and three() within the definition of one().
>>> def one(something):
... def two():
... three()
... def three():
... print something
... two()
...
>>> one(1)
1

You can use __builtins__ to hold your "global variables".
>>> __builtins__.something = "Hello world!"
>>> def foo():
print something
>>> foo()
Hello world!
This can help you avoid passing variables explicitly.
This is a terrible hack. IMHO, you really don't need to do that.

Related

How can I make #decorator and #decorator(args) share the same name?

I want to use two type of decorators:
a)
#new
def foo():
print("foo")
b)
#new(arg1, arg2, arg3, ...)
def bar():
print("bar")
Basically, I want to make different handlers for the "new message" event. You should be able to write #message.new if you'd like to use it for all the messages or #message.new(filter) if you only want the handler to override the unfiltered handler to process messages from certain people or only the messages that have certain attachments to them.
My first thought was that the decorator could check whether its first argument is a function. If it is, it would guess that it's being used as #message.new. If the first argument is not a function, it would return a decorator.
from inspect import isfunction
def new(*args):
x = args[0]
if isfunction(x):
return new_noargs(x)
else:
return gen_new_args(args)
def new_noargs(func):
def munc():
print("new_noargs")
func()
return munc
def gen_new_args(args):
def dec(func):
def zunc():
print("new_args:", args)
func()
return zunc
return dec
And it works:
#new
def foo():
print("foo")
#new(1,2,3)
def bar():
print("bar")
It looks very clumsy and unpythonic, though. Is there a more convenient way to solve my problem? Also, if I'd like to use #new(some_function), the current new method would decide that it's being called like this:
#new
def some_function():
...
How can I improve my code?
Workaround
#overengineer is a decorator that allows another decorator to be called without brackets. It's still too complicated, but more reusable.
def overengineer(decorator):
def dec(*args):
x = args[0]
if isfunction(x):
return decorator()(x)
else:
return decorator(*args)
return dec
#overengineer
def new(*args):
def dec(func):
def zunc():
print("args:", args)
func()
return zunc
return dec
I guess the premise of the question is flawed as I don't lose much by writing #new() instead of #new, but I gain consistency and simplicity: new is just a decorator. Alternatively, I could make two different decorators.

Check whether method is called directly or by another method

I'd like to know whether my method is called by the user directly or by another method. To make it less abstract:
class myclass():
def __init__(self, ...):
....
def method1(self, ...):
...
--- some if statement --
print "Hello"
return something
def callmethod(self, ...):
x = self.method1(...)
return x*2
myinstance = myclass(...)
myinstance.method1(...)
--> 'Hello'
myinstance.callmethod(...)
--> -
Hopefully my class makes clear what I'd like to do: When the user calls 'method1' the print statement shall be executed but if 'method1' is called by another method like 'callmethod' the print statement shall not be executed. Therefore I need 'some if statement' which checks whether 'method1' is called by the user directly or by another method. Thanks for you help!
No, and you don't want to do this.
If you want to change behaviour depending on the way a method is called, then you need to use a parameter. You can use a default value to make this simpler, for example:
def method1(self, do_print=True):
...
if do_print:
print "Hello"
return something
def callmethod(self, ...):
x = self.method1(do_print=False)
return x*2
Now, calling myinstance.method1() will print, whereas myinstance.callmethod() will not.
It's actually achievable using the python inspector, like e.g.:
import inspect
class myclass():
def __init__(self):
pass
def method1(self):
(frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1]
if function_name == '<module>':
print "Hello"
return 2
def callmethod(self):
x = self.method1()
return x*2
myinstance = myclass()
myinstance.method1()
myinstance.callmethod()
but I agree with Daniel it's not an elegant way to achieve the result as it hides some behaviour.
For further details also see: this post

Python - If a function is a first class object, can a function have a method?

I have a class which maintains a list of functions. These functions are just objects sitting in a queue and every so often the class pops one off and executes it. However, there are times when I would like to print out this list, and I'm imagining code as follows:
for function in self.control_queue:
print function.summarize()
if function.ready():
function()
In other words, I would like to call methods called summarize() and ready(), that I want to define somewhere, on these function objects. Also, I would like to be able to toss anonymous functions on this queue - i.e., generate everything dynamically.
you can make it a class and define __call__
class MyClass():
def summarize(self):
#summarize stuff
pass
def ready(self):
#ready stuff
pass
def _call__(self):
#put the code here, for when you call myClass()
pass
How you run it:
function = MyClass()
print function.summarize()
if function.ready():
function()
You have a couple possible approaches.
You could add the definitions to functions.
def foo():
pass
# later..
foo.summarize = lambda: "To pair with bar"
foo.ready = lambda: True
You could create class objects to wrap the function operation.
class Func():
def summarize(self):
return "Function!"
def ready(self):
return self.ready
def __call__(self):
# Act as a function
Or you can have a function which checks the function label for these capabilities.
def summarize_func(func):
return func.__name__ # Or branch here on specific names/attributes
def ready_func(func):
return True # Or branch on names/attributes
Finally to accommodate anonymous functions you can check for prescience of these attributes and return optimistically if the attributes are absent. Then you can combine above approaches with something that will work on any function.
def summarize_func(func):
if hasattr(func, summarize):
return func.summarize()
else:
# Note this will just be '<lambda>' for anonymous funcs
return func.__name__
def ready_func(func):
if hasattr(func, ready):
return func.ready()
else:
return True
One option is to implement function as a class instance:
class Function(object):
def summarize(self): pass # some relevant code here
def __call__(self): pass # and there
and use it later with
function = Function()
With __call__ magic method implemented, this function becomes a callable object.
For sure, you can assign attributes to functions, but it is rather obscure and conterintuitive:
>>> def summ(a): return sum(a)
...
>>> def function(a): return a
...
>>> function.sum=summ
>>> function.sum([1,2,3])
6

Why can't Python access a subfunction from outside?

def A():
def B():
#do something
a = A()
a.B()
Why isn't the above (such simple code) possible in Python? Is there a 'pythonic' (legible, unsurprising, non-hacky) workaround that does not turn A() into a class?
Edit 1: The above was explained to me that B is local to A, thus it only exists as long as A is being evaluated. So if we make it global (and be sure not to have it overriden), then why doesn't this work?
def A():
def B():
#do something
return A()
a = A()
a.B()
It says it's returning a 'NoneType' object.
Because a function definition just creates a name in the local namespace. What you are doing is no different than:
def f():
a = 2
and then asking why you can't access a from outside the function. Names bound inside a function are local to the function.
In addition, your proposed code is strange. when you do a = f(), you are setting a to the return value of the function. Your function returns nothing, so you can't hope to access anything through the return value. It is possible to return the inner function directly:
def f():
def g():
return "blah"
return g
>>> func = f()
>>> func()
'blah'
And this can indeed be useful. But there isn't a generic way to access things inside the function from outside except by modifying global variables (which is usually a bad idea) or returning the values. That's how functions work: they take inputs and return outputs; they don't make their innards available to the outside word.
To call B with the syntax you want, use:
def A():
def B():
print("I'm B")
A.B = B
return A
a = A()
a.B()
A.B()

Learning Python: print variable inside a function from another function

I want to do the following in python:
def func1():
var1 = "something"
def func2():
print var1
What is the correct mode to do this ? I've not found in documentation at all
PS. If possible, it's not my plan to make that 'var1' a global variable.
Thanks.
I assume you don't want to pass the variable as a parameter between the function calls. The normal way to share state between functions would be to define a class. It may be overkill for your particular problem, but it lets you have shared state and keep it under control:
class C:
def func1(self):
self.var1 = "something"
def func2(self):
print self.var1
foo = C()
foo.func1()
foo.func2()
No, it is not possible to do things like that. This is because of something called "scope". You can either create a module-level variable or place it in an OOP construct.
Well your func2() is trying to print a variable in the scope of another function. You can either
Return the value of var1 when calling func1 (eg. def func2(): print func1() }
Call func2 from func1 and pass the value of var1
You could try something like
def func1():
var1 = "something"
return var1
def func2():
print func1()
If you need func1 to do more things than just define var1, then maybe what you need is to define a class and create objects? See http://docs.python.org/tutorial/classes.html
You could try:
filename.py:
def func1():
var1 = "something"
def func2():
var = __ import__('filename').var1
print var

Categories