Python getattr default value evaluation [duplicate] - python

This question already has an answer here:
python getattr built-in method executes default arguments
(1 answer)
Closed 2 years ago.
I have a simple and possible dumb question.
getattr(obj, 'attribute', 2+2)
Question is - would default 2 + 2 be evaluated only in case 'attribute' is missing or it would be evaluated in any case?
Thanks

You can test this yourself by creating an object with an add function that lets you know it was called. For example, you can see the function prints "called" in bother cases indicating that the addition is evaluated regardless of whether the attribute exists on the object:
class obj:
a = "value from obj"
class N:
def __add__(self, other):
print('called')
return 5
a = N()
b = N()
getattr(obj, 'a', a + b)
# called
#'value from obj'
getattr(obj, 'z', a + b)
# called
# 5

Related

Default value of python get function [duplicate]

This question already has answers here:
dict.get() - default arg evaluated even upon success
(6 answers)
Closed 2 years ago.
If the default value passed to python get function (for dictionaries) is an expression, is it evaluated only when the key is not found? Let's consider the following example.
myDiction = {"a":1,"b":2}
val = myDiction.get("c",pow(2,3)-5)
Is that math expression pow(2,3)-5 evaluated or not?
It's not hard to test by passing your own function.
def someF():
print("called")
return 3
myDiction = {"a":1,"b":2}
myDiction.get("a",someF())
Prints: "called". So yes it is evaluated, like you would expect from any argument passed to to a function.
Why don't we find out?
>>> d = {1:2}
>>> d.get(1, print('default') or 3)
default
2
>>> d.get(2, print('default') or 3)
default
3
As you can see, function arguments are evaluated before being passed to the function.
It will be evaluated anyway.
Try this:
def test_func():
print("run")
return 3
myDiction = {"a": 1, "b": 2}
val = myDiction.get("a", test_func())
print(val)
You can see that even though a exists in the myDiction, the "run" message is printed.
I've been wishing for a "lazy" version of dict.get that would allow passing a callable which will be called only if the key is missing a very long time now.
We don't have it yet, but one can implement that quite easily.
from collections import UserDict
def lazy_default_func():
print('in lazy_default_func')
return 7
def lazy_default_func_with_args(*args, **kwargs):
print('in lazy_default_func_with_args', 'args', args, 'kwargs', kwargs)
return 7
class MyDict(UserDict):
def get(self, item, default=None, *args, **kwargs):
print('in get')
if item in self:
return self[item]
if not callable(default):
return default
return default(*args, **kwargs)
d = MyDict({'a': 1})
print(d.get('a', lazy_default_func))
print(d.get('b', lazy_default_func))
print(d.get('b', lazy_default_func_with_args, 'arg1'))
outputs
in get
1
in get
in lazy_default_func
7
in get
in lazy_default_func_with_args args ('arg1',) kwargs {}
7

Is it a good idea to use "is" to check which function is contained in a variable? [duplicate]

This question already has answers here:
How should functions be tested for equality or identity?
(4 answers)
Closed 2 years ago.
I have a variable that contains a function.
def foo(x):
return x + 42
def bar(x):
return x - 42
my_var = foo
I want to check if that function is a certain function. Should I use is or ==?
my_var == foo
my_var == bar
and
my_var is foo
my_var is bar
both return what I expect.
They are the same thing for a function object. The == operator calls the __eq__ function to perform the comparison. The function object does not define an __eq__ method:
>>> def foo():
... pass
...
>>> foo.__eq__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute '__eq__'
Therefore the interpreter uses the default implementation in PyObject:
res = (v == w) ? Py_True : Py_False;
which is basically a pointer comparison, essentially the same as is.
No, you should use ==.
A good rule of thumb is only use is when doing is None or is not None and nowhere else. In this case, comparing functions with is works, but if you try to compare a method of an instance of a class with itself you'll get False (even on the same instance), whereas comparing with == returns what you expect:
>>> class A:
... def my_method(self):
... pass
...
>>> a = A()
>>> a.my_method is a.my_method
False
>>> a.my_method == a.my_method
True
Better to avoid having to remember this and always compare functions with ==.
See this question: Why don't methods have reference equality?
Is checks for the identity of an object. If you assign foo to myvar, then an alias is created and they both have the same id (in the case of functions at least).
Checking 2 functions for equivalence from a mathematical standpoint entails checking the equivalence of the domains and codomains of both functions.
So is is better.

why is the class method called by instance and class not the same thing [duplicate]

This question already has answers here:
Is there a difference between "==" and "is"?
(13 answers)
Why does id({}) == id({}) and id([]) == id([]) in CPython?
(2 answers)
Closed 4 years ago.
for start, let's define a class and instance of the class
class c:
#classmethod
def m(cls, a):
return a + 1
a = c()
those methods are used the same way
>>> c.m(5), a.m(5)
6, 6
and cls in both cases is c
but c.m is a.m is False
and c.m == a.m is True
why is the class method called by instance and class not the same and why am I able to call it even by an instance of that class
it would make sense if cls were not the same in both cases
EDIT:
I already knew the difference between is and ==
I was already successfully using is to check if two classes are the same
(type(a) is int for example), but I did learn I should use it for is None, so thanks anyway for leading me to that page
My question actually was why are they not the same object
they even have same ID id(a.m) == id(c.m)

dynamically create methods in python [duplicate]

This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Why to use __setattr__ in python?
(7 answers)
Closed 6 months ago.
given the following snippet:
def fun(ret):
return ret
class A:
def __init__(self):
for string in ['a', 'b']:
setattr(self, string, lambda: fun(string))
>>> a = A()
>>> a.a()
'b'
I want a method a() which returns 'a' and a method b() which returns 'b'. As long as I don't use a lambda expression but setting the attribute to a simple string, the association is correct.
I think my intention is clear? So where am I wrong?
In Python, a function will lookup non-local names in the scope where it was defined or in the global scope if the name still does not exist there. If the value associated to the name changed, so will the returned value. Note that this is not specific to lambda functions.
A way around this is to create a closure by writing a helper function.
def fun(ret):
return ret
class A:
def __init__(self):
def apply_fun(item):
return lambda: fun(item)
for string in ['a', 'b']:
setattr(self, string, apply_fun(string))
print(A().a()) # 'a'
Alternative solution
In that particular case, using __getattr__ might be more suited as it is intended to dynamically return attributes.
def fun(ret):
return ret
class A:
def __getattr__(self, item):
if item in ['a', 'b']:
return lambda: fun(item)
print(A().a()) # 'a'

How to get a closure to refer to the value that a variable had at the time of its definition [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Creating lambda inside a loop
In the code below, invoking any member of the returned array of closures
prints the number 4.
def go():
x = []
for i in range(5):
def y(): print i
x.append(y)
return x
I would like each member of the closure to print the number that i was when the closure was defined.
One way around this is to use default arguments:
def y(i=i):
print i
Default arguments are evaluated when the function is created, not called, so this works as you'd expect.
>>> i = 1
>>> def y(i=i): print i
...
>>> i = 2
>>> y()
1
A little extra info just for fun:
If you're curious what the defaults are, you can always inspect that with the .func_defaults attribute (__defaults__ in python3.x):
>>> y.func_defaults
(1,)
This attribute is also writeable, so you can in fact change the defaults after the function is created by putting a new tuple in there.

Categories

Resources