Python Unbound method error? - python

I'm trying to inherit from this class:
class Event(Clock, Calendar):
def __init__(self):
year,month,day, hours, minutes,seconds = time.localtime()[0:6]
eClock = Clock(hours,minutes,0)
eCal = Calendar(month, day, year)
def createEvent(self,year,month,day,hours,minutes):
year,month,day = date[0:]
hours,minutes = ttime[0:2]
In order to create an event here:
sett = line[1:].split(",") # Line[1:] is going to be a
# date, such as 1/8/17 17:50.
date = sett[0]
ttime = sett[1]
ttime = ttime.split(":")
date = date.split("/")
Cevent = ttime + date
Cevent.event()
I have another class, called Reminder, that inits this:
event = Event.createEvent()
Anytime I try to run this program though, it gives me this error:
TypeError: unbound method createEvent() must be called with Event
instance as first argument (got nothing instead)
Im wondering why, and how I could take the method createEvent and use it in another class in the same file.

A bound method means that the method is called from a class. Let's look at an example:
class MyClass:
def add(self, x, y):
return x+y
vs
def add_numbers(x, y):
return x+y
The method add_numbers() is an unbound method, meaning it is not attached to any class instance. To use it, we can just call:
print(add_numbers(1, 2))
However, when we want to call the method add(), we need an instance of the class MyClass:
class_instance = MyClass()
print(class_instance.add(1, 2))
Notice that when we want to call the add() method, we first have to create a new instance of the class, then use that to call the method, Under the hood, python takes the class_instance variable and passes it to the method as the 'self' argument seen in the function definition.
In closing, your issue is in the line:
event = Event.createEvent()
The error is telling you that the method is expecting an instance of an event class, and not the class itself. If the Event class can be instantiated without arguments, then the correct syntax would be:
base_event = Event()
event = base_event.createEvent()
Of course, the method of instantiating the base_event variable will depend on the API you're trying to use.

Related

Metaclasses and methods

Adding a method to metaclass works perfectly in the below example.
class Test(object):
def __init__(self, x):
self.x = x
def double(self):
return self.x*2
# method to add
def quadruple(self):
return self.x*4
# creating metaclass
TypeTest = type('TypeTest', (Test,), {'triple': triple,
'quadruple': quadruple})
# prints 8
TypeTest(2).quadruple()
The below example doesn't work and I have no idea why. It simply doesn't recognise self in the parsed function and a TypeError occurs.
class Vehicle(object):
def __init__(self, wheels, door=False):
self.wheels = wheels
self.door = door
# method to add
def check_load(self, x):
if x > self.load:
return "Load won't fit"
else:
return "Load will fit"
# creating metaclass
Truck = type('Truck', (Vehicle,), dict(wheels=4,door=True, load=100,
check_load=check_load))
# TypeError: check_load() missing 1 required positional argument: 'x'
Truck.check_load(10)
First of all: You are not creating a metaclass, you are creating regular classes. type() is the (base) metaclass here, calling it creates a new class object (the same type of object that a class statement produces).
The first type() call is essentially equivalent to:
class TypeTest(Test)
triple = triple
quadruple = quadruple
and the second example is the same as:
class Truck(Vehicle)
wheels = 4
door = True
load = 100
check_load = check_load
You forgot to create an instance of your Truck class:
Truck.check_load(10)
This leaves the check_load() function with nothing to bind to, there is no self.
In your first example you did create an instance:
TypeTest(2).quadruple()
Notice the call, passing in 2.
Create an instance for self to be bound to:
Truck(4, True).check_load(10)
If you wanted your class to not need arguments to create an instance, you'll need to provide a different __init__ method too, one that overrides the Vehicle.__init__ method:
def init(self): pass
Truck = type('Truck', (Vehicle,), dict(
wheels=4,door=True, load=100,
check_load=check_load, __init__=init))
Now you can create the instance without arguments:
Truck().check_load(10)

Python simple class understanding

I found the below code from a website while practicing basic python scripting. From the below code I was able to understand the class and instance and first print statement.
But I do not understand the concept used behind second and third print statement. How can an instance(in the below code polly) can be passed as an argument to a class's method? Is there any option in python that we can pass this like that?.
class Pet(object):
def __init__(self, name, species):
self.name = name
self.species = species
def getName(self):
return self.name
def getSpecies(self):
return self.species
def __str__(self):
return "%s is a %s" % (self.name, self.species)
polly = Pet("Polly", "Parrot")
print "Polly is a %s" % polly.getSpecies()
Polly is a Parrot
print "Polly is a %s" % Pet.getSpecies(polly)
Polly is a Parrot
print "Polly is a %s" % Pet.getSpecies()
Traceback (most recent call last):
File "", line 1, in
TypeError: unbound method getSpecies() must be called with Pet instance as first argument (got nothing instead)
In fact, instance.instance_method() will turn into TheClass.instance_method(instance) internally, the self refers to the instance itself. so the first and the second versions are equals to each other.
a simple example:
def getSpeciesGlobal(some_object): # a normal function
return some_object.species
polly = Pet("Polly", "Parrot")
polly.species # "Parrot"
getSpeciesGlobal(polly) # "Parrot"
# if we assign this function to the class.
Pet.getSpeciesGlobal = getSpeciesGlobal
Pet.getSpeciesGlobal(polly) # "Parrot"
# the original way in your question
polly.getSpecies() # "Parrot"
Pet.getSpecies(polly) # "Parrot"
In Python, a class can be treated as a bag of properties. See below:
>>> class Stuff:
... pi = 3.14
... def foo(x, y):
... return x + y
... bar = lambda s: s * 2
...
>>> Stuff.bar(4)
8
>>> Stuff.foo(5,6)
11
>>> Stuff.pi
3.14
In this example, Stuff is just a bunch of random objects. So Stuff.bar refers to the actual function bar. Instances of a class have a different behaviour: When a function is accessed, it automatically gets converted to a bound method. This means that the instance is automatically passed as the first argument.
When you call Pet.getSpecies(polly), polly will be passed in as the self parameter. There's no magic to self, it's just another parameter. The magic is when you access polly.getSpecies and get a <bound method Polly.getSpecies of <__main__.Polly object at 0x7f946cd14b38> instead of a <function Polly.getSpecies at 0x7f946cd1e048>.
There's also the #classmethod decorator, which receives the class as the first argument instead of the instance, as well as making code easier to understand by clearly delimiting class methods and instance methods.
In the second print statement, polly is passed as the self argument to the class method. This happened implicitly in the first print statement.
On the third print, the class method is called, but there is no actual object with data to act on.

Inheritance of function from class but editing that function

I'm using Python and I have two classes. I want to import a function for a class but with the ability of adding things to that function.
class Main(self):
def __init__(self):
thingstodo()
def function(self, keypressed):
#LOTS OF CODE
keyname = keypressed
if keyname = "Escape":
dosomething()
class Main2(Main):
def __init(self):
Main.__init__(self)
def function(self, keypressed):
Main.function(self, keypressed)
if keyname = "control":
dootherthing()
Basic principles
You cannot access local variables from one function (or method) in another function. This is by design.
This class Main(self): is wrong. In Python 3 do class Main:. While using self as the name of the first argument in method is a strong convention, self is just an ordinary name not a reserved keyword or built-in.
There are several problems here:
def __init(self):
Main.__init__(self)
a. The method name needs to __init__() not __init.
b. Don't hardwire the name of the parent class with Main.__init__(self) use super().__init__().
c. If you don't do anything extra in the __init__() of Main2, than you don't need to implement the __init__() at all.
Possible solution
For your problem, using a dictionary with the key press names as keys and the functions for the actions as values seems useful.
First define a few small helper functions:
def thingstodo():
print('thingstodo')
def dosomething():
print('something')
def dootherthing():
print('dootherthing')
Now your main class:
class KeyAction: # Python 3
def __init__(self):
thingstodo()
self.key_actions = {'Escape': dosomething}
def handel_key_press(self, keypressed):
#LOTS OF CODE
keyname = keypressed
func = self.key_actions.get(keyname)
if func is not None:
func()
Names are important, therefore I use KeyAction instead of Main.
This line self.key_actions = {'Escape': dosomething} is the core of this solution. Here self.key_actions is a dictionary that maps names of key press events to functions. Note dosomething without the () because I put the function object into the dictionary rather than calling this function.
Calling this function is a bit different:
func = self.key_actions.get(keyname)
if func is not None:
func()
I use the get() method of the dictionary. This returns the value for the key if the key is in it and None if not. Now func holds either a reference to the function dosomething if the key was Escape or None. If it is a function I call it with func().
An alternative here could be a try-except:
def handel_key_press(self, keypressed):
#LOTS OF CODE
keyname = keypressed
try:
self.key_actions[keyname]()
except KeyError:
pass
Now, in your child class, you only need to add another key-value pair to self.key_actions to extend its functionality:
class ExtendedKeyAction(KeyAction):
def __init__(self):
super().__init__()
self.key_actions['control'] = dootherthing
Make two instances and test your code:
key_action = KeyAction()
key_action.handel_key_press('Escape')
key_action.handel_key_press('undefined')
extended_key_action = ExtendedKeyAction()
extended_key_action.handel_key_press('Escape')
extended_key_action.handel_key_press('control')
extended_key_action.handel_key_press('undefined')
prints:
thingstodo
something
thingstodo
something
dootherthing

Change method definition

I want to change method definition of a class.
That is my case:
(I am importing these classes from another file)
class A(object):
def __init__(self, str):
self.str = str
def method_a(self):
print self.str
class B(object):
def __init__(self, str):
self.a = A(str)
def method_b(self):
self.a.method_a()
#######################################
from module import A, B
def main():
b = B('hello')
def my_method_a(self):
print self.str + 'other definition'
b.a.method_a = my_method_a
b.method_b()
if __name__ == '__main__':
main()
When I try to execute it, I get:
my_method_a() takes exactly 1 argument (0 given)
Because it does not get 'self'.
Any help please.
If you were to run type(b.a.method_a) before patching the method, you would see <type 'instancemethod'>. Running the same code after the patch produces <type 'function'>. In order for a function to work properly as a method, it must be an attribute of the class, not an instance of the class. The following would work, as you are manually invoking the magic that produces a method from a function:
b.a.method_a = my_method_a.__get__(b.a, A)
See https://wiki.python.org/moin/FromFunctionToMethod for more information.
The difference is that when you call b.a.method_a() after the patch, method_a is an attribute of the instance b.a, not of the class A. As a result, the function's __get__ method is never called to produce an instancemethod object which already has b.a bound to the first argument of method_a.
From one perspective, b.a.method_a() is identical to A.method_a(b.a). How does Python make that transition? You need to understand the descriptor protocol. All function objects implement the __get__ method to return an instancemethod object, which you can think of as the original function with the first argument bound to the appropriate object. Consider this code:
b = B()
b.a.method_a()
Does b have an attribute called a? Yes; we set it in B.__init__.
Does b.a have an attribute method_a? No.
Does type(b.a) (that is, A) have an attribute method_a? Yes.
Call A.method_a.__get__(b.a, A), since method_a was looked up for an instance. The result is an instance method object, with its first argument bound to b.a. (This is why you can consider b.a.method_a() identical to A.method_a(b.a)).
Call the resulting instance method with zero arguments.
Now consider this code.
b = B()
b.a.method_a = my_method_a
b.a.method_a()
Does b have an attribute called a? Yes; we set it in B.__init__.
Does b.a have an attribute method_a? Yes. We set it just before we tried to call it.
Since b.a.method_a was an instance lookup, not a class lookup, the descriptor protocol is not invoked and b.a.method_a.__get__ is not called, even though my_method_a has a __get__ function just like every other function.
Call b.a.method_a with zero arguments.
This produces the error, since the function expects one argument.
why not just use inheritance and method overrides:
from module import A, B
class myA(A):
def method_a(self):
print self.str + ' other definition'
class myB(B):
def __init__(self, str):
self.a = myA(str)
def main():
b = myB('hello')
b.method_b()
if __name__ == '__main__':
main()

Communicating between objects in Python

I have something like this:
class exampleClass(object):
def doSomething(self,number):
return number + 1
class exampleClass2(exampleClass):
def callDefDoSomething(self):
print exampleClass.doSomething(5)
exampleClass2.callDefDoSomething()
-
TypeError: unbound method callDefDoSomething() must be called
with exampleClass2 instance as first argument (got nothing instead)
I started to learn about objects in Python but i cant find solution for this :(
You need to create an instance of the class, i.e., an active object, to make things work:
class exampleClass(object):
def doSomething(self,number):
return number + 1
class exampleClass2(exampleClass):
def __init__(self):
self.member1 = exampleClass()
def callDefDoSomething(self):
print self.member1.doSomething(5)
object2 = exampleClass2()
object2.callDefDoSomething()
doSomething is a method of exampleClass. Therefore, it has to be called for an instance of this class.
In callDefDoSomething, you use
exampleClass.doSomething(5)
exampleClass, however, is not an instance of this class but the class itself. What you want to use here is
self.doSomething(5)
self refers to the instance of exampleClass2, for whichcallDefDoSomethingsis invoked, which, due to inheritance, is an instance ofexampleClass`.
Regular class methods can only be called for instances not for classes. So if you want to call callDefDoSomething you have to first instantiate exampleClass2. You also have to instantiate exampleClass inside the call to callDefDoSomething.
class exampleClass(object):
def doSomething(self,number):
return number + 1
class exampleClass2(exampleClass):
def callDefDoSomething(self):
exampleClassInstance = exampleClass()
print exampleClassInstance.doSomething(5)
exampleClass2Instance = exampleClass2()
exampleClass2Instance.callDefDoSomething()
If you want to call methods on classes you should try classmethods. Check the documentation on classes in the python tutorial.
You can use this:
class exampleClass(object):
def doSomething(self,number):
return number + 1
class exampleClass2(exampleClass):
def callDefDoSomething(self):
print super(exampleClass2,self).doSomething(5)
example = exampleClass2()
example.callDefDoSomething()

Categories