Self in Class Demanding Argument - python

For some reason most instances of classes are returning Type errors saying that insufficient arguments were passed, the problem is with self.
This works fine:
class ExampleClass:
def __init__(self, some_message):
self.message = some_message
print ("New ExampleClass instance created, with message:")
print (self.message)
ex = ExampleClass("message")
However almost every other Class I define and call an instance of returns the same error. The almost identical function:
class Test(object):
def __init__(self):
self.defaultmsg = "message"
def say(self):
print(self.defaultmsg)
test = Test
test.say()
Returns a Type Error, saying that it needs an argument. I'm getting this problem not just with that class, but with pretty much every class I define, and I have no idea what the problem is. I just updated python, but was getting the error before. I'm fairly new to programming.

You have to instantiate the class:
test = Test() #test is an instance of class Test
instead of
test = Test #test is the class Test
test.say() #TypeError: unbound method say() must be called with Test instance as first argum ent (got nothing instead)
if you are curious you can try this:
test = Test
test.say(Test()) #same as Test.say(Test())
It works because I gave the class instance (self) to the unbound method !
Absolutely not recommended to code this way.

You should add parentheses to instantiate a class:
test = Test()

Your test refers to the class itself, rather than an instance of that class. To create an actual test instance, or to 'instantiate' it, add the parentheses. For example:
>>> class Foo(object):
... pass
...
>>> Foo
<class '__main__.Foo'>
>>> Foo()
<__main__.Foo object at 0xa2eb50>
The error message was trying to tell you that there was no such self object to pass in (implicitly) as the function argument, because in your case test.say would be an unbound method.

Related

Different ways of calling methods in Python, How they work?

class Test():
def a(self):
return 6
Test_instance=Test()
print(Test.a(Test_instance))
print(Test_instance.a())
print(Test.a(Test_instance,3))
print(Test_instance.a(3))
The code above give me the following result:
6
6
TypeError: a() takes 1 positional argument but 2 were given
If I exclude the line print(Test.a(Test_instance,3)) I get the same print out. But Isn't a a method of both, Test class and Test_instance object? When I write Test_instance.a() I supose I'm giving one argument to the a() method of Test_instance and when I write Test.a(Test_instance) I supose I'm giving two arguments to the a() method of Test. But the error says that Test.a(Test_instance,3) gives 2 arguments. Shouldn't it be 3?
But Isn't "a" a method of both, Test object and Test_instance object?.
It is indeed.
When I write Test_instance.a() I supose im giving one argument to "a" method of Test_instance and When I write Test.a(Test_instance) I supose Im giving two arguments to "a" method of Test.
Right. But that applies only to method calls on instances.
But the error says that Test.a(Test_instance,3) gives 2 arguments. Shouldn't be 3?
No. It is 2, as you call the method directly on the class and not via the instance.
Calling a method directly on the class calls it as it is.
Calling a method on the instance, however, prepends the instance as first argument.
The reason for this are the internals.
If I do instance.X, X is a class member and implements the __get__() method (Descriptor protocol), internally X.__get__() is called and the result of it is produced for instance.X.
And functions implement the descriptor protocol in order to create an instance method object, which is reponsible for prepending the instance as first argument.
So, in your example, you as well can do
>>> print(Test_instance.a)
<bound method Test.a of <__main__.Test instance at 0x7f6e232e3690>>
>>> Test.a.__get__(Test_instance, Test)
<bound method Test.a of <__main__.Test instance at 0x7f6e232e3690>>
Both these "bound methods" are what I referred to as "instance method object".
Other example for this:
class Desc(object):
def __get__(self, a, b):
print('Calling __get__(%r, %r, %r)' % (self, a, b))
return a or b
class Test():
x = Desc()
>>> Test.x
Calling __get__(<__main__.Desc object at 0x7f6e232e1810>, None, <class __main__.Test at 0x7f6e232ea050>)
<class __main__.Test at 0x7f6e232ea050>
>>> inst = Test()
>>> inst.x
Calling __get__(<__main__.Desc object at 0x7f6e232e1810>, <__main__.Test instance at 0x7f6e232e3c80>, <class __main__.Test at 0x7f6e232ea050>)
<__main__.Test instance at 0x7f6e232e3c80>
What happens here?
Test.x takes the x member of Test and calls its .__get__(x, None, Test). This method returns b (which is set to Test), as the a parameter is None.
inst.x takes the x member of Test and calls its .__get__(x, inst, Test). This in turn returns a.
In a similar way, methods are set up to work.
Properties as well use the same mechanism, BTW.
If you use the #classmethod and #staticmethod decorators, they wrap the functions into some wrapping objects which have a slightly different .__get__() behaviour.
When you do instance.a(), instance is impliciltly passed as the first argument. When you do instance.a(3), you give two arguments (the implicit first instance, and the explicit 3), which your function cannot handle.
When you do Test.a(), Test is not passed as an implicit first argument because a is not defined as a class method.
If you do
class Test():
#classmethod
def a(self):
return 6
and then try Test.a(123) would give you the error a() takes 1 positional argument but 2 were given
Or Test.a(Test_instance,3), you'll get the error you expect.

NameError: name 'self' is not defined Explain

I'm trying to understand how "self" works. In this first code I got error but I belive I did everything right. After that I try few more things to figure it but could not. What am I missing here?
class myClass:
def foo(self):
print('WORKED')
self.foo()
NameError: name 'self' is not defined
class myClass:
def foo(self):
print('WORKED')
foo()
TypeError: foo() missing 1 required positional argument: 'self'
class myClass:
def foo():
print('WORKED')
foo()
myClass.foo()
WORKED
WORKED
(in here pylint give warning that says "Method has no arguments")
The correct usage is:
class MyClass:
def foo(self):
print('WORKED')
def bar(self):
self.foo()
obj = MyClass()
obj.bar()
You have to define the method with the parameter self. It will be automatically passed as obj when calling obj.foo(). That is, obj.foo() is equivalent to MyClass.foo(obj).
Why?
class myClass:
def foo(s):
print('WORKED', s)
return s
s = foo(1)
print("Hello")
myClass.foo(2)
print(myClass.s)
Result:
WORKED 1
Hello
WORKED 2
1
So if you call foo() without self it will be considered as a class field. If you ommited field declaration (i.e. s = foo(1) being foo(1) directly) it will execute also (as your code) but will not store result anywhere.
You cannot s = self.foo(1), because self will not be defined outside a member function. However, you can call it directly s = foo(1) and store in member s
Others have provided examples of code which runs, but I think there's a deeper issue of not understanding how Python works.
The thing to understand here is that unlike other languages like Java or C#, in Python the "body" of a class is a block of code which gets executed during the creation of the class.
class creates a special scope, then all the inside the body is run, then the class is created using all the symbols collected in the class body. It's also different from Ruby where first the class is created then the body is executed (and it has a self representing the class itself and you can call methods like attr_accessor): in Python first the body is executed then the class is created.
An other thing to note is that in Python self is not exactly magical, rather when you write obj.foo() Python executes it as type(obj).foo(obj). Technically you don't even have to call the first parameter self.
This means:
in your first snippet, right after your defined the method you tried to call it on something which doesn't even exist a this point (you've not created a self you could call)
in your second snippet, the function exists in the scope but it's not been converted to a method yet, so it's still waiting for one positional parameter.
in your third snippet, the function exists in the scope and takes no parameters and you can call it, however if you try to call it on an instance afterwards it's not going to work properly
PS: essentially you can think of:
class Foo:
...
as a shorthand for
def Foo_body:
...
return locals()
Foo = type("Foo", (object,), Foo_body())

Why python super() not working without parameters in ABCMETA class?

I have a problem with understanding function super() behavior in abc.ABCMeta class in python3.6.
class ParentClass():
def test():
return 1
​
#six.add_metaclass(ABCMeta)
class ChildClass(ParentClass):
def test(self):
test_ = super().test
test_ = 2
return test_
​
a = ChildClass()
​
a.test()
Code failed with 'TypeError: super(type, obj): obj must be an instance or subtype of type'.
When I used super(ChildClass, self).test it worked correctly! Printing from ChildClass test function:
print(__class__)
print(type(__class__))
print(ChildClass)
print(type(ChildClass))
I get next output:
<class '__main__.ChildClass'>
<class 'type'>
<class '__main__.ChildClass'>
<class 'abc.ABCMeta'>
I feel that the reason in object initialization but I can't undersand this information with my current skills in OOP and Python OOP.
0-argument super uses the class in which the call actually appeared, but after #six.add_metaclass(ABCMeta), the class bound to the ChildClass name is a new class created by the decorator. 0-argument super is still using the original class.
If you're going to use 0-argument super, which only works on Python 3, just use Python 3 metaclass syntax instead of six.

Python AttributeError: Object has no attribute in Unittest

I have 2 scripts, 1st is All_Methods, and another is All_Testcases, as I am using unittest framework, so here we go.
All_Methods is like:
class All_Services():
def abc(self):
x =1
def bca(self):
print "My Name is Taimoor"
self.abc()
def cba(self):
self.bca()
and on another script which is All_TestCases is like this:
from All_Methods import All_Services as service
class All_TestCases(unittest.TestCase):
def test_1_running_method(self)
service.cba(self)
Exception showing is:
AttributeError: 'All_TestCases' object has no attribute 'bca'
Kindly someone tell me, what I am missing here?
Thanks.
You are not using classes in the usual way when you pass in self to methods that you call on the class. Common is to call the methods on instances of the class and getting the self argument implicitly.
When you call Method.running_query_Athena(self) self is an instance of All_TestCases which does not have the method connecting_Athena.
Did you mean for All_TestCases to derive from All_Methods?
Why is All_Methods a class at all?
Use proper indentation since python is solely based on the basis of how the code is indented.
Please, Please use proper naming conventions; as advised under PEP 8.
You're trying to access an instance method without an instance.
Try the following:
class MyClass:
def my_instance_method(self):
return True
#classmethod
def my_class_method(cls):
return True
#staticmethod
def my_static_method():
return True
This won't work:
>> MyClass.my_instance_method()
TypeError: my_instance_method() missing 1 required positional argument: 'self'
but these will since they are not bound to a class instance being created.
MyClass.my_class_method()
MyClass.my_static_method()
An instance method requires that you instantiate the Class; meaning you use:
MyClass().my_instance_method()
Since you seem to want to set response_id on the class instance; using the self argument which denotes the class instance to get the response_id. - I suggest that you use an instance method and instantiate the class as shown above (note the () after the class name)
Kindly do fix your formatting in the question.
There are quite a few things wrong with the code in the example, but putting that aside.
The error is caused by passing an instance of class A as the self argument to a (non-static) method of class B.
Python will attempt to call this method on the instance of class A, resulting in the missing attribute error.
Here is a simplified example of the problem:
class A:
def is_ham(self):
# Python secretly does `self.is_ham()` here,
# because `self` is the current instance of Class A.
# Unless you explicitly pass `self` when calling the method.
return True
class B:
def is_it_ham(self):
# Note, `self` is an instance of class B here.
return A.is_ham(self)
spam = B()
spam.is_it_ham()

Python class variable changed a function into a method, why?

Why does Python turn a free function into an unbound method upon assignment to a class variable?
def make_func(s):
def func(x):
return '%s-%d' % (s, x)
return func
class Foo(object):
foofunc = make_func('foo')
So this works as expected: (returns "dog-1")
make_func('dog')(1)
But this fails with:
Foo.foofunc(1)
TypeError: unbound method func() must be called with Foo instance as first argument (got int instance instead)
Upon closer inspection, Python turned the "inner" function func inside make_func into a method, but since there's no self, this method will never work. Why does Python do this?
>>> import inspect
>>> inspect.getmembers(Foo, inspect.ismethod)
[('foofunc', <unbound method Foo.func>)]
Python can't tell "how" you assigned a method to a class attribute. There is no difference between this:
class Foo(object):
def meth():
pass
and this
def func():
pass
class Foo(object):
meth = func
In both cases, the result is that a function object is assigned to a class attribute named 'meth'. Python can't tell whether you assigned it by defining the function inside the class, or by "manually" assigning it using meth = func. It can only see the "end result", which is an attribute whose value is a function. Either way, once the function is in the class, it is converted to a method via the normal process that notices functions in class definitions and makes them into methods.
class Foo(object):
foofunc = make_func('foo')
foofunc is a class variable, not a method (for which you need the 'def'). And you initialize it with the result of make_func(...), so it won't change again.
If you want to call Foo.foofunc, you need to assign foofunc = make_func without a parameter.

Categories

Resources