calling a class without () is working fine but not giving desired output - python-3.x

I am new to python, can anyone please explain to me why this is happening??
What is the meaning of "()"
class ganga:
a ="subhanshu"
def course(self,name):
self.ab = name
obj1=ganga() #it works fine
obj = ganga #works fine
obj1.course("apple") #it works fine
onj.course("apple") #gives me error
error is:
TypeError: course() missing 1 required positional argument: 'name'

Function course has two arguments: self and name. The self argument refers to the object on which to perform the function's operation.
Case #1
obj1 = ganga()
You created an object of the class ganga. When you called the function via the object obj1.course("apple"), the self argument was automatically filled in as obj1.
Case #2
obj = ganga
Here you made a copy of the class ganga and assigned it to the variable. Therfore, when you called the function, it expects you to specify both the arguments. Try the following -
obj1 = ganga()
obj.course(obj1, "apple")
This perform the course operation on obj1.

Related

Can't Access Instance Values Defined in Class Method (Python)

Before people start to refer documentations or calling me dumb, please keep in mind, I'm new to this programming world! Please criticize but don't discourage.
So, i just created a class user with a method named addusers in it. So, i just simply tried to invoke addusers method by giving arguments while invoking it.
Class that I made:
class user:
def addusers(self,name,age):
self.name = name
self.age = age
Made an object, and gave arguments to invoke a method:
result = product.addusers("nerd",43)
Trying to print instance method
print(result.name)
print(result.age)
Result I'm getting:
File "c:\Users\Nerd\Desktop\PythonBootCamp\chk.py", line 7, in <module>
result = product.addusers("nerd",43)
TypeError: product.addusers() missing 1 required positional argument: 'age'
Anybody has any idea what is happening?

Usage of __setattr__ to rewrite whole method of library class issue: missing 1 required positional argument: 'self'

I've got some imported packages with tricky structure
and need to call some method that bases on lots of other methods
with non-default parameters, which are not class attributes themself like pipeline in sklearn.
Minimal example of this module structure:
class Library_class:
def __init__(
self,
defined_class_options,
):
self.defined_class_options = defined_class_options
def method1( self , default_non_class_arg = 12 ):
assert self.defined_class_options==3
return default_non_class_arg
def method2( self, image ):
return image/ self.method1()
Default usage:
class_instance = Library_class( 3 )
class_instance.method2( 36 )
> 3.0
I need to set default_non_class_arg to 6 for example.
I've tried multiple approaches:
Analogous to https://stackoverflow.com/a/35634198/7607734
class_instance.method2( 36 ,
method1__default_non_class_arg=3 )
TypeError: method2() got an unexpected keyword argument 'method1__default_non_class_arg'
It don't work probably because class definitely don't have set_params
With setattr on redefined function
class_instance.__setattr__('method1',Library_class.new_method1)
class_instance.method2( 36 )
TypeError: new_method1() missing 1 required positional argument: 'self'
Both your snippets and question are quite messy, almost to the point of being unreadable.
Anyway, if you wantt to replace method1 with another function, say new_method1 in an specific instance, just do that. Your call to .__setattr__ does that, but it is not needed at all, (and if it was, due to you not having the method to be replaced name at code writting time, and needed it as a parameter, it is more correct to call the built-in setattr, not the instance method: `setattr(class_instance, "method1", new_method1").
Ordinarily, if you know, at code writting time you have to replace "method1" in an instance, the assigment operator will do it:
class_instance.method1 = new_method1
What went wrong in your examle is that if you assign a method to an instance, instead of a class, you are bypassing the mechanism that Python uses to insert the self attribute into it - so your new_method1 needs a different signature. (and this is exactly what the error message "TypeError: new_method1() missing 1 required positional argument: 'self'" is saying):
class MyClass:
...
def method1(self, param1=36):
...
...
def new_method1(param1=6): # <-- written outside of any class body, sans self
...
my_instance = MyClass()
my_instance.method1 = new_method1
this will work.
new_method1 could be written in a class body as well, and could be replaced just the same, but you would have to write it without the self parameter the same, and then it would not work straight as a normal method.
OR, you can, at assigment time, insert the self argument yourself - the functools.partial call is a convenient way to do that:
class MyClass:
...
def method1(self, param1=36):
...
def new_method1(self, param1=6):
...
...
my_instance = MyClass()
from functools import partial
MyClass.method1 = partial(MyClass.new_method1, my_instance)
Now, this should answer what you are asking, but it would not be honest of me to end the answer without saying this is not a good design. The best thing there is to pull your parameter from another place, it might be from an instance attribute, instead of replacing the method entirely just to change it.
Since for normal attributes, Python will read the class attribute if no instance attribute exists, it will happen naturally, and all you have to do is to set the new default value in your instance.
class MyClass:
default_param_1 = 36 # Class attribute. Valid for every instance unless overriden
...
def method1(self, param1=None):
if param1 is None:
param1 = self.default_param_1 #Automatically fetched from the class if not set on the instance
...
...
my_instance = MyClass()
my_instance.default_param_1 = 6
...

Python calling mock with "=" not called result

I am trying to mock the following call:
df_x = method() # returns a pandas dataframe
df_x.loc[df_x['atr'] < 0, 'atr'] = 0
I have mocked the method so it returns a MagicMock and set a default value to the __ getitem__ attribute of the MagicMock as like this:
mock_df_x = mock_method.return_value
mock_df_x.__getitem__.return_value = 0
The problem is when I try asserting the call:
mock_df_x.loc.__getitem__.assert_called_with(False, 'atr')
I get a function not called error. If I call the function like this without the "= 0" part the assertion works.
df_x.loc[df_x['atr'] < 0, 'atr']
The reason you are seeing this different behavior depending on whether on you have = 0 at the end of the call you are testing is that in Python's data model, those correspond to two different magic methods: __getitem__ and __setitem__.
This makes sense, because for example doing some_dictionary['nonexistent_key]' raises KeyError, whereas some_dictionary['nonexistent_key]' = 1 doesn't, and sets the value as expected.
Now, in order to fix your test, you only need to change your assertion from:
mock_df_x.loc.__getitem__.assert_called_with((False, 'atr'))
which only works if you are accessing the key, to:
mock_df_x.loc.__setitem__.assert_called_with((False, 'atr'), 0)
which works if you are trying to assign a value to that key.
Notice the extra parameter, too, corresponding to the value you are actually trying to assign.

Python: ' __init__() takes 7 positional arguments but 8 were given' -- but both statements seem wrong

I have a class that is called in a couple of contexts:
class Datamodel:
def __init__(self, habvalues, hablist=[], orglist=[], genlist=[]):
self.habvalues = habvalues
self.uses_database = False
if hablist and orglist and genlist:
self.hablist = hablist
self.orglist = orglist
self.genlist = genlist
self.uses_database = True
There is one method that calls this class using only the habvalues parameter, and it seems to work fine. However, when called using all the parameters, with lists that are shown by my logging calls to contain valid data, I get the following error message:
__ init__() takes 7 positional arguments but 8 were given
The calling function reads like this:
self.newmodel = evocontrol.Datamodel(self.habvalues, self.habRecords, self.orgRecords, self.genlist)
So, the error message seems to be wrong. There are not 7 positional arguments in my code, only 4. And only 4 are given.
What could be the source of a miscount such as this? What kinds of things should I be looking for here?
Please, try passing the arguments as keyword arguments
self.newmodel = evocontrol.Datamodel(self.habvalues, hablist=self.habRecords, orglist=self.orgRecords, genlist=self.genlist)

How can I make objects with functions? (Turning a string into a object name)

I've just started learning Python recently and the first project I'm making is a text based adventure game however I've run into a problem. I need a function that makes more objects using the class Goblin that are named after a string.
def spawn(name):
title = name
exec("{0} = {1}".format('title', Goblin))
return title, 'spawn'
Essentially, another function calls this function to create another Goblin (a class) using the input name(a string) as the name of the new Goblin.
What I don't under stand though is that when I run the code(using "bill" as the argument), it gives me this error.
bill = <class '__main__.Goblin'>
^
SyntaxError: invalid syntax
Shouldn't my function be equivalent to:
bill = Goblin
When you do this:
exec("{0} = {1}".format('title', Goblin))
format method converts Goblin class by calling default __str__ method which yields <class '__main__.Goblin'>
Do this instead:
exec("{0} = {1}".format('title', 'Goblin'))
Wait! don't to this, just do:
title = Goblin
as it's strictly equivalent (without any security issues :)).
But that will just alias Goblin class to title. No real interest to all this after all (unless you want to create an instance?: title = Goblin())
With your comment: "I want a Goblin that is named after the string which title represents" I get it: you need
exec("{0} = {1}".format(title, 'Goblin()'))
(no quotes for the first arg so the name you're passing is used, and () on the second to create an instance)
Again: this is really a clumsy way of doing it. What if you want to iterate through all your goblins?
It would be much better to create a dictionary:
goblins_dict = dict()
goblins_dict["my_goblin"] = Goblin()
goblins_dict["my_goblin_2"] = Goblin()
and so on...

Resources