Python 3 : Inheritance and the assignment of "self" - python

Why does this script require "self" as an argument to mssg() in line 3? PyCharm flags "self" in line 3 as, expected type "Another", got "Main" instead. This warning makes sense to me (although the code works). When "self" is omitted, Python throws an error:
TypeError: mssg() missing 1 required positional argument: 'self'
class Main():
def __init__(self):
print(Another.mssg(self))
class Another():
def __init__(self):
pass
def mssg(self):
return "Hello World"
_foo = Main()
Using your guidance, here are three different ways to prevent the TypeError:
class Main():
def __init__(self):
print(Another.mssg('asdasdsa'))
print(Another().mssg())
print(_bar.mssg())
class Another():
def __init__(self):
pass
def mssg(self):
return "Hello World"
_bar = Another()
_foo = Main()

If you use Another.mssg(self), then your are calling a class method, that is why self is taken as a parameter and you need to use exactly one argument to call the function. Try print(Another.mssg('asdasdsa')) and you will see that it works.
If your intention was using mssg(self) as an instance method, then you should call it using print(Another().mssg()), so you create your instance and then you call its method.

Related

Is `self` actually mandatory for class methods in Python?

I saw a code snippet in Python 3.6.5 that can be replicated with this simplified example below and I do not understand if this is something concerning or not. I am surprised it works honestly...
class Foo:
def bar(numb):
return numb
A1 = bar(1)
print(Foo)
print(Foo.A1)
print(Foo.bar(17))
In all python guides that I have seen, self appears as the first argument for all the purposes we know and love. When it is not, the methods are decorated with a static decorator and all is well. This case works as it is, however. If I were to use the static decorator on bar, I get a TypeError when setting A1:
Traceback (most recent call last):
File "/home/user/dir/understanding_classes.py", line 1, in <module>
class Foo:
File "/home/user/dir/understanding_classes.py", line 7, in Foo
A1 = bar(1)
TypeError: 'staticmethod' object is not callable
Is this something that is OK keeping in the code or is this a potential problem? I hope the question is not too broad, but how and why does this work?
The first parameter of the method will be set to the receiver. We call it self by convention, but self isn't a keyword; any valid parameter name would work just as well.
There's two different ways to invoke a method that are relevant here. Let's say we have a simple Person class with a name and a say_hi method
class Person:
def __init__(self, name):
self.name = name
def say_hi(self):
print(f'Hi my name is {self.name}')
p = Person('J.K.')
If we call the method on p, we'll get a call to say_hi with self=p
p.say_hi() # self=p, prints 'Hi my name is J.K.'
What you're doing in your example is calling the method via the class, and passing that first argument explicitly. The equivalent call here would be
Person.say_hi(p) # explicit self=p, also prints 'Hi my name is J.K.'
In your example you're using a non-static method then calling it through the class, then explicitly passing the first parameter. It happens to work but it doesn't make a lot of sense because you should be able to invoke a non-static method by saying
f = Foo()
f.bar() # numb = f, works, but numb isn't a number it's a Foo
If you want to put a function inside of a class that doesn't have a receiver, that's when you want to use #staticmethod (or, #classmethod more often)
class Person:
def __init__(self, name):
self.name = name
def say_hi(self):
print(f'Hi my name is {self.name}')
#staticmethod
def say_hello():
print('hello')
p = Person('J.K.')
Person.say_hello()
p.say_hello()

Calling a class function from the same file in Python

How do I call a function defined in a class in Python?
import pypyodbc as pyodbc
Master_Conn = 'Driver={SQL Server};Server=server\23;Database=DBname;UID=username;PWD=password;'
Master_db = pyodbc.connect(Master_Conn)
Master_Cursor = Master_db.cursor()
class Test:
def __init__(self):
self.master_status = ""
def Getmodel(self):
self.master_status= dict(Master_Cursor.execute("select col1,col2 from tablename ").fetchall())
print (self.master_status)
Test.Getmodel()
With above code, I get
TypeError: Getmodel() missing 1 required positional argument: 'self'
So I tried Test.Getmodel(self) and it resulted in
NameError: name 'self' is not defined.
I even tried both scenarios with if __name__== '__main__': but got same errors.
You are defining Getmodel as an instance method. So it have to be called on an instance of the class Test.
To create an instance of class Test you can write
instance_of_test = Test()
Now you can call Getmodel on instance_of_test
instance_of_test.Getmodel()
You can shorten this process by writing
Test().Getmodel()
Note that self is (usually) passed hiddenly when calling an instance method; it represents the instance calling the method.
Consider the following class Pizza
class Pizza:
def __init__(self, size):
self.size = size
def get_size(self):
return self.size
First you need to create an instance of Pizza
mypizza = Pizza(42)
then you can call the instance method get_size on mypizza
mypizza.get_size()
What your doing will work if you instantiate an object of the class Test first. Instantiation just means you call the class as if it were a method which. The following should work:
Test().Getmodel()
The () is what makes the instantiation happen so now the self essentially gets passed to the Getmodel() method because an object of the class Test now exists.

TypeError: generatecode() takes 0 positional arguments but 1 was given

I have the code below:
from tkinter import *
class Window(Frame):
def __init__(self, master = None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title("COD:WWII Codes")
self.pack(fill=BOTH, expand=1)
codeButton = Button(
self,
text="Generate Code",
command=self.generatecode
)
codeButton.place(x=0, y=0)
def generatecode(self):
f = open("C:/Programs/codes.txt", "r")
t.insert(1.0. f.red())
root = Tk()
root.geometry("400x300")
app = Window(root)
root.mainloop()
Then, I got the error below:
TypeError: generatecode() takes 0 positional arguments but 1 was given
So, how can I solve the error?
When you call a method on a class (such as generatecode() in this case), Python automatically passes self as the first argument to the function. So when you call self.my_func(), it's more like calling MyClass.my_func(self).
So when Python tells you "generatecode() takes 0 positional arguments but 1 was given", it's telling you that your method is set up to take no arguments, but the self argument is still being passed when the method is called, so in fact it is receiving one argument.
Adding self to your method definition should resolve the problem.
def generatecode(self):
pass # Do stuff here
Alternatively, you can make the method static, in which case Python will not pass self as the first argument:
#staticmethod
def generatecode():
pass # Do stuff here
I got the same error:
TypeError: test() takes 0 positional arguments but 1 was given
When defining an instance method without self and I called it as shown below:
class Person:
# ↓↓ Without "self"
def test():
print("Test")
obj = Person()
obj.test() # Here
So, I put self to the instance method and called it:
class Person:
# ↓↓ Put "self"
def test(self):
print("Test")
obj = Person()
obj.test() # Here
Then, the error was solved:
Test
In addition, even if defining an instance method with self, we cannot call it directly by class name as shown below:
class Person:
# Here
def test(self):
print("Test")
Person.test() # Cannot call it directly by class name
Then, the error below occurs:
TypeError: test() missing 1 required positional argument: 'self'
But, if defining an instance method without self, we can call it directly by class name as shown below:
class Person:
# ↓↓ Without "self"
def test():
print("Test")
Person.test() # Can call it directly by class name
Then, we can get the result below without any errors:
Test
In detail, I explain about instance method in my answer for What is an "instance method" in Python? and also explain about #staticmethod and #classmethod in my answer for #classmethod vs #staticmethod in Python.
The most upvoted answer does solve this issue,
And just in case anyone is doing this inside of a jupyternotebook. You must restart the kernel of the jupyternotebook in order for changes to update in the notebook

Method of an object in Python

I was just pulling off a toy example for myself, but it is not working and I cannot make it work. Does anybody know why this is not working and how to make it work:
class A(object):
#def __init__():
#pass
def do1():
print("foo")
def do2():
print("Hello")
Al = A
Al.do1()
TypeError: unbound method do1() must be called with A instance as first argument (got nothing instead)
In your code variable A1 it's reference to your class not instance, create instance of your class
Al = A()
and run your method
Al.do1()
You need to call your class to crate a correct instance and pass the self keyword to enclosing function to provides a handle back to the instance to be processed :
class A(object):
#def __init__():
#pass
def do1(self):
print("foo")
def do2():
print("Hello")
Al = A()
Al.do1()
Note that without passing the self to your function after calling it you will get a TypeError.
TypeError: do1() takes 0 positional arguments but 1 was given
Or as #Padraic Cunningham mentioned in comment you can use staticmethod as a decorator to wrap your function which makes python doesn't pass the first default argument (self) to it.
class A(object):
#def __init__():
#pass
#staticmethod
def do1():
print("foo")
def do2():
print("Hello")
Al = A()
Al.do1()

My classes think that "self" is an argument that needs a value assigned

I'm not sure why this is happening. It seems to think that "self" requires an argument, which doesn't make any sense.
Here's my code:
class Animal:
def __init__(self):
self.quality = 1
class Bear(Animal):
def __init__(self):
Animal.__init__(self)
def getImage(self):
return "bear.ppm"
class Fish(Animal):
def __init__(self):
Animal.__init__(self)
def getImage(self):
return "fish.ppm"
And the error I get is:
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
Bear.getImage()
TypeError: getImage() takes exactly 1 argument (0 given)
You have to instantiate Bear before you call getImage():
b = Bear()
b.getImage()
getImage is an instance method, so it is only designed to be called on a specific instance of the Bear class. The state of that instance is what is passed as the self variable to getImage. Calling b.getImage() is equivalent to this:
b = Bear()
Bear.getImage(b)
So, without an instance of Bear, there is nothing that can be used for the self argument, which is why you see that exception when you called Bear.getImage(). See the documentation on Python instance methods for more information.
If you want to be able to call getImage on the class Bear rather than on a specific instance, you need to make it a static method, using the #staticmethod decorator:
class Bear(Animal):
def __init__(self):
Animal.__init__(self)
#staticmethod
def getImage():
return "bear.ppm"
Then you could call Bear.getImage().
getImage() is an instance method, so it can only be called with a instantiation of Bear class. So here is how you can do it:
Bear().getImage()
or
be = Bear()
be.getImage()

Categories