Why can't Python access a subfunction from outside? - python

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()

Related

How do I check if a variable exists, inside a Function?

I'm trying so check if a variable exists, but inside a function.
I was taught that, to do this, the only thing you needed to do was:
'a' in locals()
Unfortunately, things turned out to be a little bit more difficult than I expected.
I tried to define a function that included this method.
q=[1,2,3]
def f():
print('q' in locals())
When I run this function, it returns:
False
The problem is, as we can see, that q is a variable, so when I run the same command, but outside the function:
'q' in locals()
It returns:
True
Is there a way to solve this?
You may test for the existence of your list q in the globals() dictionary, since it exists in global scope, not the local scope of your function f, i.e.:
def f():
print('q' in globals())
As pointed out in the comments, testing the existence of variables using their string names like this is not ideal and you may instead use a try/except:
def f():
try:
# Do something with q
print(q)
except NameError:
print("Variable not defined")
When you code the following lines
q=[1,2,3]
def f():
print('q' in locals())
f()
Here, variable 'q' is not local to function f() as it is declared outside the function scope.Inside the function, q can be accessed using global.
But, outside the function 'q' is a local variable.
Therefore, when you check inside the function
q=[1,2,3]
def f():
print('q' in locals())
it will return False
But if you declare inside the function and check as follow:-
def f():
q=[1,2,3]
print('q' in locals())
It will return True as q is now local to the function.
Also if you check 'q' inside the function as global it will return True as 'q' is declared outside the function and has global scope.
q=[1,2,3]
def f():
print('q' in globals())
f()
Output
True
you can use
hasattr(obj, "var")
and replace obj with self
class test():
def __init__(self):
self.a = 1
def check(self, var):
return hasattr(self, var)
t = test()
print(t.check("a"))
print(t.check("b"))
output
True
False

Why python understanding "self", "this" and "that"?

I am new to Python with Java background, the concept of "self" in function confuses me. I understand first argument "self" mean the object itself, but I do not understand how Python make this work. I also know that I could use "this" or "that" or "somethingElse", and Python would still understanding I mean to use the object.
I copied some code from a reddit post:
class A():
def __init__(self):
self.value = ""
def b(this):
this.value = "b"
def c(that):
that.value = "c"
a = A()
print(a.value)
a.b()
print(a.value)
>>>"b"
a.c()
print(a.value)
>>>"c"
How do python knows I do not mean to use an object here in the first argument? For example I modified the above code a bit:
class A():
def __init__(self):
self.value = ""
def b(this):
this.value = "b"
def c(that):
that.value = "c"
def somethingElse(someObjectIWantToPass):
someObjectIWantToPass.value = "still referring A.value"
class B():
def __init__(self):
self.value = ""
a = A()
print(a.value)
a.b()
print(a.value)
a.c()
print(a.value)
a.somethingElse()
print(a.value)
b = B()
a.somethingElse(b)
print (b.value)
And it broke:
b
c
still referring A.value
Traceback (most recent call last):
File "D:/Documents/test.py", line 32, in <module>
a.somethingElse(b)
TypeError: somethingElse() takes 1 positional argument but 2 were given
A method's first argument is always1 its instance. Calling it self is idiomatic in Python but that name is strictly convention.
class A():
def some_method(me): # not called `self`
print(str(id(me))
a = A()
a.some_method()
print(id(a))
If you're trying to pass another arbitrary object in, it has to be the second argument.
class B():
def another_method(self, other):
print(id(other))
b = B()
b.another_method(a)
print(id(b)) # different!
print(id(a)) # the same.
1 Not actually always. #classmethod decorated methods use cls as their first argument, and #staticmethod` decorated methods have nothing passed to its first argument by default.
class C():
#classmethod
def some_classmethod(cls, other, arguments):
# first argument is not the instance, but
# the class C itself.
#staticmethod
def something_related(other, arguments):
# the first argument gets neither the instance
# nor the class.
You are too focused on syntactic sugar. Just realize that the first parameter in a non static member function in python is the reference to the current object. Whether you want to call it this, that, foobar, poop, it doesn't matter. The first parameter of a member function is considered the reference to the object on which the method is called.
The use of self is just a universal way everyone has understood it and the way Python recommends - a convention if you may.
The same goes for **kwargs and *args. These are simply conventions that have permeated the Python ecosystem and everyone just uses it that way, but it doesn't mean you can't give them a different name.
Your last example broke because the function you are calling (A.something) does not take any parameters. This will make sense if you understood what I had said earlier about first parameter in non static member function being a reference to the object on which the method was called.

Share variables between modules

I have this situation:
library_file1.py:
class A:
def foo(self):
print("bar")
def baz(self):
pass
project_file.py:
from library_file1 import A
class B(A):
def baz(self):
print(the_variable)
library_file2.py:
from project_file import B
the_variable = 7
b = B()
b.foo() # prints "bar"
b.baz() # I want this to print "7", but I don't know how
How do I allow code to be written in project_file.py that can access variables from library_file2.py? The only solution I can think of is this:
project_file.py:
from library_file1 import A
class B(A):
def baz(self, the_variable):
print(the_variable)
library_file2.py:
from project_file import B
the_variable = 7
b = B()
b.foo()
b.baz(the_variable)
but this feels awkward and doesn't scale to many variables like the_variable.
Quite easy: you need the variable to be in project_file.py instead of library_file2.py.
Change project_file to:
from library_file1 import A
the_variable = None
class B(A):
def baz(self):
print(the_variable)
And then in library_file2:
import project_file
from project_file import B
project_file.the_variable = 7
b = B()
b.foo() # prints "bar"
b.baz() # prints "7"
Using an argument is also a good solution (you should avoid globals as much as you can).
There is no such a thing as a truly global variable in python. Variables are always attached to a scope. We usually say that a variable is "global" when it's in the module scope.
The widest scope is the built-in scope, so it would be theoretically possible for you to add something as a built-in. However this is a really bad practice.
Also it doesn't complete fix the problem, because all files could access that new built-in, but they couldn't re-assign it without explicitly mentioning the scope.

How can I tell if a function and class instance method are the same?

How can I tell if a class instance method and function are the same?
I have a simple class that uses a decorator:
#decorate_class
class Hello:
#decorate_func
def world(self):
return
And these are my decorators:
# A global variable
global_func = None
def decorate_func(func):
global_func = func
return func
def decorate_class(clazz):
print clazz.__dict__["world"] == global_func
return clazz
The above returns False, possible because type(func) in decorate_func is function, but in decorate_class it is instancemethod. But printing both of them gives me:
<function world at 0x7f490e59ce60>
As in, the same memory address. How do I compare them to know that they are the same function? Is comparing by the memory address safe (and correct)?
Your problem here is actually your use of global_func.
If you change decorate_class to:
def decorate_class(clazz):
print global_func, clazz.__dict__["world"] == global_func
return clazz
You'll see that global_func is None.
To fix this, explicitly declare global_func as global in decorate_func:
def decorate_func(func):
global global_func
global_func = func
return func
And everything will work.
This is (basically) because Python assumes that, if you assign to a variable in a function, that variable is assumed to be local to that function, unless it is explicitly declared to be global.

How to access a decorated method local variables ( locals() ) from inside a Python decorator?

Here's what I need:
Let's say I have this decorator:
def deco(func):
def decoret(*args, **kwargs):
print(func.__locals__) # I know __locals__ is not valid, but I need something like this
return decoret
#deco
def func():
test1 = 123
test2 = 456
func()
I want to fetch a list of all local variables (as if I was calling locals() inside the function), so I would be able to access a dictionary with test1 and test2 values inside the decorator's decoret function.
I know I can do this by using Python inspect module, but I wasn't able to trace the right frame to get the function.
Also, I'm using Python 3.2 CPython.
There are no locals in a function until it's executed. The only things available to you when it's decorated are what is there when it's defined.
d = 'd'
def a(d=d):
b = 'b'
c = 'c'
print a.__dict__
# {}
print a.b
# AttributeError: 'function' object has no attribute 'b'
print dir(a)
# Doesn't print anything
Actually, I found a way to circumvent and implement this using a trace from sys.
Take a look a this snippet:
def Property(function):
keys = 'fget', 'fset', 'fdel'
func_locals = {'doc':function.__doc__}
def probeFunc(frame, event, arg):
if event == 'return':
locals = frame.f_locals
func_locals.update(dict((k,locals.get(k)) for k in keys))
sys.settrace(None)
return probeFunc
sys.settrace(probeFunc)
function()
return property(**func_locals)
Took this from a snippet of code located at http://code.activestate.com/recipes/410698/
Also, take a look on this stackoverflow topic: Python: static variable decorator

Categories