Unable to call function with self - python

I'm writing a simple code snippet here, but unable to run the code
class test:
def __init__(self):
pass
def functiona(self, a):
b = a+0
print(b)
def functionb(self):
a = 5
self.functiona(a)
test.functionb('abc')
It errors out with "AttributeError: 'str' object has no attribute 'functiona'" Unable to call it with self. However, if I provide test.functiona(a) it works fine.
Few of other code samples works with self.function, how to solve this issue

test.functionb('abc') is a function call on the class, not on an instance.
I suppose it works if you do test().functionb('abc')?
The difference is:
In your case, you call the function object on the class. As it is not a staticmethod or classmethod, it is called with self = 'abc', a string. This string hasn't a method functiona().
In my case, the call operates on a class instance. Here, self is set to the instance you just created – and you get an error because it doesn't know where to pass the 'abc'.

Problem lies in the call test.functionb('abc'). You are not using object of the class to call the method. So, the self parameter is not passed.
Python considers, the first parameter to be self, and you passed 'abc' which is a string.
Use it like test().functionb('abc') , then the default first argument becomes the object of test - like functionb(test_ob, 'abc').

you can add the decorator #classmethod and then call it like you did
class test:
def __init__(self):
pass
#classmethod
def functiona(self, a):
b = a+0
print(b)
#classmethod
def functionb(self):
a = 5
self.functiona(a)
>>> test.functiona(1001)
>>> 1001
>>> test.functionb()
>>> 5

Problem lies in the call test.functionb('abc'). You are not using object of the class to call the method. So, the self parameter is not passed. Python considers, the first parameter to be self, and you passed 'abc' which is a string.
Use it like test().functionb('abc') , then the default first argument becomes the object of test - like functionb(test_ob, 'abc').

Related

Difference between using the decorator and the function with staticmethod

I am trying to create a class which gets given a function, which will then be run from that instance. However, when I tried to use staticmethod, I discovered that there is a difference between using the decorator and just passing staticmethod a function.
class WithDec():
def __init__(self):
pass
#staticmethod
def stat(val):
return val + 1
def OuterStat(val):
return val + 1
class WithoutDec():
def __init__(self, stat):
self.stat = staticmethod(stat)
With these two classes, the following occurs.
>>> WithDec().stat(2)
3
>>> WithoutDec(OuterStat).stat(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'staticmethod' object is not callable
What is going on, and what can I do to stop it.
Static methods still work through the descriptor protocol, meaning that when it is a class attribute, accessing it via an instance still means that the __get__ method will be called to return an object that actually gets called. That is,
WithDec().stat(2)
is equivalent to
w = WithDec()
w.stat(2)
which is equivalent to
WithDec.stat.__get__(w, WithDec)(2)
However, the descriptor protocol is not invoked when the static method is an instance attribute, as is the case with WithoutDec. In that case
WithoutDec().stat(2)
tries to call the literal staticmethod instance stat, not the the function returned by stat.__get__.
What you wanted was to use staticmethod to create a class attribute, just not via decorator syntax:
class WithoutDec():
def stat(val):
return val + 1
stat = staticmethod(stat)
You first bind stat to a regular function (it's not really an instance method until you try to use it as an instance method), then replace the function with a staticmethod instance wrapping the original function.
The problem is that you are trying to use staticmethod() inside __init__, which is used to create an instance of the class, instead of at the class level directly, which defines the class, its methods and its static methods.
This code works:
def OuterStat(val):
return val + 1
class WithoutDec():
stat = staticmethod(OuterStat)
>>> WithoutDec.stat(2)
3
Note that trying to create an instance of WithoutDec with its own, different, version of stat, is contrary to the meaning of a method being static.
I found a very inspiring solution on this thread. Indeed your code is not very pythonic, and attributes a static method to an attribute of an instance of your class. The following code works:
class WithoutDec():
stat = None
#staticmethod
def OuterStat(val):
return val + 1
then you call:
my_without_dec = WithoutDec()
my_without_dec.stat = WithotuDec.OuterStat
my_without_dec.stat(2)
later if you want to create a new method, you call:
def new_func(val):
return val+1
WithoutDec.newStat = staticmethod(new_func)
my_without_dec.stat = WithoutDec.newStat
my_without_dec.stat(2)
Yes -
In this case, you just have to add the function as an attribute of the instance, it will work as expected, no need for any decorators:
def OuterStat(val):
return val + 1
class WithoutDec():
def __init__(self, stat):
self.stat = stat
The thing is: there is a difference if a function is an attribute of the class or an attribute of the instance. When it is set inside an instance method with self.func = X, it becomes an instance attribute - Python retrieves it the way it was stored, with no modifications, and it is simply another reference to the original function that can be called.
When a function is stored as a class attibute, instead, the default behavior is that it is used as an instance method: upon retrieving the function from an instance, Python arranges things so that self will be injected as the first argument to that function. In this case, the decorators #classmethod and #staticmethod exist to modify this behavior (injetct the class for classmethod or make no injection for staticmethod).
The thing is that staticmethod does not return a function - it returns a descriptor to be used as a class attribute, so that when the decorated function is retrieved from a class, it works as a plain function.
(Internal detail: all 3 behaviors: instance method, classmethod and staticmethod are implementing by having an appropriate __get__ method on the object that is used as an attribute to the class).
NB: There were some discussions in making "staticmethod" to become itself "callable", and simply call the wrapped function - I just checked it made it into Pythonn 3.10 beta 1. This means that your example code will work as is for Python 3.10 - nonetheless, the staticmethod call there is redundant, as stated in the beggining of this answer, and should not be used.

Can we call a class method without self?

class abc:
def yo(var):
a=var
print(a)
x=abc().yo(5)
Output:
Traceback (most recent call last):
File "main.py", line 5, in
x=abc().yo(5)
TypeError: yo() takes 1 positional argument but 2 were given
class abc:
def yo(self,var):
self.a=var
print(self.a)
x=abc().yo(5)
Output: 5
it's working till i use the self keyword i mean can we call a function without using self parameter in it why it says yo() takes 1 arguments and is given 2 when we exclude self?
you have to use decorators to change the first argument in your class methods ,if you don't put any decorator the fuction have the self argument by defaulf (the instance which use this method), if you put the #classmethod decorator like bellow the first argument is cls (the method's class):
class abc:
a = 'abc'
#classmethod
def aFunction(cls, value)
print(cls.a + value)
the second decorator, probably the one you are looking for allows you to have a class method without default argument:
class abc:
def __init__(self,value):
self.value = value
#staticmethod
def aFunction(value):
return value+'abc'
self is actually a convention used by since a long time and not a real python keyword.
self is nothing but a parameter in function and you can easily use another parameter name in place of it.
Then why use self?
Because it is advisable as it increases the readability of code.
Moreover, if the method does not require self, it usually signifies that it should be a static method

Can we create instance method with out self

I am trying to create class that having one instance method, is it possible to create instance method without self.
class A():
def display():
print("Hi")
a = A()
a.display()
I am getting like this: Type Error: display() takes no arguments (1 given)
For an instance method, you need to add a parameter that represents the instance itself. It MUST be present and it MUST be the first parameter of the method - that's mandatory, you cannot change this. It can be called whatever you want, although self is the standard used by the community, which you should also follow.
class A():
def display(self):
print('Hi')
Now, as you probably noticed, we're not doing anything in particular with the instance in the display method. To avoid this redundancy, we need to use a different type of method.
A method which does not take an instance as an argument is called a static method and is represented by the #staticmethod decorator directy above the function definition:
class A():
#staticmethod
def display():
print('Hi')
Both snippets will run without errors and, producing the same output when you execute the following code:
a = A()
a.display()
But the second version is preferred - because explicit is better than implicit.
Using #staticmethod will work... but I won't recommend it for beginner uses
Usually function define an object behavior so you'll need the object itself using self !
As others have pointed out, an instance method must have at least one parameter, as the object itself is passed (implicitly) as the first argument. But why?
This def statement, like any other, defines a function, not a method. So where does the method come from? Let's go step by step.
class A:
def display(self):
print("Hi")
If we look directly in the dictionary that stores a class's attributes, we see that display is bound to an instance of function.
>>> type(A.__dict__['display'])
<class 'function'>
We get the same result if we try to access the attribute using the normal dot syntax:
>>> type(A.display)
<class 'function'>
But something ... different ... happens if we try to access that function via an instance of the class:
>>> type(A().display)
<class 'method'>
Where did the method come from? Anytime you access an attribute, the machinery that handles such access looks to see if the result has a __get__ method. The function type provides such a method, so instead of getting the function itself back, you get the result of calling that function's __get__ method. That is, A().display is really the same as A.display.__get__(A(), A). And what __get__ returns is an object that does two things:
Saves a reference to the instance A()
Saves a reference to the function A.display.
When you try to call this object, what it does is takes any arguments passed to it, and passes the saved reference to A() along with those arguments to the function A.display. That is,
a = A()
a.display() == A.display.__get__(a, A)(a)
An that's why display gets defined with one more argument than is seemingly necessary.
Others have also mentioned static methods. What does #staticmethod do? staticmethod is another type, whose instances wrap a function. The staticmethod definition of __get__, though, doesn't do anything other than return the underlying function, not any kind of new method object. So given
class A:
#staticmethod
def display():
print("Hi")
we can see that display is an instance of static method, not a function:
>>> >>> type(A.__dict__['display'])
<class 'staticmethod'>
and that the __get__ method returns the function itself, whether the attribute is accessed via the class
>>> type(A.display)
<class 'function'>
or an instance
>>> type(A().display)
<class 'function'>

Python function pointer in class __init__

In the code below, class A has a member function which is set to point to a function defined outside the class.
in class B, the same function is set to the external pointer in the class definition.
Calling the function for an object of type A will fail, because the self does not get passed to the function. But for B, the self gets passed.
Why does the self get passed for B, but not for A?
def f1(s,a):
print s
print a
class A(object):
def __init__(self):
self.fp1 = f1
class B(object):
fp1 = f1
a=A()
b=B()
try:a.fp1("blaa")
except Exception, e: print `e`
try:b.fp1("bluu")
except Exception, e: print `e`
Output:
TypeError('f1() takes exactly 2 arguments (1 given)',)
<__main__.B object at 0x2ab0dacabed0>
bluu
When you did self.fp1 = f1 you just assigned a function to an instance variable of the class A. So when you call it you have to pass two arguments.
When you did:
class B(object):
fp1 = f1
during creation process of the class B python found a function fp1 in the class scope and created an instancemethod from it (replaced the variable with name fp1 with an instancemethod created from the function that it held before). When you call an instancemethod on an object self gets automatically passed as the first argument.
You can check this by typing:
>>> a = A()
>>> b = B()
>>> type(a.fp1)
function
>>> type(b.fp1)
instancemethod
In class A you bind a function to an instance. This could be really considered as "function pointer" so all arguments must be passed explicitly. In class B you bind the function to the class which will cause the function to work as method. You could modify class definition A to
class A(object):
def __init__(self):
A.fp1 = f1
which will give the same behavior has class B, i.e. fp1 of all instances points to f1, or you could wrap f1.
class A(object):
def __init__(self):
self.fp1 = lambda a: f1(self, a)
This will allow to change fp1 for each instance individually. The latter variant is probably what you were looking for.
The magic that makes instance.method(...) equivalent to Class.method(instance, ...) is dependent on the function object being an attribute of the class. The details vary (and with them, the ugly workaround by which you can create such a method). In Python 3, all functions are descriptors. In Python 2, there are special unbound method objects which are implicitly created to wrap functions stored as class attributes and do roughly what all functions do by themselves in Python 3.
In either case, accessing it through an instance creates a bound method which passes the instance along as first argument when called. In either case, a function accessed through an instance attribute is in no way special, it's just another object which can be passed around and used.
You can achieve similar behavior by either using partial (a bit of a leaky abstraction):
from functools import partial
# in __init__
self.fp1 = partial(f1, self)
or by creating a method which delegates:
def __init__(self):
self._fp1 = f1
def fp1(*args, **kwds):
return self._fp1(self, *args, **kwds)
In the first case you create a field in the class, that has a method object stored in it. So "a.fp1" is not a method call and therefore "a" is not put as the first argument. It's a retrieval of a method object, and then calling it.
For the second case, you can refer to the documentation:
Any function object that is a class attribute defines a method for
instances of that class.
So, for b "fp1" becomes a method for instances of class b.
You can find more detailed explanation here: method objects vs function objects , Python class instances vs class

Interesting 'takes exactly 1 argument (2 given)' Python error

For the error:
TypeError: takes exactly 1 argument (2 given)
With the following class method:
def extractAll(tag):
...
and calling it:
e.extractAll("th")
The error seems very odd when I'm giving it 1 argument, the method should take only 1 argument, but it's saying I'm not giving it 1 argument....I know the problem can be fixed by adding self into the method prototype but I wanted to know the reasoning behind the error.
Am I getting it because the act of calling it via e.extractAll("th") also passes in self as an argument? And if so, by removing the self in the call, would I be making it some kind of class method that can be called like Extractor.extractAll("th")?
The call
e.extractAll("th")
for a regular method extractAll() is indeed equivalent to
Extractor.extractAll(e, "th")
These two calls are treated the same in all regards, including the error messages you get.
If you don't need to pass the instance to a method, you can use a staticmethod:
#staticmethod
def extractAll(tag):
...
which can be called as e.extractAll("th"). But I wonder why this is a method on a class at all if you don't need to access any instance.
If a non-static method is member of a class, you have to define it like that:
def Method(self, atributes..)
So, I suppose your 'e' is instance of some class with implemented method that tries to execute and has too much arguments.
Am I getting it because the act of calling it via e.extractAll("th") also passes in self as an argument?
Yes, that's precisely it. If you like, the first parameter is the object name, e that you are calling it with.
And if so, by removing the self in the call, would I be making it some kind of class method that can be called like Extractor.extractAll("th")?
Not quite. A classmethod needs the #classmethod decorator, and that accepts the class as the first paramater (usually referenced as cls). The only sort of method that is given no automatic parameter at all is known as a staticmethod, and that again needs a decorator (unsurprisingly, it's #staticmethod). A classmethod is used when it's an operation that needs to refer to the class itself: perhaps instantiating objects of the class; a staticmethod is used when the code belongs in the class logically, but requires no access to class or instance.
But yes, both staticmethods and classmethods can be called by referencing the classname as you describe: Extractor.extractAll("th").
Yes, when you invoke e.extractAll(foo), Python munges that into extractAll(e, foo).
From http://docs.python.org/tutorial/classes.html
the special thing about methods is
that the object is passed as the first
argument of the function. In our
example, the call x.f() is exactly
equivalent to MyClass.f(x). In
general, calling a method with a list
of n arguments is equivalent to
calling the corresponding function
with an argument list that is created
by inserting the method’s object
before the first argument.
Emphasis added.
Summary (Some examples of how to define methods in classes in python)
#!/usr/bin/env python # (if running from bash)
class Class1(object):
def A(self, arg1):
print arg1
# this method requires an instance of Class1
# can access self.variable_name, and other methods in Class1
#classmethod
def B(cls, arg1):
cls.C(arg1)
# can access methods B and C in Class1
#staticmethod
def C(arg1):
print arg1
# can access methods B and C in Class1
# (i.e. via Class1.B(...) and Class1.C(...))
Example
my_obj=Class1()
my_obj.A("1")
# Class1.A("2") # TypeError: method A() must be called with Class1 instance
my_obj.B("3")
Class1.B("4")
my_obj.C("5")
Class1.C("6")`
try using:
def extractAll(self,tag):
attention to self

Categories