This question already has an answer here:
How to call a compiled function body?
(1 answer)
Closed 2 years ago.
Is there a way I could access a function that is nested inside another function. For example, I have this block of code right here. For example, I did f().s() but it did not work:
def f():
def s():
print(13)
Yes, you can:
def f():
def s():
print(13)
return s
Then you can call:
>>> f()()
13
Or if you want to have f().s():
def f():
class S:
def s():
print(13)
return S
You need to specify that the second function is a global var, then you'd need to call the first function in order for Python interpreter to create that second function.
See below;
>>> def foo():
... global bar
... def bar():
... print("Hello world!")
...
>>> bar()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'bar' is not defined
>>> foo()
>>> bar()
Hello world!
>>>
you certainly could do something
def f():
def s():
print("S")
return s
f()()
you could also expose them in an internal dict
def f(cmd):
return {"s": lambda: do_something_s,"y": lambda: do_something_y}.get(cmd,lambda:invalid_cmd)()
then use f("s") or f("y")
none of these are likely to be the correct solution to what you are actually trying to achieve ...
Related
I have this code:
def foo(bar):
def test(some_string):
return 'Decorator test: '+bar(some_string)
return test
def main():
print(bar('test1'))
#foo
def bar(some_string):
return some_string[:3]
I understand that calling bar('test1) is basically calling foo(bar('test1')), but when I try to print some_string in foo before the other function, I get some_string is not defined:
def foo(bar):
print(some_string)
def test(some_string):
return 'Decorator test: '+bar(some_string)
return test
How does test know about some_string while foo doesn't?
Why do I have to return test for the decorator to work? returning directly Decorator test: '+bar(some_string) doesn't work as some_string is not defined.
I understand that calling bar('test1) is basically calling foo(bar('test1'))
No, it is not, your understanding is incorrect. It is basically calling
foo(bar)('test')
The #foo decorator syntax tells Python to call foo() passing in the function object named by bar (and the result is assigned back to the name bar).
The foo() decorator returned a new function object:
def test(some_string):
# ...
return test
So the result of foo(bar) is that function object named test (a local name in the foo() decorator). foo(bar)('test') thus called test('test').
If you wanted to print the argument passed to test(..), do so inside that function:
def foo(bar):
def test(some_string):
print(some_string)
return 'Decorator test: '+bar(some_string)
return test
I understand that calling bar('test1) is basically calling foo(bar('test1'))
No, that is incorrect.
Calling bar('test1') is equivalent to
bar = foo(bar)
bar('test1')
Why do I have to return test for the decorator to work? returning directly Decorator test: '+bar(some_string) doesn't work as some_string is not defined.
When you do
#decorator
def func():
pass
Python translates it to
def func():
pass
func = decorator(func)
As you can see, Python expects decorator to return a new function. This is why you must return test from foo for bar to work correctly. Otherwise, None is assigned to bar:
>>> def foo(bar):
def test(some_string):
return 'Decorator test: '+bar(some_string)
>>> #foo
def bar(some_string):
return some_string[:3]
>>> bar()
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
bar()
TypeError: 'NoneType' object is not callable
How does test know about some_string while foo doesn't?
Simply because some_string isn't created until test is reached. some_string is a parameter of test, so it exists only in the scope of test. Otherwise, no name some_string exist, so you'll get a NameError if you try to access it - including inside of foo.
If you want to print the value of some_string, do so inside of test:
def foo(bar):
def test(some_string):
print(some_string)
return 'Decorator test: '+bar(some_string)
return test
This question already has answers here:
Python: weird "NameError: name ... is not defined" in an 'exec' environment
(2 answers)
Closed 7 years ago.
You can define both classes and functions in exec'd code without problems:
my_func = """
def test_func():
print "Hi from test_func!"
"""
my_class = """
class test_class:
def __init__(self):
self.a = "a"
"""
def call_func():
exec(my_func)
test_func()
def call_class():
exec(my_class)
a = test_class()
>>> call_func()
Hi from test_func!
>>> call_class()
a
However, defining both a class and a function that uses that class in exec'd code results in a NameError, because the class doesn't end up in the correct scope:
my_class_fun = """
class test_class_2:
def __init__(self):
self.a = "a"
def test_func_2():
a = test_class_2()
print(a.a)
"""
def test_2():
exec(my_class_fun)
test_func_2()
>>> test_2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in test_2
File "<string>", line 7, in test_func_2
NameError: global name 'test_class_2' is not defined
Passing globals() as the second argument to exec so that everything ends up in the global namespace fixes this problem.
My question is, why is that necessary? test_class_2 and test_func_2 seem like they should both be local to test_2, so why doesn't test_func_2 have access to test_class_2?
EDIT:
Fundamentally, my question is why is test_2() above different from something like this code, which works fine:
def test_func():
class test_class:
def __init__(self):
self.a = "a"
def test_func_inner():
c = test_class()
print(c.a)
test_func_inner()
>>> test_func()
a
Because your class (and function) not in global space
Demo:
>>> def test_2():
... exec(my_class_fun)
... global test_class_2
... global test_func_2
... test_func_2()
...
>>> test_2()
a
Is there a way to define a function to be global from within a class( or from within another function, as matter of fact)? Something similar to defining a global variable.
Functions are added to the current namespace like any other name would be added. That means you can use the global keyword inside a function or method:
def create_global_function():
global foo
def foo(): return 'bar'
The same applies to a class body or method:
class ClassWithGlobalFunction:
global spam
def spam(): return 'eggs'
def method(self):
global monty
def monty(): return 'python'
with the difference that spam will be defined immediately as top-level class bodies are executed on import.
Like all uses of global you probably want to rethink the problem and find another way to solve it. You could return the function so created instead, for example.
Demo:
>>> def create_global_function():
... global foo
... def foo(): return 'bar'
...
>>> foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
>>> create_global_function()
>>> foo
<function foo at 0x102a0c7d0>
>>> foo()
'bar'
>>> class ClassWithGlobalFunction:
... global spam
... def spam(): return 'eggs'
... def method(self):
... global monty
... def monty(): return 'python'
...
>>> spam
<function spam at 0x102a0cb18>
>>> spam()
'eggs'
>>> monty
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'monty' is not defined
>>> ClassWithGlobalFunction().method()
>>> monty()
'python'
You can use global to declare a global function from within a class. The problem with doing that is you can not use it with a class scope so might as well declare it outside the class.
class X:
global d
def d():
print 'I might be defined in a class, but I\'m global'
>> X.d
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'X' object has no attribute 'd'
>> d()
I might be defined in a class, but I'm global
I found a case where global does not have the desired effect: inside .pdbrc file. If you define functions in .pdbrc they will only be available from the stack frame from which pdb.set_trace() was called.
However, you can add a function globally, so that it will be available in all stack frames, by using an alternative syntax:
def cow(): print("I'm a cow")
globals()['cow']=cow
I've tested that it also works in place of the global keyword in at least the simplest case:
def fish():
def cow():
print("I'm a cow")
globals()['cow']=cow
Despite being more verbose, I thought it was worth sharing this alternative syntax. I have not tested it extensively so I can't comment on its limitations vs using the global keyword.
How to I declare a default value in a python object?
Without a python object it looks fine:
def obj(x={123:'a',456:'b'}):
return x
fb = obj()
print fb
With a python object I get the following error:
def foobar():
def __init__(self,x={123:'a',456:'b'}):
self.x = x
def getStuff(self,field):
return x[field]
fb = foobar()
print fb.x
Traceback (most recent call last):
File "testclass.py", line 9, in <module>
print fb.x
AttributeError: 'NoneType' object has no attribute 'x'
How do I get the object to return the value of a variable in the object?
With a python object, I got an error:
def foobar():
def __init__(self,x={123:'a',456:'b'}):
self.x = x
def getStuff(self,field):
return x[field]
fb2 = foobar({678:'c'})
print fb2.getStuff(678)
Traceback (most recent call last):
File "testclass.py", line 8, in <module>
fb2 = foobar({678:'c'})
TypeError: foobar() takes no arguments (1 given)
You didn't define a class, you defined a function with nested functions.
def foobar():
def __init__(self,x={123:'a',456:'b'}):
self.x = x
def getStuff(self,field):
return x[field]
Use class to define a class instead:
class foobar:
def __init__(self,x={123:'a',456:'b'}):
self.x = x
def getStuff(self, field):
return self.x[field]
Note that you need to refer to self.x in getStuff().
Demo:
>>> class foobar:
... def __init__(self,x={123:'a',456:'b'}):
... self.x = x
... def getStuff(self, field):
... return self.x[field]
...
>>> fb = foobar()
>>> print fb.x
{456: 'b', 123: 'a'}
Do note that using a mutable value for a function keyword argument default is generally not a good idea. Function arguments are defined once, and can lead to unexpected errors, as now all your classes share the same dictionary.
See "Least Astonishment" and the Mutable Default Argument.
to define a class in python you have to use
class classname(parentclass):
def __init__():
<insert code>
With your code you're declaring a method not a class
Use
class foobar:
instead of
def foobar():
I'm trying clean implement of Objective-C's category in Python, and found this answer to similar question of mine. I copied the code below:
categories.py
class category(object):
def __init__(self, mainModule, override = True):
self.mainModule = mainModule
self.override = override
def __call__(self, function):
if self.override or function.__name__ not in dir(self.mainModule):
setattr(self.mainModule, function.__name__, function)
But I do not want to waste namespace.
By using this `categories', there remains a variable as NoneType object like below:
>>> from categories import category
>>> class Test(object):
... pass
...
>>> #category(Test)
... def foobar(self, msg):
... print msg
...
>>> test = Test()
>>> test.foobar('hello world')
hello world
>>> type(foobar)
<type 'NoneType'>
>>>
I want it to be like below
>>> from categories import category
>>> class Test(object):
... pass
...
>>> #category(Test)
... def foobar(self, msg):
... print msg
...
>>> test = Test()
>>> test.foobar('hello world')
hello world
>>> type(foobar)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foobar' is not defined
>>>
Is there anyway to delete it automatically like below?
def __call__(self, function):
if self.override or function.__name__ not in dir(self.mainModule):
setattr(self.mainModule, function.__name__, function)
del(somewhere.function.__name__)
I found that sys._getframe give me some useful information. But I couldn't make it by myself.
No, there's no way to automatically do that. You would have to manually delete the name afterwards. category here is a decorator, which means that
#category(Test)
def f():
...
is the same as
def f():
...
f = category(Test)(f)
Even if, from inside category, you could delete the name in the outer scope, it wouldn't be enough, because that name is rebound after the decorator executes.
The code that you linked to borders on an abuse of the decorator syntax. Decorators are meant to provide a way to modify or extend the function they decorate, but that code relies on side-effects of the decorator (namely, assigning the function as a method of a class), and then discards the function. But it can only "discard" it by returning None, so None remains bound to the function's name, as you saw.
I would recommend you follow the advice of the highest-voted answer on that question, and simply assign new methods to your classes. There is no real need for an "infrastructure" like categories in Python, because you can just directly add new methods to existing classes whenever you want.
While I completely agree with what BrenBarn said, you could split the function removal into a later step. The problem is that after the decorator executed, the variable is reassigned. So you cannot perform the removal within the decorator itself.
You could however remember the functions and remove them from the module at a later point.
class category(object):
functions = []
def __init__(self, mainModule, override = True):
self.mainModule = mainModule
self.override = override
def __call__(self, function):
if self.override or function.__name__ not in dir(self.mainModule):
setattr(self.mainModule, function.__name__, function)
self.functions.append((inspect.getmodule(function), function.__name__))
return self.dummy
#staticmethod
def dummy():
pass
#classmethod
def cleanUp(cls):
for module, name in cls.functions:
if hasattr(module, name) and getattr(module, name) == cls.dummy:
delattr(module, name)
cls.functions = []
This category type will remember the functions it decorates and stores the names and modules they belong to for a later cleanup. The decorator also returns a special dummy function so that the cleanup can ensure that the variable was not reassigned later.
>>> class Test(object): pass
>>> #category(Test)
def foobar(self, msg):
print(msg)
>>> #category(Test)
def hello_world(self):
print('Hello world')
>>> test = Test()
>>> test.foobar('xy')
xy
>>> test.hello_world()
Hello world
>>> type(foobar)
<class 'function'>
>>> type(hello_world)
<class 'function'>
>>> category.cleanUp()
>>> type(foobar)
Traceback (most recent call last):
File "<pyshell#26>", line 1, in <module>
type(foobar)
NameError: name 'foobar' is not defined
>>> type(hello_world)
Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
type(hello_world)
NameError: name 'hello_world' is not defined