Setting Default Paramaters in Python and Over-Riding Same Syntax Query - python

Here's the segment of relevant code:
class MainPage(webapp2.RequestHandler):
def write_form(self,text=""):
self.response.out.write(form%{"text":escape_html(text)}) #form is a html form
def get(self):
self.write_form()
def post(self):
user_input = self.request.get('text') #from a html form
encode = user_input.encode('rot13')
self.write_form(encode)
When write_form is defined, we set the default value of text to be the empty string, I understand this.
Where I'm confused is the last line self.write_form(encode)we're not explicitly stating that we are now setting the variable text to encode (or whatever we want to pass in...).
Does this mean that as we only have one variable (not counting self) that whatever I pass in python will assume it to be what I am passing in for 'text'?
Thanks in advance
Update
Using jamylak's answer, I tried it for myself (python 2.7 as I don't use 3) in a simplified version to get my answer. For n00bs like me this might make the answer a bit clearer:
def example(result="42"):
print result
example()
>>>42
example(87)
>>>87
example("hello")
>>>"hello"

Yes, self is passed implicitly when you call the method of an instance and default arguments need not always be specified with their names(if passed in the correct order). On a side note python 3 allows you to use the asterisk (*) to make sure that you pass them with their names:
>>> def foo(*, text=''):
pass
>>> foo('aa')
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
foo('aa')
TypeError: foo() takes 0 positional arguments but 1 was given
>>>
>>> foo(text='aaa')

your first argument is self which is passed to that function automatically by python. Second argument rot13 is passed to text. If you pass a third argument you will get an error.

Related

Provide default value to dynamic parameters without access to the original variable-using code

So this is the default behavior when you give a bad variable name:
>>> foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
>>>
what I'm looking for is something like:
>>> set_name_error_handling('assign_default',None)
>>> foo
>>>
(foo is automatically assigned None)
I'm using this on dynamic parameter handling and would like to use a behavior that if the parameter is not given, a default value is being used. And I have some code that I don't have control of that have used None handling. Is it possible for me to just add some dynamic header like below and save the mess by not changing all other code?
# This may work in python2 but not python3
def foo(self,params):
local = locals()
for key in params:
local[key] = params[key]
# Do important things onwards, cannot change
Edit: A way to do the specific problem above, is to provide a default option, let's say:
options = foo.get_default_params()
# do whatsoever changes to modify options
result = foo.call(options)
This assumes that a default parameter table is available. Is it still doable when you don't even have the default parameter table or it's not possible to generate one (infinite possible parameters like print())?
Edit: To center the question into methodology I have rephrased the title and removed reference to override NameError.
I don't think Python offers something like that. However, you could always do:
try:
foo
except NameError:
foo = None
# do whatever with foo
If you are trying to define a function, I would define it like this:
def baz_func(foo=None):
# function body here
You can call this as both baz_func() or baz_func(foo=5).

Missing 1 required positional argument

I am as green as it gets when it comes to programming but have been making progress. My mind however still needs to fully understand what is happening.
class classname:
def createname(self, name):
self.name = name;
def displayname(self):
return self.name;
def saying(self):
print("Hello %s" % self.name);
first = classname;
second = classname;
first.createname("Bobby");
Error:
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
first.createname("Bobby")
TypeError: createname() missing 1 required positional argument: 'name'
The error tells me that I need 1 more argument in the name, so I must be going wrong there, but I already tried something like this:
first.createname("bobby", "timmy");
I also rule out the fact that it would be the def createname(self, name), because self is or should be alone and not included? So I do not really understand what is going on.
You have not actually created an object yet.
For instance, you would want to write:
first = classname()
instead of just
first = classname
At the moment, how you wrote it, first is pointing to a class. E.g., if you ask what first is, you'd get:
<class '__main__.classname'>
However, after instantiating it (by simply adding the () at the end), you'd see that first is now:
<__main__.classname object at 0x101cfa3c8>
The important distinction here is that your call set first as a class, whereas mine set it as an object.
Think about it like this: A class is to an object as humankind is to you, or as canine is to Lassie.
You set it as "canine", whereas you wanted to set it as "Lassie".
Note: you also usually want to initialize your objects. For that, you place an __init__ method in your class.

Should all dict params in python decorated by asterisks

def accept(**kwargs):
pass
If I defined accept and I expect it be called by passing a param which is dict. Are the asterisks necessary for all dict params?
What if I do things like:
def accept(dict):
pass
dict = {...}
accept(dict)
Specifically speaking, I would like to implement a update method for a class, which keeps a dict as a container. Just like the dict.update method, it takes a dict as a param and modify the content of the container. In this specific case should I use the kwargs or not?
** in function parameter collects all keyword arguments as a dictionary.
>>> def accept(**kwargs): # isinstance(kwargs, dict) == True
... pass
...
Call using keyword arguments:
>>> accept(a=1, b=2)
Call using ** operator:
>>> d = {'a': 1, 'b': 2}
>>> accept(**d)
>>> accept(d)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: accept() takes exactly 0 arguments (1 given)
See Python tutorial - Keyword argument and Unpacking Argument Lists.
BTW, don't use dict as variable name. It shadows builtin function/type dict.
See f below. The function f has two parameters, a positional one called name and a keyword argument message. They are local variable in the frame of the function call.
When you do f("John", **{"foo": "123", "message": "Hello World"}), the function f will unpack the dictionary into local variable by its key/value pair. In the end you have three local varaibles: name, foo=123, and message=Hello World.
The purpose of **kwargs, double asterisks is for uknown keyword arguments.
Contrast this:
def f(name, message=None):
if message:
return name + message
return name
Here I am telling user if you ever want to call f, you can pass a keyword argument message. This is the only kwarg I will ever accept and expect to receive if there is such one. If you try f("John", foo="Hello world") you will get unexpected keyword argument.
**kwargs is useful if you don't know ahead of time what keyword arguments you want to receive (very common for dispatching to lower-level functions/methods), then you use it.
def f(name, message=None, **kwargs):
if message:
return name + message
return name
In the second example, you can do f("John", **{"foo": "Hello Foo"}) while omitting message. You can also do f("John", **{"foo": "Hello Foo", "message": "Hello Message"}).
Can I ignore it?
As you see yes you can ignore it. Here f("John", **{"foo": "Hello Foo", "message": "Hello Message"}) I still only use message and ignore everything else.
Don't use **kwargs unless you need to be careless about the inputs.
What if my input is a dictionary?
If your function simply takes the dictionary and modifies the dictionary, NOT using individaul key, then just pass the dictionary. There is no reason to make a dictionary item into variables.
But here are two main usages of **kwargs.
Supposed I have a class and I want to create attributes on the fly. I can use setattr to set class attributes from input.
class Foo(object):
def __init__(**kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
If I do Foo(**{"a": 1, "b": 2}) I will get Foo.a and Foo.b at the end.
This is particularly useful when you have to deal with legacy code. However, there is a big security concern. Imagine you own a MongoDB instance and this is a container for writing into a database. Imagine this dict is a request form object from user. The user can shovel ANYTHING and you simply save it in the database like that? That's a security hole. Make sure you validate (use a loop).
The second common usage of kwargs is that you don't know things ahead of times which I have covered (it's actually sort of the first common usage anyway).
If you want to pass a dictionary as input to a function, you can simply do it like this
def my_function1(input_dict):
print input_dict
d = {"Month": 1, "Year": 2}
my_function1(d) # {'Month': 1, 'Year': 2}
This is straight forward. Lets see the **kwargs method. kwargs stands for keyword arguments. So, you need to actually pass the parameters as key-value pairs, like this
def my_function2(**kwargs):
print kwargs
my_function2(Month = 1, Year = 2)
But if you have a dictionary and if you want to pass that as a parameter to my_function2, it can be done with unpacking, like this
my_function2(**d)

How to pass non default argument with default arguments in python django forms

Here is my code
class FarticlesWizard(FormWizard):
def done(self,request,form_list):
if request.method=='POST':
form1=F1articles(request.POST)
form2=F2articles(request.POST)
form_dict={}
for x in form_list:
form_dict=dict(form_dict.items()+x.cleaned_data.items())
insert_db=Marticles(heading = form_dict['heading'],
content = form_dict['content'],
created_by=request.session['user_name'],
country=form_dict['country'],
work=form_dict['work'])
insert_db.save()
return HttpResponseRedirect('/display/')
but i now i need to pass def done(self,request,id=None, form_list): where id is non default argument ...iam getting an error message non-default argument follows default argument (views.py, line 130) is there a way to do it?
No. As the error message suggests, any arguments with default values must come after all arguments without default values.
Why do you feel you need to add the new argument in the middle like that? Why not just do def done(self, request, form_list, id=None)? Adding a new argument in the middle will break all existing code that calls the function with positional arguments.
Default arguments have to all go after non default arguments, or positional argument passing is messed up. If you have def done(self,request,id=None,form_list): and you call done(r,fl) somewhere, python doesn't know if fl goes in id or form_list. You'll always have to specify id to get to specifying form_list. That's why default arguments all go at the end, like def done(self,request,form_list,id=None)

Python mandatoryl arbitrary argument list *args

is there any way to define a mandatory *args (arbitrary arguments) in a method of a class?
class foo():
def __init__(self,*args):
....
Given this, you can create an object from the foo-class without any arguments x=foo(), i.e. its optional. Any ideas how to change it to a non-optional or "give me at least one arguments"-thing?
Another questions concerns the list unpacking with x=foo(*list) --> Is there a way to recognize the list as a list and unpack the list automatically, so that you donĀ“t have to use the * in a function/method call?
Thx
*args is meant to receive all arguments that are not already taken by normal arguments.
Usually if you need an argument to be mandatory, you just use a normal argument:
>>> def foo(arg, *rest):
... print arg, rest
...
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes at least 1 argument (0 given)
If you think it is more elegant to gather all arguments in a tuple, you have to handle the error case yourself:
>>> def foo(*args):
... if len(args) < 1:
... raise TypeError('foo() takes at least 1 argument (%i given)' % len(args))
...
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in foo
TypeError: foo() takes at least 1 argument (0 given)
But as you can (or should) see, from the signature of that function it is not clear how many arguments to that function are mandatory to anyone who uses that function. You should either avoid this altogether or at least document it very well.
There are other problems as well: if you give on argument to foo() that is iterable (like a string), you will not get the intended result.
Responding to your comment below, your first approach was the right one: take a list.
def scrape(urls):
for url in urls:
do_something(url)
The caller simply has to pass a list with only one element: scrape(['localhost']).
Even better would probably be to take only one URL and let the caller iterate over a list. In that case the caller could parallelize the operations if she ever wants to.
As to your second question1: either you function takes a list as an argument or it doesn't. Either it makes sense in your program to pass around lists or it doesn't.
I guess, I'm not entirely sure what you are asking there, but then again your whole question sounds like you found a shiny new tool and now you want to use it everywhere, regardless of whether it makes sense or not.
1 please don't ask more than one question at once!
Either test the length of the resultant tuple, or put one or more normal arguments before it.
No.
For "give me at least one argument," just check the len() of the tuple you receive and throw an exception if you don't get at least one. Here I am using the fact that empty tuples are "falsy" to do that implicitly:
def __init__(self, *args):
if not args:
raise TypeError("__init__ takes at least 2 arguments (1 given)")
For "auto-unpacking," you will also need to test for this and perform it yourself. One method might be:
if len(args) == 1 and not isinstance(args[0], basestring) and iter(args[0]):
args = args[0]
The iter() will always be true, but if what you pass it is not iterable, it will raise an exception. If you want to provide a friendlier error message, you could catch it and raise something else.
Another alternative would be to write your method so that it recursively iterates over all elemets of args and all subcontainers within it; then it doesn't matter.
Or, you know, just have the caller pass in an iterable to begin with, and don't mess with *args. If the caller wants to pass in a single item, there is simple syntax to turn it into a list: foo([item])

Categories

Resources