Order of binding of variables in Python - python

I'm trying to modify a function which uses a module-level variable variable defined below it, similar to this:
def say_hello():
print(MESSAGE)
MESSAGE = "Hello, world!"
say_hello()
I would like to make the message a parameter, like so:
MESSAGE = "Hello, world!"
def say_hello(message=MESSAGE):
print(message)
say_hello()
I've noticed that in order for this to work, I had to move the definition of MESSAGE up in the code. Apparently, all module-levels are first 'bound' and are then available within function bodies, but when provided as default function arguments, they have to be defined before the function. Is this correct?
(I would also like to read up on this to fully understand it; any references would be much appreciated).

... when provided as default function arguments, they have to be defined before the function. Is this correct?
Correct. Default arguments are evaluated at function definition time.
If you need them evaluated at function call time, this common pattern works:
def say_hello(message=None):
if message is None:
message = MESSAGE
print(message)
MESSAGE = "Hello, world!"
say_hello()

def say_hello():
print(MESSAGE)
# ^^^^^^^ This...
...is evaluated when say_hello is called. As long as MESSAGE has been assigned by the time say_hello is called, say_hello will see the value.
# vvvvvvv This...
def say_hello(message=MESSAGE):
print(message)
...is evaluated when say_hello is defined. Python evaluates default argument values at function definition time, so MESSAGE has to be assigned before say_hello is even defined for this to work.

While you're learning about default argument binding, give this a try:
def foo(bar=[]):
bar.append(3)
print(bar)
baz = []
faz = []
foo(baz)
foo(faz)
foo()
foo()
The calls with their own arguments will do what you expect - each one prints only one variable. But the calls to foo with the default argument may surprise you. The first time you call it, you get the expected result: [3]. The second time you call it, you may be surprised that the result is [3, 3].
There's actually nothing in this answer that isn't in the others. As others have said, the default argument is evaluated at the time the function is defined. What you see here is a consequence of that - the arguments are evaluated only at the time that the function is defined. bar=[] is evaluated once, giving you one list.
If you do object creation or function calls as part of your default argument, they only happen once, with the net result being a surprisingly static-acting argument. Most of the time, this is not what we're looking for.
The definitive reference for python is found at docs.python.org . The specific reference for defining functions is at https://docs.python.org/3/tutorial/controlflow.html#defining-functions.

Related

apply rotation function of Numpy randomly in python [duplicate]

I was unable to find a reasonable way to create a variable which calls a function requiring parameters.
Here is a simplified version of my code. I would like ‘print_hello’ to print ‘hello’ when it is called, and not when it is defined.
print_hello = print(‘hello’)
When I define ‘print_hello’, it calls print(‘hello’). When I call ‘print_hello’, it gives me an error. How do I fix this?
If you just want a function that does precisely what you describe, Sheldore's answer is the simplest way to go (and more Pythonic than using a named lambda).
An alternative approach is to make a partial application of the function with functools.partial, which allows you to pass additional arguments at call time:
from functools import partial
print_hello = partial(print, "hello")
print_hello() # Prints "hello" to stdout
print_hello(file=sys.stderr) # Prints "hello" to stderr
print_hello("world") # Prints "hello world" to stdout
Just define print_hello as a lambda function
>>> print_hello = lambda: print('hello')
>>> print_hello()
hello
To delay execution, you'll have to wrap the call to print in another function. A lambda is less code than defining another function.
Note: that pep08 recommends using a def function rather than a lambda when assigning to a variable. See here. So #Sheldores answer is probably the way to go.
You need to define a function. In python a function is defined using def as shown in a simple example for your purpose below. You then call the function using the function name and (), for instance print_hello().
def print_hello(): # <--- Does not accept an argument
print('hello')
print_hello() # <--- No argument is passed
# hello
Another example to give you more idea on how to pass an argument to the function. You can define a variable that contains the string you want to print, let's say to_print and then pass this as an argument to your function during calling it. While explaining more details is out of the scope of this answer, the two examples I gave should get you started. For more details, you can refer to the official docs here
def print_hello(to_print): # <--- Accepts an argument
print(to_print)
to_print = "hello"
print_hello(to_print) # <--- Argument is passed
# hello
You could use a lambda expression:
print_hello = lambda: print('hello')
Or an actual function definition:
def print_hello(): print('hello')
Or functools.partial (this is different in that you can still use other arguments for print whereas you lose that functionality with the others unless specified in the definitions)
from functools import partial
print_hello = partial(print, 'hello')
To use any of these:
print_hello()
#'hello'

understanding python inner function .how does this works?

def prefix_factory(prefix):
def prefix_printer(text):
print(f"{prefix}: {text}")
return prefix_printer
Now lets execute the below line.
# First time we are executing this
debug = prefix_factory('DEBUG')
# Second time we are executing as
debug('Hello world')
First time we are executing this
1st execution or assignment of function to the variable debug is assigned the value "DEBUG". My understanding is this is how it has to be executed.
ideally inner function prefix_printer(text) - gets defined inside prefix_factory()
'return prefix_printer' should get an error, stating that text is not available or text is missing.
Second time we are executing as
debug('hello world ') - 2nd execution of the function reference.
The question for the second execution is, I am assuming 'hello world' should be considered as a value for the prefix. and text should be blank as we don't call prefix_printer in the return statement with any value. Hence it has to be '' empty string. I am coming from c, C++ background.
My question is, it's the same piece of code 1st-time prefix is assigned,
but during the 2nd execution debug('Hello world') it behaves differently. How is it possible, please clarify in detail how this works?
When debug = prefix_factory('DEBUG') is executed, variable debug is assigned the return value from calling function prefix_factory('DEBUG'). It is not assigned the value "DEBUG" as you said. And what is this return value?
Function prefix_factory returns prefix_printer, which is a function nested within prefix_factory. Moreover, prefix_printer references a variable, prefix, which is defined in the outer, enclosing function. When prefix_factory returns a nested function, prefix_printer, that references a variable defined in the nesting function, that returned function is known as a closure. Even though we have now returned from the call to printing_factory, the closure function prefix_printer, which has now been assigned to variable debug, still has a reference to the value of variable prefix as it existed at the time prefix_factory was called.
Subsequently, when you execute debug('Hello World'), because debug evaluates to our prefix_printer closure , this is equivalent to calling function prefix_printer('Hello World') with variable prefix initialized to 'DEBUG'.

What is the difference between calling function with parentheses and without in python? [duplicate]

This question already has answers here:
What does it mean when the parentheses are omitted from a function or method call?
(6 answers)
Closed 2 years ago.
I have a question. Lets assume that we have function hello(). What is the difference between calling it with parentheses and without? When I call hello() it is referring to an object with value equals this function. Or maybe am I wrong? What happens when I call it without parentheses?
I wonder why
def hello():
pass
print(id(hello))
print(id(hello()))
returns different results
4400606744
4398942536
Short answer: see https://nedbatchelder.com/text/names.html to get a better understanding of the difference between objects and the names used to refer to objects.
A function is called if and only if you use parentheses. hello() calls the function; hello is simply a name bound to the function, and can be used, for example, to pass the function object as an argument to another function.
def caller(f):
f()
def hello():
print("hi")
def goodbye():
print("bye")
caller(hello) # Prints "hi"
caller(goodbye) # Prints "bye"
Regarding your update, id returns different values because each call to id receives a completely separate object as its argument. With id(hello), id gets the function object itself. With id(hello()), id is getting the object returned by the call to hello; it's the same as
x = hello()
print(id(x))
TL;DR: the parentheses execute the function itself; without them you treat the function as it were a variable
In python you append the parentheses (with optional variables inside) to the function name only when you want to invoke it.
But there is also another way to use function names.
In fact, in python functions are first class objects, that means that the function can be passed around as if it where a variable name. To do you must not append the parentheses () at the end of the function name.
Check the following:
def f():
return 'f'
print( type(f) ) # result: <class 'function'>
print( type(f()) ) # result: <class 'str'>
As you can see, in the first instance we print the type of f (without parentheses), which is a function
In the second instance we print the type of f() (with the parentheses), which is a string, that is the type returned by f when it is invoked.
This behavior is useful to pass functions as parameters of other functions, etc, etc.
The fact that id() and id(function-invoked>) returns different ids:
print(id(hello)) # here it returns the id of the function name
print(id(hello())) # here it returns the id
# of the object returned by the function itself
In short, function with parenthesis () is actually calling (invoke) that function whereas function without parenthesis () is an object of that function which can be passed as an argument and later be called by appending () to it.
def hello():
return 1
i.e.
hello >> returns object
hello() >> outputs 1
hello refers to the function object, hello() calls the function itself.
For example:
>>> def hello():
... print "hello"
...
>>> hello
<function hello at 0x106c91398>
>>> hello()
hello
A function is an object just like any other object in Python. If you define a new function, a new function object is created and is assigned to the name of the function.
def spam():
print('The knights who say Ni!')
print(spam) # => <function spam at 0x7fc64efc6f28>
spam() # => output: 'The knights who say Ni!
As you can see after the function was defined it got assigned to the name of spam. It is essentially similar to an assignment statement being run. Now that name is going to give you access to the function but in order to actually use it you have to call it using the parentheses like spam(). If you don't call it using the parentheses, it will just return the function object that has been assigned to the name spam.

Will Python automatically detect that the function was never called but defined?

True or False
If a function is defined but never called, then Python automatically detects that and issues a warning
One of the issues with this is that functions in Python are first class objects. So their name can be reassigned. For example:
def myfunc():
pass
a = myfunc
myfunc = 42
a()
We also have closures, where a function is returned by another function and the original name goes out of scope.
Unfortunately it is also perfectly legal to define a function with the same name as an existing one. For example:
def myfunc(): # <<< This code is never called
pass
def myfunc():
pass
myfunc()
So any tracking must include the function's id, not just its name - although that won't help with closures, since the id could get reused. It also won't help if the __name__ attribute of the function is reassigned.
You could track function calls using a decorator. Here I have used the name and the id - the id on its own would not be readable.
import functools
globalDict = {}
def tracecall(f):
#functools.wraps(f)
def wrapper(*args, **kwargs):
global globalDict
key = "%s (%d)" % (f.__name__, id(f))
# Count the number of calls
if key in globalDict:
globalDict[key] += 1
else:
globalDict[key] = 1
return f(*args, **kwargs)
return wrapper
#tracecall
def myfunc1():
pass
myfunc1()
myfunc1()
#tracecall
def myfunc1():
pass
a = myfunc1
myfunc1 = 42
a()
print(globalDict)
Gives:
{'myfunc1 (4339565296)': 2, 'myfunc1 (4339565704)': 1}
But that only gives the functions that have been called, not those that have not!
So where to go from here? I hope you can see that the task is quite difficult given the dynamic nature of python. But I hope the decorator I show above could at least allow you to diagnose the way the code is used.
No it is not. Python is not detect this. If you want to detect which functions are called or not during the run time you can use global set in your program. Inside each function add function name to set. Later you can print your set content and check if the the function is called or not.
False. Ignoring the difficulty and overhead of doing this, there's no reason why it would be useful.
A function that is defined in a module (i.e. a Python file) but not called elsewhere in that module might be called from a different module, so that doesn't deserve a warning.
If Python were to analyse all modules that get run over the course of a program, and print a warning about functions that were not called, it may be that a function was not called because of the input in this particular run e.g. perhaps in a calculator program there is a "multiply" function but the user only asked to sum some numbers.
If Python were to analyse all modules that make up a program and note and print a warning about functions that could not possibly be called (this is impossible but stay with me here) then it would warn about functions that were intended for use in other programs. E.g. if you have two calculator programs, a simple one and an advanced one, maybe you have a central calc.py with utility functions, and then advanced functions like exp and log could not possibly be called when that's used as part of simple program, but that shouldn't cause a warning because they're needed for the advanced program.

Python basic nested statements and scope concept

def func():
def nested():
global x
x = 1
x = 2
func()
print(x)
The correct answer would be '2' and the reason why is because func() is not defined. But when I read this it seems that func() is defined as nested(). I would think that when you call func() that would then automatically call nested(). I'm struggling to grasp this and understand why I shouldn't read it that way.
You're defining nested inside func, but you're not calling nested() anywhere in func, so when you call func() it's effectively doing nothing.
To do what you want try defining func as:
def func():
def nested():
global x
x = 1
nested()
UPDATE: After StevenRumbalski's comment, I think a small addition about what exactly is going on in that function can help clarify things around.
Python's functions are themselves objects which can respond to the operator ().
When you define a new function, what you're actually doing is instantiating a function object and giving it a name. In the example above, def func() creates a function instance and gives it name func, so that when you apply operator () to func (i.e. when you call the function with func()) the code of the function associated to that name is executed.
Let's now take one step further and look at what happens with nested.
Nested is defined inside func's scope, so when you exit func's scope the name nested is not defined anymore.
If, however, you return the function object to the caller of func, you can use that object to run nested's code.
A small example:
def returning_func():
def nested():
print("I am nested!")
return nested # note the lack of the () operator!
In this case, if we do
my_reference_to_nested = func()
nothing gets printed, because nested is defined but not executed.
If we call it, however:
my_reference_to_nested()
we execute nested's code and print to the output I am nested!

Categories

Resources