I am trying to understand python inheritance a little. Here is a use case:
class Test:
def hello():
print("hello")
return "hello"
def hi():
print(hello())
print("HI")
class Test1(Test):
hi()
pass
x = Test1()
x.hello()
I don't understand why I can't call "hi()" in class Test1. It inherited it class Test right?
I think you are misunderstanding the relationship and definitions of classes and objects. Classes are like blueprints to create objects. By writing methods inside a class, you are essentially defining the behaviors of the object that can be created from the class blueprint. So, with your code:
class Test:
def hello():
print("Hello")
return "Hello"
def hi():
print(hello())
print("Hi")
class Test1(Test):
hi() # <- You really shouldn't call a method directly from a "blueprint" class
pass
x = Test1()
x.hello()
While your last two lines of code are valid, it's a bad idea (and almost always invalid) to call a method outside of the class's scope directly inside a class definition. The reason why hi() does not work in the Test1 class is that it's not defined in the scope of Test1; even though this class indeed inherits from the Test class, it only affects the object that is created from the class (like the object x you created from the Test1() class).
Here's a more detailed explanation about classes and objects from another relevant question: What are classes, references and objects?
Hope this helped!
Related
I am trying to implement python classes and objects in my application code. Currently, I have a file that includes all the frequently used functions. I import them in another file.
funcs.py
class name1():
def func1(x):
return x
def func2(y):
return y
....
file1.py
from funcs import func1
from funcs import func2
I'd like to organize the code in class, method and attributes and then invoke them in different files.
How do I call a method within a class from another file? What changes do I need to make in funcs.py file?
If you want to call a method within a class, first you have to instantiate an object of that class, and then call the method in reference to the object. Below is not an ideal implementation but it's just for example.
example.py
class MyClass:
def my_method(self):
print('something')
object1 = MyClass()
object1.my_method()
Then when you want to call the method in another file you have to first import them.
another.py
from .example import MyClass
object2 = MyClass()
object2.my_method()
If you just want to call the method without having to create an object first you can use #staticmethod.
class MyClass:
#staticmethod
def my_method(self):
print('something')
MyClass.my_method()
Yet as I said this is not the ideal implementation. As #juanpa.arrivillaga said ideally you cannot just throw in any method and bundle them into a single class. The content of a class is all related to the object you want to define as a class.
I used to program in scheme:
in scheme (a functional style), functions are values.
you can attach a function to a "struct"-
the scheme equivalent of a class in python-
can you do something similar
with python classes?
or, to put it differently, can you pass a function to a constructor?
The answer is yes: functions are first-class values in Python, and you can attach these dynamically to classes or class instances to make methods. In the case of classes this is trivial, but in the case of instances this requires a bit of setup.
To illustrate the difference, consider the following code:
class Hello:
def say_hello(self):
print("Hello")
print(type(Hello.say_hello)) # <class 'function'>
print(type(Hello().say_hello)) # <class 'method'>
You can see that for the same method, when it is referenced from the class it is a function type, and when it is referenced from the instance it is a method type. (Also, functions and methods are themselves classes; it's turtles all the way down.)
To dynamically add methods to classes, it it suffices to use regular functions. For example:
def say_hello(self):
print(f"Hello, {self.name}!")
class Greeter:
def __init__(self, name):
self.name = name
Greeter.greet = say_hello
Greeter("Sir Robin").greet() # Prints "Hello, Sir Robin!"
However, methods on instances are bound to the instance; this means that when you call instance.method(), Python supplies the self argument to the method automatically. For normal classes Python handles the binding itself, but this does not happen when you add methods dynamically. For example, this code will result in an error:
def say_hello(self):
print(f"Hello, {self.name}!")
class Greeter:
def __init__(self, name):
self.name = name
greeter = Greeter("Sir Robin")
greeter.greet = say_hello
greeter.greet() # TypeError: say_hello() missing 1 required positional argument: 'self'
Instead you have to bind the method yourself. This can be done using MethodType from the types library.
import types
def say_hello(self):
print(f"Hello, {self.name}!")
class Greeter:
def __init__(self, name):
self.name = name
greeter = Greeter("Sir Robin")
greeter.greet = types.MethodType(say_hello, greeter)
greeter.greet() # Prints "Hello, Sir Robin!"
Caveat: In 99% of cases you will be better off just using regular functions or classes, as dynamically assigning methods is not usually done in Python and will likely confuse other developers. If you really need dynamic lookup, it is much more common to use magic methods like __getattr__ than dynamic method binding. Use this technique at your own risk!
class MyClass:
def my_method(self):
print("Hello world!")
or
By using my_object.my_method = my_function or MyClass.my_method = my_function you can add it dynamically. But this is discouraged, since it makes the code harder to understand.
Edit: To get a bound method, which receives the self arg, you need to add it to the class. This is then also reflected on existing instances. If you add the method to an instance directly, it won't receive self when called.
Suppose I have the following code:
class Classy:
def other(self):
print("other")
def method(self):
print("method")
self.other()
obj = Classy()
obj.method()
The output:
method
other
So I invoke another object/class method from inside the class. I invoke the other method within the 'method' method.
Now if I run the following code:
class Classy:
def other(self):
print("other")
def method(self):
print("method")
Classy.other(self)
obj = Classy()
obj.method()
The output is the same. Now my question is: What is the difference between these two?
I am not sure if it is just a different style of calling - so it is basically the same - or if there is a difference in the logic. If yes, I would be interested in an example where the difference matters.
Let's set it up so we can run them side by side:
class Classy:
def other(self):
print("Classy.other")
def method(self):
print("Classy.method")
self.other()
class NotClassy:
def other(self):
print("NotClassy.other")
def method(self):
print("NotClassy.method")
NotClassy.other(self)
So far, so good:
>>> Classy().method()
Classy.method
Classy.other
>>> NotClassy().method()
NotClassy.method
NotClassy.other
But what if inheritance gets involved, as it so often does in oop? Let's define two subclasses that inherit method but override other:
class ClassyToo(Classy):
def other(self):
print("ClassyToo.other")
class NotClassyToo(NotClassy):
def other(self):
print("NotClassyToo.other")
Then things get a bit problematic; although the subclasses have almost identical implementation, and the parent classes seemed to behave exactly the same, the outputs here are different:
>>> ClassyToo().method()
Classy.method
ClassyToo.other
>>> NotClassyToo().method()
NotClassy.method
NotClassy.other # what about NotClassyToo.other??
By calling NotClassy.other directly, rather than invoking the method on self, we've bypassed the overridden implementation in NotClassyToo. self might not always be an instance of the class the method is defined in, which is also why you see super getting used - your classes should cooperate in inheritance to ensure the right behaviour.
I have a scenario whereby I'd like to have a base class A (defined in a.py) with all of the generic logic accompanied by a single method foo() to be implemented by derived classes. That is, a.py would have
class A(object):
def __init__(self):
print "A()"
def foo(self):
print "A.foo()"
and file b.py,
from a import A
class B(A):
def __init__(self):
super(B,self).__init__();
print "B()"
def foo(self):
print "B.foo()"
Now I can add
if __name__ == "__main__":
B().foo()
to b.py and run via python b.py, but I'd like to see if there's a way to avoid doing this in all the subclass modules. This way all I have to do is instruct the subclass developers to provide a sensible foo() (along with any extra setup in the overridden __init__()), without having to add the if __name__ == "__main__" bit as I want that bit to always call the foo() method on the object of the class being provided by the module.
My hunch is that this cannot be done in Python since it amounts to instantiating the subclass objects from within a.py, but I'd like to see if others can provide a concrete answer for me, or even better a way around.
Can someone explain why I'm getting the error:
global name 'helloWorld' is not defined
when executing the following:
class A:
def helloWorld():
print 'hello world'
class B(A):
def displayHelloWorld(self):
helloWorld()
class Main:
def main:
b = B()
b.displayHelloWorld()
I'm used to java where class B would obviously have a copy of class A's method "helloWorld" and thus this code would run fine when executing main. This however appears to think class B doesn't have any method called "helloWorld"
Missing the self before the helloWorld(). The self keyword means that this an instance function or variable. When class B inherits class A, all the functions in class A can now be accessed with the self.classAfunction() as if they were implemented in class B.
class A():
def helloWorld(self): # <= missing a self here too
print 'hello world'
class B(A):
def displayHelloWorld(self):
self.helloWorld()
class Main():
def main(self):
b = B()
b.displayHelloWorld()
You need to indicate that the method is from that class (self.):
class B(A):
def displayHelloWorld(self):
self.helloWorld()
Python differs in this from Java. You have to specify this explicitly in Python whereas Java accepts implicitly as well.
I don't know what is the version of python used in this example but it seems that syntax looks like python3. (except print statement which looks like python2.x)
Lets suppose that this is python3
I would say that helloWorld is class method of class A and It should be called as class attribute. As soon as this function is in class namespace It can be accessed outside this class only using owner class.
A.helloWorld()
or
B.helloWorld()
or
self.__class__.helloWorld()
You can't call it as bound method in this case because self argument will be passed and as soon as your function doesn't expect it it will fail.
there is possibility that helloWorld is method of A and self parameter is just missed
in this case this method can be called as follow:
self.helloWorld()
or
A.helloWorld(self)