What's the pythonic way of passing on default arguments? [closed] - python

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I've been wondering about this for a while. If I have a function with a default argument, and that function is called by another function which needs to pass on said argument. Now that function would also need to set a default. How can I avoid copy-pasting the default value?
Example code:
def foo(a=3):
print(a)
def bar(it=10, a=3):
for i in range(it):
foo(a=a)
How do I avoid having to set the default value for a second time?
I can think of perhaps doing it with argv like:
def foo(a=3):
print(a)
def bar(it=10, *argv):
for i in range(it):
foo(*argv)
But aside from me not liking it (it doesn't play well with code completion) that only works if there is only a single function whose default parameters I want to pass on. It doesn't work if there are two or more.
The other option would be completely restructuring the code, perhaps passing on a partial application of foo, like:
def foo(a=3):
print(a)
def bar(pfoo, it=10):
for i in range(it):
pfoo()
bar(pfoo=foo) # if I want to use the default
bar(pfoo=lambda: foo(a=5)) # if I want a different value for a
But depending on the specific use case, this feels a bit overengineered (and perhaps hard to read) to me.
My "dreamcode" would be something like:
def foo(a=3):
print(a)
def bar(it=10, a=foo.defaults.a):
for i in range(it):
foo(a=a)
I noticed there are __defaults__ and __kwdefaults__ dunders, but the former is a tuple and not named, so I would have to make sure I get the order right (which is a major source of error), and the latter is only filled if there is a * argument in foo, that would otherwise swallow all the other arguments. Hence if I want to use those dunders I have to change it to:
def foo(*, a=3):
print(a)
def bar(it=10, a=foo.__kwdefaults__['a']):
for i in range(it):
foo(a=a)
But I don't really want foo to accept arbitrary arguments...
How do you guys deal with this?

For your example, if you just want to call foo() from bar() with the same default parameter of a=3, then you don't need to assign any value to a:
def foo(a=3):
print(a)
def bar(it=10):
for i in range(it):
foo()
This will call foo, and assign the default value of 3 to the parameter a

Rather than specify foo's default as the default value of bar's parameter, use a sentinel value that indicates whether you want to call foo with an explicit argument or not.
from functools import partial
use_foo_default = object()
def bar(it=10, a=use_foo_default):
f = foo if a is use_foo_default else partial(foo, a)
for i in range(it):
f()
(If you know that foo can't take None as a valid argument, you can use None in place of the explicitly declared sentinel shown here.)

Related

Return Order of Magic Methods [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 months ago.
Improve this question
I've been programming for a couple of months now and now I actually have a question... So, if I am not completely wrong, there is just one return per call, right? Doesn't matter if its None or a certain return but there cant be like 2 return statements in one call? So lets move on to the magic methods. In which order do they get processed?
def __str__(self):
return f"{self.first} {self.second}"
def __repr__(self):
return "{} {}".format(self.first, self.second)
Always the last one? Or are there differences between certain magic methods in terms of ranking systems? Or do they even get both processed but just one becomes returned=?
There is no return order. Each magic method is a hook called by the Python implementation in order to implement specific protocols.
x.__str__ defines what str(x) means.
x.__repr__ defines what repr(x) means.
And that's it. Well, almost.
You also need to know when str or repr might be used aside from explicit calls. Some examples:
print calls str on each of its arguments to ensure that it has str values to write to the appropriate file.
The interactive interpreter calls repr on the value of each expression it evaluates.
In addition, object.__str__ falls back to use __repr__, I think by invoking x.__repr__() directly (rather than calling repr(x), which would then call x.__repr__()). So str(x) can indirectly be implemented using a __repr__ method if no class involved defined a __str__ method.
Other groups of magic methods might cooperate in order to define a more complicated protocol. For example,
x += y
could involve several options, tried in order:
x = x.__iadd__(y), if x.__iadd__ is defined
x = x.__add__(y), if x.__add__ is defined
x = y.__radd__(x), if x.__add__ is not defined or x.__add__(y) returned NonImplemented.

Bind the output of a method before using or call the method when you need its output? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
In both examples, class.method() returns a list.
Example A:
if class.method():
for i in class.method():
# do stuff
Example B
list = class.method()
if list:
for i in list:
# do stuff
Which is better? It would seem to me that in some languages (but I don't know which), example A would result in class.method() being needlessly evaluated twice, and example B would be best practice. However, perhaps other languages (again not knowing which) might retain the output of a method in memory in case that method is called again, therefore avoiding having to do the same evaluation twice and resulting in little difference between examples A and B. Is this so? If so, can you give examples of a language for each case? And the real reason for the question: which is best practice in Python?
Unless your Python interpreter has JIT capabilities, the method will be evaluated every time you call it.
And even when the JIT compilation is possible, methods have to be proven by the compiler / interpreter that they do not have any side effects, that is they are deterministic.
For example, consider a method that pulls data from a database or a method that contains a call to a random number generator:
import random
def method():
return random.uniform(0.0, 1.0)
Output of such a method cannot be saved in memory because the second time you call it, it may change.
On the other hand, getter methods that accumulate data are a great example of a deterministic method, given that they do not call a non-deterministic method in their body.
from dataclasses import dataclass
#dataclass
class Example:
a : list
b : list
def method(self):
return self.a + self.b
In practice, you are better of to not assume anything from the compiler / interpreter and do these small, easy to do optimizations yourself. You also have to consider that your code can be run on multiple platforms, which further complicates things.
So I would recommend you to call the method only once and save its output in a temporary variable:
result = class.method()
if result :
for i in result:
# do stuff
And given that it's Python, I recommend to ask for forgiveness with the try keyword if most of the time you run the method, its output is not None:
result = class.method()
try:
for i in result:
# do stuff
except TypeError:
pass

Why is "wrapper" is better name for a decorator than "adder"? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
A bare-bones example of a decorator is:
def strong(func):
def wrapper():
return '<strong>' + func() + '</strong>'
return wrapper
#strong
def greet():
return 'Hello!'
wrapper is an entitled name for the 'inside first-order-function' inside the Higher-Order function strong.
My question is that the word wrapper has no real meaning except to confuse newbie. Why not use 'adder', because it can be discerned intuitively?
Decorator pattern - Wikipedia
In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class.[1]
The keyword in Wikipedia's explanation is 'added'.
And in Cambridge English Dictionary:
to add something to an object or place, especially in order to make it more attractive:
The keyword is also 'add'.
So why is wrapper better than 'adder'?
When you use a decorator, you've wrapped your original code in another function, making the original function invisible. To continue your example,
def strong(func):
def wrapper():
return '<strong>' + func() + '</strong>'
return wrapper
#strong
def greet():
return 'Hello!'
def weak_greet():
return 'hi'
print(greet)
print(weak_greet)
If you run this, you get the following output.
<function strong.<locals>.wrapper at 0x000000000129A268>
<function weak_great at 0x000000000129A2F0>
When you used the decorator, you took your function, created a new function that wrapped code around your old function and returned that new, anonymous, function.
You can see some unpleasant effects if you try to pickle it.
if you do pickle.dumps(weak_greet), you get b'\x80\x03c__main__\nweak_great\nq\x00.'. but if you try to pickle.dumps(greet), you get AttributeError: Can't pickle local object 'strong.<locals>.wrapper'. (dealing with decorated classes and functions that must be pickled is one of the circles of hell I don't wish to revisit any time soon).
You are not adding to your function. You are wrapping your original function in a shiny new function. That new function says, "There's something I'm hiding in here and I won't tell you what it is (functools.wraps can sometimes help with this, as it would in your case). But, when you give me input, I'll alter it like so (or not at all), pass it to my secret function, (possibly) alter the output and give you that. Your original function is inaccessible (hence pickle's confusion).
NOTE: You can re-create the look of your original function by further wrapping your wrapper with #functools.wraps(original_function), which does not affect output, but wraps everything in a box to make it look exactly like the original function. so,
from functools import wraps
def strong(func):
#wraps(func)
def wrapper():
return '<strong>' + func() + '</strong>'
return wrapper
would now look like your original function and be pickle-able. It would be like wrapping a surprise present, and then wrapping the present again with wrapping paper that told you (in great detail) what the surprise was.

Hand over global variables to methods in python? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
This is more a question about good programming style. I usually work with Java, and now I do some working with Python. In Python, there is no need to hand over global variables if you only want to read from them. On the other hand, I think the Java syntax is more helpful in his regard. You have to hand over required variables, and so you can see what variables are used by what method, which I am sure is helpful for somebody who is reading your code.
Now do you hand over variables in Python although you could already access them because they're global? What is the good 'pythonic' way?
Thanks,
ZerO
def foo(a):
a = 2
foo(1)
1 is 'handed over' to method foo().
Yes, this
def foo(a):
a = 2
foo(1)
is preferred over this
a = 1
def foo():
a = 2
foo()
Imagine you have 3 methods that all do something to a list.
a_list_name = []
def a()
a_list_name.something
def b()
a_list_name.something
def c()
a_list_name.something
a()
b()
c()
If you define the list 'global' you will have to refer that exact list in each method. If you for some reason want to change the list name you now have to edit all 3 methods.
However if you pass in the list through a parameter you only have to edit the method calls and the method code can remain untouched. Like this
def a(l)
l.something
def b(l)
l.something
def c(l)
l.something
my_list = []
a(my_list)
b(my_list)
c(my_list)
This makes your code more modular, and most of all it makes your code (methods) testable because they don't depend on some variable that is defined somewhere else

Using setattr to freeze some parameters of a method [duplicate]

This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 6 months ago.
in order to automatically generate parameterized tests, I am trying to add methods to a class in by freezing some parameters of an existing method. Here is the piece of Python 3 code
class A:
def f(self, n):
print(n)
params = range(10)
for i in params:
name = 'f{0}'.format(i)
method = lambda self: A.f(self, i)
setattr(A, name, method)
However, the following lines then produce rather disappointing output
a = A()
a.f0()
prints "9" (instead of "0"). I must be doing something wrong, but I can't see what. Can you help ?
Thanks a lot
Edit: this question is indeed a duplicate. I would like to acknowledge the quality of all comments, which go much deeper than the raw answer.
Try
method = lambda self, i=i: A.f(self, i)
because otherwise when you call the method i's value may have changed
The best way to "freeze" parameters in Python is to use functools.partial. It's roughly equivalent to warwaruk's lambda version, but if you have a function with lots of arguments yet only want to freeze one or two of them (or if you only know certain arguments and don't care about the rest) using partial is more elegant as you only specify the arguments you want to freeze rather than having to repeat the whole function signature in the lambda.
An example for your program:
class A:
def f(self, n):
print(n)
from functools import partial
for i in range(10): # params
setattr(A, 'f{0}'.format(i), partial(A.f, n=i))
Depending on which version of Python 3 you're using, you may not need to include the 0 in the string format placeholder; starting with 3.1, iirc, it should be automatically substituted.

Categories

Resources