Python TypeError regarding arguments - python

This is my code:
class bla:
def function1():
print 1
def function2():
bla.function1()
x = bla()
x.function2()
I don't understand why I get the error "TypeError: function2() takes no arguments (1 given)" as I don't seem to be passing any argument to function2.

Regular methods are called with an implicit self reference to their object - otherwise they wouldn't be able to access any data members of x.
They should always be declared like so:
class bla:
def function1(self):
print 1
if you want them to operate on the object (self is loosely equivalent to the this pointer in C++, for example).
Alternatively, if you don't care about the object (so you're really just using the class to group some functions together), you can make them static like so:
class bla:
#staticmethod
def function1():
print 1
#staticmethod
def function2():
bla.function1()
In fact, that's the only way you can call bla.function1() without an instance of bla from your function2.

That's cause your calling your function as a method and that automatically binds the method's object as the first argument to your function.
Either do:
bla.function2() #a function call
or:
class bla:
#normal and correct way to define class methods - first argument is the object on which the method was called
def function1(self):
print 1
def function2(self):
self.function1()

You have to type:
class bla:
def function1(self):
print 1
def function2(self):
self.function1()
self (a reference to the object on which the method is called) is passed as the first parameter to each method. The name of this first variable, "self" is just a common convention.

You have to pass the argument self to the functions function1 and function2. See the Python Classes documentation. So your code would be
class Bla: # Notice capitalization.
def function1(self):
print 1
def function2(self):
bla.function1()
x = Bla()
x.function2()
See also the answers to the question Why do you need explicitly have the “self” argument into a Python method?.
Basically in Python a call to a member function (like function1)
x = Bla()
x.function1()
is translated into
Bla.function(x)
self is used to refer to the instance of the class x.

Related

Why is binding a class instance method different from binding a class method?

I was reading the python docs and stumbled upon the following lines:
It is also important to note that user-defined functions which are attributes of a class instance are not converted to bound methods; this only happens when the function is an attribute of the class.
Please, someone explain what does that mean in plain english.
I'm going to introduce some shorthand notation:
let 'user-defined functions' be denoted by f,
let 'class instance' be denoted by ci while class denoted simply by c. Obviously(?), ci = c(), with some abuse of notation.
Also, allow membership statements to be recast in simple set notation eg 'user-defined functions which are attributes of a class instance' in shorthand is 'vf: fεa(ci)', where v: 'for all' and where 'a' is the shorthand for (set of) attributes (eg of a class or class instance) and 'ε' denotes the set membership function.
Also, the process of binding a function is described in shorthand by ci.f(*args) or c.f(*args) => f(ci, *args) or f(c, *args) (the former referring to an instance method call while the later referring to a class method call)
Using the newly introduced shorthand notation, does the quote from the docs imply that
vf: fεa(c), c.f(*args) => f(c, *args) is a true statement
while
vf: fεa(ci), ci.f(*args) => f(ci, *args) is false?
Setting a User Defined Method to be an Attribute of Class, The Wrong Way
Consider the following example class A and function f:
class A:
pass
def f(self):
print("I\'m in user-defined function")
a = A()
The function f is defined separately and not inside the class.
Let's say you want to add function f to be an instance method for a object.
Adding it, by setting f as a attribute, won't work:
import types
class A:
pass
def f(self):
print("I\'m in user-defined function")
a = A()
a.f = f
# <function f at 0x000002D81F0DED30>
print(a.f)
# TypeError: f() missing 1 required positional argument: 'self'
# a.f()
Because function f is not bound to the object a.
That is why when calling a.f() it shall raise an error regarding the missing argument (if f has been bounded to a, that object a was the missing argument self).
This part is what the docs referred at:
It is also important to note that user-defined functions which are attributes of a class instance are not converted to bound methods.
Of course, all this has not to happen if function f has been defined inside class A, that's what the following part from the docs states:
...this only happens when the function is an attribute of the class.
Setting a User Defined Method to be an Attribute of Class, The Right Way
To add function f to object a you should use:
import types
class A:
pass
def f(self):
print("I\'m in user-defined function")
a = A()
a.f = types.MethodType( f, a )
# <bound method f of <__main__.A object at 0x000001EDE4768E20>>
print(a.f)
# Works! I'm in user-defined function
a.f()
Which bounds the user-defined method f to instance a.
When you create a method the usual way, it will be a bound method: it receives the instance as first argument (which we usually assign to 'self'):
class A:
def meth(*args):
print(args)
a = A()
a.meth()
# (<__main__.A object at 0x7f56a137fd60>,)
If you take an ordinary function and add it to the class attributes, it will work the same way:
def f(*args):
print(args)
A.f = f
a = A()
a.f()
# (<__main__.A object at 0x7f56a137f700>,)
The instance gets passed as first argument, it is a bound method.
If, on the other side, you make the function an attribute of an instance of the class, it won't be a bound method = it won't be passed the instance as first argument when called:
a = A()
a.f = f
a.f()
# ()
I don't think the fancy-schmancy formal logic notation is helping here.
However, to answer the question: what does "user-defined functions which are attributes of a class instance are not converted to bound methods; this only happens when the function is an attribute of the class" mean?
A bound method is one which is dependent on the instance of the class as the first argument. It passes the instance as the first argument which is used to access the variables and functions. In Python 3 and newer versions of python, all functions in the class are by default bound methods.
So, if you create a user-defined function as an attribute of a class instance, it is not automatically converted to a bound method. 'Class instance' is just a Python way of saying what 'object' or 'object instance' means in other languages.
For example:
class HelloClass:
greeting = 'Hello'
def greet(self, name):
print(f'{greeting} {name}')
hc = HelloClass()
hc.greet('John')
Here HelloClass is the class, while hc is the class instance. greet is a bound method, expecting at least a single parameter (called self by convention) which is automatically assigned the class instance when called - i.e. the value of self before printing hello John is the hc class instance.
Now, if you try this:
def greet_with_hi(self, name):
print(f'Hi {name}')
class HiClass:
greet = greet_with_hi
hc = HiClass()
hc.greet('John')
That works (although your IDE may object), but this doesn't work at all:
def greet_with_hi(self, name):
print(f'Hi {name}')
class HiClass:
def __init__(self):
self.greet = greet_with_hi
hc = HiClass()
hc.greet('John')
It causes TypeError: greet_with_hi() missing 1 required positional argument: 'name'. And it should, because .greet on an instance of HiClass is not a bound method and the self greet_with_hi expects won't be filled automatically.
I think the meaning is best clarified by way of example.
Suppose that we have a class instance containing various attributes that are user-defined functions.
add1 was added by defining it as part of the class definition.
add2 was added by monkey-patching the class before instantiation.
add3 was added by monkey-patching the class after instantiation
add4 was added by monkey-patching the instance after instantiation
class Number:
def __init__(self, x):
self.x = x
def add1(self):
return self.x + 1
def add2(self):
return self.x + 2
def add3(self):
return self.x + 3
def add4(self):
return self.x + 4
setattr(Number, 'add2', add2)
two = Number(2)
setattr(Number, 'add3', add3)
setattr(two, 'add4', add4)
print(two.add1()) # prints 3
print(two.add2()) # prints 4
print(two.add3()) # prints 5
print(two.add4()) # TypeError: add4() missing 1 required positional argument: 'self'
We try calling these.
The first three all work (in the case of add3 it doesn't even matter that it wasn't an attribute of the class at the time of instantiation).
Note that when we call these, we do not explicitly pass anything corresponding to the first positional argument inside the function (i.e. self) -- it is added automatically for us. This is what is meant by it being a bound method. It is declared with one positional argument and we are explicitly passing none at all.
But in the case of add4 it is complaining about missing positional argument - this is because the instance is not automatically added as a first argument. (It would work if you used explicitly two.add4(two).)
Bound methods are based on descriptors which are documented here. There is even a section "Functions and Methods".
It is a known fact, that descriptors work only in the classes, not in instances. That is documented here.
Putting those two pieces of information together explains the difference quoted in the question:
user-defined functions which are
attributes of a class instance are not converted to bound methods;
this only happens when the function is an attribute of the class.
Bound methods python
a bound-method is the one which is dependent on the instance of the class as the first argument. It passes the instance as the first argument which is used to access the variables and functions. In Python 3 and newer versions of python, all functions in the class are by default bound methods.
Let’s understand this concept with an example:
# Python code to demonstrate
# use of bound methods
class A:
def func(self, arg):
self.arg = arg
print("Value of arg = ", arg)
# Creating an instance
obj = A()
# bound method
print(obj.func)
Output:
< bound method A.func of <__main__.A object at 0x7fb81c5a09e8>>
Here,
obj.func(arg) is translated by python as A.func(obj, arg).
The instance obj is automatically passed as the first argument to the function called and hence the first parameter of the function will be used to access the variables/functions of the object.
Let’s see another example of the Bound method.
# Python code to demonstrate
# use of bound methods
class Car:
# Car class created
gears = 5
# a class method to change the number of gears
#classmethod
def change_gears(cls, gears):
cls.gears = gears
# instance of class Car created
Car1 = Car()
print("Car1 gears before calling change_gears() = ", Car1.gears)
Car1.change_gears(6)
print("Gears after calling change_gears() = ", Car1.gears)
# bound method
print(Car1.change_gears)
Output:
Car1 gears before calling change_gears() = 5
Gears after calling change_gears() = 6
<bound method Car.change_gears of <class '__main__.Car'>>
The above code is an example of a class method. A class method is like a bound method except that the class of the instance is passed as an argument rather than the instance itself. Here in the above example when we call Car1.change_gears(6), the class ‘Car’ is passed as the first argument.
Need for these bound methods
The methods inside the classes would take at least one argument. To make them zero-argument methods, ‘decorators‘ has to be used. Different instances of a class have different values associated with them.
For example, if there is a class “Fruits”, and instances like apple, orange, mango are possible. Each instance may have a different size, color, taste, and nutrients in it. Thus to alter any value for a specific instance, the method must have ‘self’ as an argument that allows it to alter only its property.
Example:
class sample(object):
# Static variable for object number
objectNo = 0
def __init__(self, name1):
# variable to hold name
self.name = name1
# Increment static variable for each object
sample.objectNo = sample.objectNo + 1
# each object's unique number that can be
# considered as ID
self.objNumber = sample.objectNo
def myFunc(self):
print("My name is ", self.name,
"from object ", self.objNumber)
def alterIt(self, newName):
self.name = newName
def myFunc2():
print("I am not a bound method !!!")
# creating first instance of class sample
samp1 = sample("A")
samp1.myFunc()
# unhide the line below to see the error
# samp1.myFunc2() #----------> error line
# creating second instance of class sample
samp2 = sample("B")
samp2.myFunc()
samp2.alterIt("C")
samp2.myFunc()
samp1.myFunc()
Output:
My name is A from object 1
My name is B from object 2
My name is C from object 2
My name is A from object 1
In the above example two instances namely samp1 and samp2 are created. Note that when the function alterIt() is applied to the second instance, only that particular instance’s value is changed. The line samp1.myFunc() will be expanded as sample.myFunc(samp1). For this method, no explicit argument is required to be passed. The instance samp1 will be passed as an argument to the myFunc(). The line samp1.myFunc2() will generate the error :
Traceback (most recent call last):
File "/home/4f130d34a1a72402e0d26bab554c2cf6.py", line 26, in
samp1.myFunc2() #----------> error line
TypeError: myFunc2() takes 0 positional arguments but 1 was given
It means that this method is unbound. It does not accept any instance as an argument. These functions are unbound functions.
Sources:
Geeks For Geeks: Bound Methods Python
Geeks For Geeks: Bound, unbound and static methods in Python

how to move function to class? python

I would like to to use service functions in a classmethod, where the service function is defined somewhere else. I want to be dynamic, so I can define different functions in different situations. I've tried this:
def print_a():
print 'a'
class A:
func = print_a
#classmethod
def apply(cls):
cls.func()
A.apply()
Yet I receive this error:
unbound method print_a() must be called with A instance as first argument (got nothing instead)
Any ideas how to make it work?
you can use call
def print_a():
print 'a'
class A:
func = print_a.__call__
#classmethod
def apply(cls):
cls.func()
A.apply()
Output
a

Binding class methods to external functions

I get an error when trying to bind a class method to a function. Why?
def foo():
print "Hello world"
class something(object):
bar = foo
test = something()
test.bar()
TypeError: foo() takes no arguments (1 given)
Also, if I am unable to modify foo, can I do this adaptation from within the class definition?
A simple way to do it is to wrap the function in a staticmethod inside A:
class A():
bar = staticmethod(foo)
>>> test = A()
>>> test.bar()
Hello world
A class method in python always takes at least one argument, usually called self. This example is taken from the official Python tutorial:
# Function defined outside the class
def f1(self, x, y):
return min(x, x+y)
class C:
f = f1
def g(self):
return 'hello world'
h = g
Note that both methods, regardless of whether they are defined outside or inside of the class, take self as an argument.
Edit: If you really can't change your foo function, then you can do something like this:
>>> def foo():
... print "Hello World"
...
>>> class something(object):
... def bar(self): foo()
...
>>> test = something()
>>> test.bar()
Hello World
When you call a class method this way you pass the class instance as the first parameter.
When you call test.bar what in fact happens is more like bar(test). You pass an argument to the method.
Class methods all have a first argument of the instance of the class. So add a parameter to your function and it would work.
The initial def creates a function object named foo. Since it's outside any class, it's just a function that takes no arguments. The assignment bar = foo just gives the new name test.bar to that same function object. The call test.bar(), however, assumes that bar is a class method, and passes the object test as the first argument to the method (the one that you would normally call self). You could call it as a static method with something.bar() and not get the error.
Remember that when a python class calls one of it's methods it will pass in a self argument. You need to account for that in your code:
def foo(self):
print ("Hello world")
class something(object):
bar = foo
test = something()
test.bar()
You can read all about classes in the Python Documentation
The easiest workaround to not passing in a self that I can think of is:
def foo():
print ("Hello world")
class something(object):
bar = [foo] # contains pointer to static method
test = something()
test.bar[0]() # calls the static method

Python member function decorators use instance as a parameter

How to use instance as a parameter in the python member function decorators.
The following is an example.
def foo(func):
def wrap(s):
func()
s.ma()
return wrap
class A:
def ma(self):
print "this is ma"
#foo(self) #error.name 'self' is not defined
def mb(self):
print "this is mb"
It's not clear what you're looking for, but if you want to be able to use the reference to the instance inside your decorator:
def foo(func):
def wrap(s): # I'd call this 'self' instead of 's' to remind us it's a reference to an instance
func(s) # This is a function, not a method yet - so we need to pass in the reference
s.ma() # This is a method, because you use attribute lookup on the object s to get it
return wrap
class A:
def ma(self):
print "this is ma"
#foo # if the way foo wraps mb doesn't depend on some arg, don't use args here
def mb(self):
print "this is mb"
I think you're confused here about the difference between methods and functions in Python – you seem to expect func will work like a method, when in fact it will still be a function when it is being decorated. It is the decorated function that will, at attribute lookup on the instance, be turned into a method; this means you still need the explicit self when you call func in your wrapper function.
See the terrific answer to How to make a chain of function decorators? for a better explanation of what's going on.

decorator inside class & decorated classmethod without 'self' gives strange results

Example code:
# -*- coding: utf-8 -*-
from functools import wraps
class MyClass(object):
def __init__(self):
pass
#decorator inside class
def call(f):
#wraps(f)
def wrapper(*args):
print 'Wrapper: ', args
return wrapper
#decorated 'method' without self
#call
def myfunc(a):
pass
c = MyClass()
c.myfunc(1)
Returns:
Wrapper: (<test3.MyClass object at 0xb788a34c>, 1)
Is this normal? Can someone explain?
If this is a feature I would use it in my library.
This is perfectly normal.
The function myfunc is replacecd by an instance of wrapper. The signature of wrapper is (*args). because it is a bound method, the first argument is the instance of MyClass which is printed out after the string `Wrapper: '.
What's confusing you?
It's worth noting that if you use call as a decorator from outside of MyClass, it will generate a TypeError. One way around this is to apply the staticmethod decorator to it but then you can't call it during class construction.
It's a little bit hacky but I address how to have it both ways here.
update after comment
it gets the instance as the first argument regardless of if you type self in the parameter list because after the class is created, and an instance instantiated, it is a bound method. when you call it in the form
#instance.call
def foo(bar):
return bar + 1
it expands to
def foo(bar):
return bar + 1
foo = instance.call(f)
but note that you are calling it on an instance! This will automatically expand to a call of the form
def foo(bar):
return bar + 1
foo = MyClass.call(instance, f)
This is how methods work. But you only defined call to take one argument so this raises a TypeError.
As for calling it during class construction, it works fine. but the function that it returns gets passed an instance of MyClass when it is called for the same reason that I explained above. Specifically, whatever arguments you explicity pass to it come after the implicit and automatic placement of the instance that it is called upon at the front of the argument list.
#call
def myfunc(a):
...
is equivalent to
def myfunc(a):
...
myfunc=call(myfunc)
The orginial myfunc may have expected only one argument, a, but after being decorated with call, the new myfunc can take any number of positional arguments, and they will all be put in args.
Notice also that
def call(f)
never calls f. So the fact that
def myfunc(a)
lacks the normal self argument is not an issue. It just never comes up.
When you call c.myfunc(1), wrapper(*args) gets called.
What is args? Well, since c.myfunc is a method call, c is sent as the first argument, followed by any subsequent arguments. In this case, the subsequent argument is 1. Both arguments are sent to wrapper, so args is the 2-tuple (c,1).
Thus, you get
Wrapper: (<test3.MyClass object at 0xb788a34c>, 1)

Categories