Suppose there is a function defined as
def function1(x, y, z=True,a):
...
...
When I call function1, it seems I can call the function in the following manners
function1(10,2,3)
function1(x=10,y=2,a=3)
But calling function1(x=10,y=2, 3) will cause error, where 3 should be assigned to a. Generally, what are the correct ways to call a function withou causing potential issues.
That is not a valid way to define a function in python 2 or 3. Default arguments (ones with default values, namely x=y) must come after non-default arguments. With your function definition, you should receive the following error:
File "<stdin>", line 1
SyntaxError: non-default argument follows default argument
Related
If your question was closed as a duplicate of this, it is because you had a code sample including something along the lines of either:
class Example:
def __int__(self, parameter):
self.attribute = parameter
or:
class Example:
def _init_(self, parameter):
self.attribute = parameter
When you subsequently attempt to create an instance of the class, an error occurs:
>>> Example("an argument")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Example() takes no arguments
Alternately, instances of the class seem to be missing attributes:
>>> class Example:
... def __int__(self): # or _init_
... self.attribute = 'value'
>>> Example().attribute
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Example' object has no attribute 'attribute'
You might also wonder: what do these exception messages mean, and how do they relate to the problem? Why didn't a problem occur earlier, for example, with the class definition itself? How else might the problem manifest? How can I guard against this problem in the future?
This is an artificial canonical duplicate created specifically to head off two of the most common typographical errors in code written by new Python programmers. While questions caused by a typo are normally closed for that reason, there are some useful things to explain in this case, and having a duplicate target allows for closing questions faster. I have tried to design the question to be easy to search for.
This is because the code has a simple typographical error: the method should instead be named __init__ - note the spelling, and note that there are two underscores on each side.
What do the exception messages mean, and how do they relate to the problem?
As one might guess, a TypeError is an Error that has to do with the Type of something. In this case, the meaning is a bit strained: Python also uses this error type for function calls where the arguments (the things you put in between () in order to call a function, class constructor or other "callable") cannot be properly assigned to the parameters (the things you put between () when writing a function using the def syntax).
In the examples where a TypeError occurs, the class constructor for Example does not take arguments. Why? Because it is using the base object constructor, which does not take arguments. That is just following the normal rules of inheritance: there is no __init__ defined locally, so the one from the superclass - in this case, object - is used.
Similarly, an AttributeError is an Error that has to do with the Attributes of something. This is quite straightforward: the instance of Example doesn't have any .attribute attribute, because the constructor (which, again, comes from object due to the typo) did not set one.
Why didn't a problem occur earlier, for example, with the class definition itself?
Because the method with a wrongly typed name is still syntactically valid. Only syntax errors (reported as SyntaxError; yes, it's an exception, and yes, there are valid uses for it in real programs) can be caught before the code runs. Python does not assign any special meaning to methods named _init_ (with one underscore on each side), so it does not care what the parameters are. While __int__ is used for converting instances of the class to integer, and shouldn't have any parameters besides self, it is still syntactically valid.
Your IDE might be able to warn you about an __int__ method that takes suspicious parameters (i.e., anything besides self). However, a) that doesn't completely solve the problem (see below), and b) the IDE might have helped you get it wrong in the first place (by making a bad autocomplete suggestion).
The _init_ typo seems to be much less common nowadays. My guess is that people used to do this after reading example code out of books with poor typesetting.
How else might the problem manifest?
In the case where an instance is successfully created (but not properly initialized), any kind of problem could potentially happen later (depending on why proper initialization was needed). For example:
BOMB_IS_SET = True
class DefusalExpert():
def __int__(self):
global BOMB_IS_SET
BOMB_IS_SET = False
def congratulate(self):
global BOMB_IS_SET
if BOMB_IS_SET:
raise RuntimeError("everything blew up, gg")
else:
print("hooray!")
If you intend for the class to be convertible to integer and also wrote __int__ deliberately, the last one will take precedence:
class LoneliestNumber:
def __int__(self):
return 1
def __int__(self): # was supposed to be __init__
self.two = "can be as bad"
>>> int(LoneliestNumber())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __int__ returned non-int (type NoneType)
(Note that __int__ will not be used implicitly to convert instances of the class to an index for a list or tuple. That's done by __index__.)
How might I guard against the problem in the future?
There is no magic bullet. I find it helps a little to have the convention of always putting __init__ (and/or __new__) as the first method in a class, if the class needs one. However, there is no substitute for proofreading, or for training.
I got a method or __init__ with multiple argument, then I realize I do not need that argument so I delete it and rewrite the method. Now I have a lot of method/init call which have more argument than the method itself, resulting to unexpected argument.
I have a lot more unexpected argument than what the image shows, so much that I hope I do not need to delete the argument manually by hand. Is there any way to delete all unexpected argument automatically in PyCharm?
I do not want to silent the warning, I want to delete all the unexpected argument.
Simplified and exaggerated example of my problem
def foo(number):
pass
# code here ....
foo(1, "function call number 1")
foo(2, "function call number 2")
foo(3, "function call number 3")
.......
foo(1156, "function call number 1156")
I am new to making unit tests. I'm currently running pytest. I have this Program.py running but when I run pytest on my Program_test.py I've been failing the tests due to these TypeErrors from my where I had my assert line on the code below. I have the program ask the users for an input value or enter to exit the program. I have the 'import pytest' already included in my Program_test.py program.
Am I using lambda wrong? I'm not sure how to best approach this and get those user inputs to work. This is just testing the get_weight function from users.
***It was already fixed. I had a problem with lambda and underneath was very helpful
Here's an example to show where you are going wrong and for the purpose of explanation I am assigning the lambdas to variables:
zero_arg_lambda = lambda: "131" # Takes no args
one_arg_lambda = lambda x: "131" # Takes one arg
Call zero_arg_lambda with arg (same as your error):
zero_arg_lambda(1)
>>> Traceback (most recent call last):
>>> File "<input>", line 1, in <module>
>>> TypeError: <lambda>() takes no arguments (1 given)
Call one_arg_lambda :
one_arg_lambda(1)
>>> "131"
So in short your code is passing a parameter to the lambda even though you have specified that it does not take one.
The one_arg_lambda example takes a parameter and simply returns the value to the right of the colon.
I would recommend reading over the docs on lambda
Or if you don't look there the expected lambda format is:
lambda parameters: expression
Also note the docs on monkeypatch.context.setattr which have a good example of using a lambda expression.
To pin-point it the error in your code is coming from the context.setattr call inside your test.
def test_get_weight_returns_valid_input(monkeypatch):
with monkeypatch.context() as context:
# Old line causing error: context.setattr('builtins.input', lambda: "131")
context.setattr('builtins.input', lambda x: "131") # Fixed
I came across something I don't quite understand with how the parameters in the def function works:
ie:
def test(a=1, b=9, c='what'):
return a
test(a,b,c)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-295-937fe43dbbd5> in <module>()
2 return a
3
----> 4 test(a,b,c)
NameError: name 'a' is not defined
and
def test(a=1, b=9, c='what'):
return a
test('what')
Output: 'what'
Well, I am looking to set the parameters a,b as default values. Now, for the 1st example, if I call test(a,b,c), it says a is not defined. However, I have already "defined" it in the function parameter? That means, if let's say a, b and c are default parameters, I cannot execute test(a,b,c)? Only test() works? WHAT!
In example 2, I don't even know anymore...
The problem is that you are trying to call your method test with three variables which do not exist in the global scope where you are running the method.
The way you are defining your method:
def test(a=1, b=1, c=1)
does not imply that the arguments a, b, c are available to be used globally the way you are trying to use them.
By defining your method as a=1, b=1, c=1, you are setting default values to your arguments. What this means, is that you can call your method with or without passing arguments to your method.
So, for your first example, you can call it like this:
test(a="what")
Which indicates that now you are assigning "what" to a and will no longer hold its default value of "1".
Alternatively, you can simply call it without any arguments, which in turn would assign default values to your local arguments inside your method. So, if you actually call your method like this:
test()
Then, the default value of "1" will now be assigned to "a".
In your second example, you are passing a string, and by default, your parameters get assigned from left to right of your function definition. So, when you do this:
test("what")
You are assigning "what" to a.
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])