passing object to object [duplicate] - python

This question already has answers here:
Can you explain closures (as they relate to Python)?
(13 answers)
Closed 6 years ago.
I am trying to understand the background of why the following works:
def part_string(items):
if len(items) == 1:
item = items[0]
def g(obj):
return obj[item]
else:
def g(obj):
return tuple(obj[item] for item in items)
return g
my_indexes = (2,1)
my_string = 'ABCDEFG'
function_instance = part_string(my_indexes)
print(function_instance(my_string))
# also works: print(part_string(my_indexes)(my_string))
how come I can pass my_string to function_instance object even though I already passed my_indexes attributes to part_string() when creating function_instance? why Python accepts my_string implicitly?
I guess it has something to do with the following, so more questions here:
what is obj in g(obj)? can this be something other e.g. g(stuff) (like with self which is just a convention)?
what if I want to pass 2 objects to function_instance? how do I refer to them in g(obj)?
Can You recommend some reading on this?

What you're encountering is a closure.
When you write part_string(my_indexes) you're creating a new function, and upon calling it, you use the old variables you gave to part_string together with the new variables given to function_instance.
You may name the inner function whatever you want, and there is no convention. (obj is used in here but it can be pie. There are no conventions for this except func for function closures (decorators).
If you wish to pass two variables to the function, you may define two variables to the g(obj) function:
def g(var1, var2):
...
Here's some more info regarding closures in python.

Related

Iterating Through a List of Functions in Python [duplicate]

This question already has answers here:
Creating a list of methods to be executed in Python
(4 answers)
Closed 4 months ago.
Let's say I have the following code:
string = "XxXxXx"
print(string.lower())
print(string.upper())
How could I use a list instead along the lines of:
string = "XxXxXx"
list = [lower(), upper()]
for i in list:
print(string.i)
Obviously the code above does not work at all and the problem I'm working on is way more complicated. But if I could make the example above work, it would really take care of my problem!
Functions (and methods) are first class objects in python. You can therefore store them in a list just like you would anything else.
If you want to be able to apply the functions to arbitrary strings, use the unbound function objects in the class:
string = "XxXxXx"
func_list = [str.lower, str.upper]
for i in func_list:
print(i(string))
If you want to only apply the functions to your special string, you can store the bound methods in a list instead:
string = "XxXxXx"
func_list = [string.lower, string.upper]
for i in func_list:
print(i())
In both cases, the () operator is what calls the function. The function name by itself is a reference to the object. In the first case, the . operator does not do anything surprising. In the second case, since you invoke it on an instance of a class, it binds the function object in the class to the instance, creating a bound method that has an implicit self argument.

Why defining global <variable name> inside called function works for immutable objects in python3? [duplicate]

This question already has answers here:
Using global variables in a function
(25 answers)
Why isn't the 'global' keyword needed to access a global variable?
(11 answers)
Closed last year.
def func():
global count
count += 1
if __name__ == '__main__':
count = 0
print(count)
func()
print(count)
As defined in the python documentation:
If we have a mutable object (list, dict, set, etc.), we can use some specific operations to mutate it and all the variables that refer to it will see the change.
If we have an immutable object (str, int, tuple, etc.), all the variables that refer to it will always see the same value, but operations that transform that value into a new value always return a new object.
Its clearly mentioned in the 2nd statement that int is immutable, but if you run the python code above with global it seems to be working.
Any explanation that anyone can provide here, or i am missing something here?

Python variable inheritance not working (as expected) [duplicate]

This question already has answers here:
How to create dynamical scoped variables in Python?
(4 answers)
Closed 2 years ago.
Why, in this code, can't I access db or file from inside do_more()?
def do_stuff(queue):
db = getDbConn()
while True:
file = queue.get() #DirEntry object
...
do_more(otherObject)
q.task_done()
I'm aware I could pass db and file as arguments to do_more(), but I feel like those variables should just be available in functions called from other functions. It works that way from main to first level functions. What am I missing here?
In the code you provided, you don't even attempt using the variables from do_stuff.
But as a general rule, you should be able to use variables from a parent function inside a child function, either by passing them as variables or by using them when initializing the child function, like this:
def foo():
foo2 = "foo"
def bar():
print(foo2)
bar()
foo()
If i did not answer your question let me know.
no , you cant access those variables , I know what you think , which is wrong.
you can access variables inside loops and if statements, not here.
imagine you have a function which is used in many different places, in that case you have access from this function to many variables which makes things complicated.
functions should be stand-alone objects which take some arguments do stuff and return something.so inside a function scope you can only see variables which are defined there and the arguments passed from the parent function using parenthesis.

Python - scope of wrapping functions [duplicate]

This question already has answers here:
Counting python method calls within another method
(3 answers)
Closed 9 years ago.
The goal is to wrap a function or method and carry data around with the wrapper that's unique to the wrapped function.
As an example - let's say I have object myThing with method foo. I want to wrap myThing.foo with myWrapper, and (as an example) I want to be able to count the number of times myThing.foo is actually called.
So far, the only method I've found to be effective is to just add an attribute to the object -- but this feels a little bit clumsy.
class myThing(object):
def foo(self):
return "Foo called."
def myWrap(some_func):
def _inner(self):
#a wild kludge appears!
try:
self.count += 1
except AttributeError:
self.count = 0
return some_func(self)
return _inner
Stick = myThing()
myThing.foo = myWrap(myThing.foo)
for i in range(0, 10):
Stick.foo() ##outputs "Foo called." 10 times
Stick.count # the value of Stick.count
So, this achieves the goal, and in fact if there are multiple instances of myThing then each one 'tracks' its own self.count value, which is part of my intended goal. However, I am not certain that adding an attribute to each instance of myThing is the best way to achieve this. If, for example, I were to write a wrapper for a function that wasn't part of an object or class, adding attributes to an object that isn't there won't do anything.
Maybe there is a hole in my understanding of what's actually happening when a method or function is wrapped. I do know that one can maintain some kind of static data within a closure, as with the following example:
def limit(max_value):
def compare(x):
return x > max_value
return compare
isOverLimit = limit(30)
isOverLimit(45) #returns True
isOverLimit(12) #returns False
alsoOver = limit(20)
alsoOver(25) # returns True
isOverLimit(25) # returns False
The second example proving that it's not simply modifying the original instance of limit, and that isOverLimit continues to act as it did before the second alsoOver is created. So I get the sense that there's a way for the wrapper to carry an incremental variable around with it, and that I'm just missing something obvious.
Seems like this is a dupe of Counting python method calls within another method
The short answer is to use a decorator on the method/function you want to count, and have the decorator store the counter as a function attribute. See the answers in the question I linked.

Why doesn't python allow passing variables by reference [duplicate]

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 6 months ago.
This probably fits more a discussion group, but I'm not proficient in the
innards of the language (or even the language itself). In any case, what's bugging me is:
If python is allowing interference (side effects) with outer scope using the nonlocal keyword, then why does it not allow a similar interference with function arguments by
permitting passing arguments by reference:
Possible right now:
>>> def outer():
x = 1
def inner():
nonlocal x
x = 2
print("inner:", x)
inner()
print("outer:", x)
>>> outer()
inner: 2
outer: 2
Why not - or what could go wrong if we had:
>>> def outer():
x = 1
def inner(byref x):
x = 2
print("inner:", x)
inner(x)
print("outer:", x)
>>> outer()
inner: 2
outer: 2
(using some keyword like 'byref' or 'nonlocal, just for illustration).
Python always passes parameters using reference value. Refer to this link here and especially rad the detailed response provided by the user pepr
Also this link has pretty detailed discussion on how exactly parameters are passed within python and also pass-by-reference can be simulated - refer to the EDIT of the accepted answer to this question.
In case, you want to delve deeper - please refer to this Effbot article that also contains some debate/discussions around the same topic.
This is not possible because Python does not have a concept of "variable" at all. All the names in a Python program are references to objects. So you can only pass a reference to an object when calling a function or method. This is called passing by reference value.
However, it is not possible to obtain a reference to an existing reference. In this respect, references are the only "non first class" citizens in the Python world.
There are two kinds of objects referenced by names in a program: immutable (e.g. string, int, tuple) an mutable (e.g. list, set, most user classes).
You can call methods on mutable objects that in fact modify the objects state, and this looks similar to passing a reference to the object in a language such as C++. Beyond that, the passing by reference does not make much sense in Python.
See Prahalad Deshpande's answer for some links.
Suppose you do allow reference arguments. What happens, then, when you do the following?
def f(byref x):
print x
print x
x = 3
class Foo(object):
def __init__(self):
self.count = 0
#property
def x(self):
count += 1
return count
f(Foo().x)
When is the getter called? How many times is it called? Does this print 1 twice, or does it print 1, then 2, or 2, then 3? Since there's no setter, what happens when you try to assign to x?
In another language, where variables are places to put things instead of names for values, this wouldn't be a problem. Foo().x would have a memory location once evaluated, and f would use that memory location for its x argument. In Python, it doesn't work like that. You can't pass in the memory location of 1 and change its contents, because then other code will find that 1 is magically 2 all of a sudden. Python's name semantics and attribute/item getter/setters make reference arguments even more confusing than in languages like C++, where they're already confusing and bug-prone.
In Python int objects are immutable. When you think you are changing the value of x, you are really creating a new int at a different memory location and getting x to reference that.

Categories