Multiple classes in Python - python-3.x

I am learning OOPS in Python. I encountered this piece of code during my course.
class Point(object):
def __init__(self,x,y):
self.x=x
self.y=y
class Line(object):
def __init__(self,p1,p2):
self.p1=p1
self.p2=p2
def slope(self):
return (self.p2.y - self.p1.y)/ (self.p2.x-self.p1.x) 
Let's say for Point class I have two instances P1(11,6) and P2(12,3). For class Line, I have one object L1(7,2). What does it mean that self.p2.y? What value would be accessed here?
I have looked at many places but couldn't find this concept?

self refers to the object of that class. the variables after the . operator are attributes
you can use something other than self, but its good practice to use self.
so for P1, self refers to the P1 object.
theres also a version of self for classes (cls) but thats for class methods

Related

Is a python `abstract property` that returns an abstract class an example of the Factory Pattern

I need to document my design, in particular, the design patterns used, and would like to use the standard terminology.
From Refactoring Guru, "Factory Method defines a method, which should be used for creating objects instead of direct constructor call. Subclasses can override this method to change the class of objects that will be created".
I have a CraneInterface class with an abstract method, and the signature of this method enforces that its return type is an implementation of an AxisInterface. Essentially, subclasses of CraneInterface "override this method to change the class of objects that will be created". The only diference with my version is that it does not necessarily "create" a new instance, it could also return one that already exists. Is this still the Factory Pattern? And if not, does this design pattern have a common name?
i.e: A traditional factory looks like this:
class IAnimal(ABC):
#abstractmethod
def speak(self):
pass
class Dog(IAnimal):
#overide
def speak(self):
print('Woof')
class Cat(IAnimal):
#overide
def speak(self):
print('Meow')
class AnimalFactory(ABC):
#abstractmethod
def make_animal(self) -> IAnimal:
pass
class CatFactory(AnimalFactory):
#overide
def make_animal(self) -> IAnimal:
return Cat()
class DogFactory(AnimalFactory):
#overide
def make_animal(self) -> IAnimal:
return Dog()
My code looks more like this:
class AnimalFactory2(ABC):
#property
#abstractmethod
def animal(self) -> IAnimal:
pass
class CatFactory2(AnimalFactory2):
def __init__(self):
self.__cat = Cat()
#overide
#property
def animal(self) -> IAnimal:
return self.__cat
class DogFactory2(AnimalFactory2):
def __init__(self):
self.__dog = Dog()
#overide
#property
def animal(self) -> IAnimal:
return self.__dog
Does the second example use the Factory Pattern? Does it have a different name or even have a name at all? The main difference is that it does not create a new instance each time it is called.
Extra info:
In my actual code, I have a 3 axis CraneInterface class that has abstract methods for all the ways you can interact with a crane. It is implemented by a CraneSimulator and a CraneOpcuaClient that actually talks to a real crane. The original design of the simulator implemented the abstract method inside the CraneSimulator class, however, this had lots of duplicated code, as every function of the crane was repeated for each of the 3 axes. To solve this, I created an AxisSimulation class which had methods to interact with it, and then there are 3 instantiations inside the CraneSimulator, and the implementations of the CraneInterface abstract methods simply forward the request to one of the 3 axis objects.
The problem was that the CraneInterface also needed the ability to notify "observers" whenever the state of the crane changed, for example, a position or temperature change. I.e the CraneInterface needed to have a function add_on_x_position_changed_callback(self, callback: Callable[[Position],None]). To do this, the CraneInterface had properties with custom setters that notified a list of observers whenever the value was set. By putting the AxisSimulation inside the CraneSimulator the properties had moved out of the CraneInterface, and the add_on_changed_callback methods of the CraneInterface would no longer work.
So to solve this, the CraneInterface had an abstract property to return an abstract AxisInterface class (like the AnimalFactory2 example). The AxisInterface then had the observable properties with a custom setter (and methods to add observers), so that users of the CraneInterface can add observers to the data.
I know that the "observable" part is an example of the Observer pattern, but is the deferring of the type of Axis implementation returned, an example of the Factory Pattern?
Thanks.

Overwriting parent function in multiple children

I have a couple of child classes that I want to use but they both inherit a method from their parent that doesn't quite behave the way I need it to.
class ParentClass():
def __init__(self, value):
self.value = value
def annoying_funct(self):
print("I don't do quite what's needed and print {0}".format(self.value + 1))
def other_parent(self):
print("I do other useful things my children inherit")
class Child1(ParentClass):
def __init__(self, value, new_value1):
super(Child1, self).__init__(value)
self.new_value1 = new_value1
def other_child1(self):
print("I do useful child things")
class Child2(ParentClass):
def __init__(self, value, new_value2):
super(Child2, self).__init__(value)
self.new_value2 = new_value2
def other_child2(self):
print("I do other useful child things")
I want to overwrite annoying_funct() as something like this:
def annoying_funct():
print("I behave the way I am needed to and print {0}".format(self.value))
ParentClass, Child1 and Child2 are from a very complex library (scikit-learn), so I want to keep all of my wrappers as thin as possible. What would be the cleanest/most pythonic way of getting the functionality of my two child classes while altering the parent class as needed?
My thoughts so far:
Create a new class that inherits from the parent which overwrites the function I don't like and then make wrapper classes for the children that inherit from the new class and the child classes.
class NewParentClass(ParentClass):
def annoying_funct(self):
print("I behave the way I am needed to and print {0}".format(self.value))
class NewChild1(NewParentClass, Child1):
pass
class NewChild2(NewParentClass, Child2):
pass
My areas of confusion:
Is this the correct approach? It seems a little weird and klugy. Is there a cleaner way of doing this?
Is the syntax used for the two child classes correct? It runs for me, but it seems a little weird having them do nothing but inherit and pass.
Is having my new parent inherit from the previous parent the correct way of doing this? The code runs for the children without the inheritance between parentClass and newParentClass (eg. def newParentClass():), but if someone tried to make an instance of newParentClass() the function wouldn't work because it uses attributes not present in that class (value). Is that ok if I assume the class will never be used?
There are a couple of ways to do what you ask.
Create a new class inheriting from the parent class, then use it as new parent class.
The only drawback for this solution is that the when you provide the new parent or child class to functions requiring the original Parent class might not work since they might use annoying_funct and rely on an annoying behavior.
class NewParentClass:
def annoying_funct(self):
print("I behave the way I am needed to and print {0}".format(self.value))
class NewChild1(NewParentClass):
pass
class NewChild2(NewParentClass):
pass
Manipulate the existing Parent class
This is the solution I would like to use since it destroys the annoying_funct completely by replacing it with a well behaving one, buy again, other methods and functions requiring the former annoying_funct might fail. The good side is, you don't need to create another parent class and children, so your code will be much more elegant.
class ParentClass():
...
def annoying_funct(self):
print("I don't do quite what's needed and print {0}".format(self.value + 1))
...
def well_behaving_func(s):
print("Good")
# Dynamically change the class method
ParentClass.annoying_func = well_behaving_func
class Child1(Parent):
pass
class Child2(Parent):
pass
c = Child1()
c.annoying_funct() # prints 'Good'
Add a well behaving new method to parent class before inheriting from it.
If you want to maintain the current behavior and don't want your existing code or packages dependent on the parent class break, you certainly should not overwrite the annoying_funct in the parent class. So you should define a well behaving function and use it in child classes.
class ParentClass():
...
def annoying_funct(self):
print("I don't do quite what's needed and print {0}".format(self.value + 1))
...
def well_behaving_func(s):
print("Good")
# Dynamically change the class method
ParentClass.well_behaving_func = well_behaving_func
class Child1(Parent):
pass
class Child2(Parent):
pass
c = Child1()
# use 'well_behaving_func', not the annoying one
c.well_behaving_func() # prints 'Good'
What I ended up doing was using the concept of a mixin to add my new functionality to the child classes. The resulting code was as follows:
class AnnoyMixin:
def well_behaving_func(self):
print("I behave the way I am needed to and print {0}".format(self.value))
class NewChild1(AnnoyMixin, Child1):
def annoying_funct(self):
return well_behaving_func(self)
class NewChild2(AnnoyMixin, Child2):
def annoying_funct(self):
return well_behaving_func(self)
Functionally, this mostly behaves the same as the code I had proposed in my question, but the modifications help with readability. First, by naming the new parent as a "Mixin" it makes it clear that this class is not designed to stand on its own, but rather is intended to add functionality to another class. Because of this, AnnoyMixin doesn't need to inherit from ParentClass, simplifying inheritance for the NewChild classes.
Second, rather than overwriting annoying_funct in AnnoyMixin, we create the new function well_behaving_func. It is then the NewChild classes job to overwrite annoying_funct by calling well_behaving_func. Functionally, this works more or less the same as if the AnnoyMixin had over written annoying_funct, but this way, it is clearer to those reading the code that annoying_funct is being overwritten in the NewChild classes.

How can an outer class access data from its inner class?

I am trying to better understand how to use sub-classes using a very simple test-case based off of this question/answer.
class Outer():
def __init__(self, x):
self.x = super(Inner, self).__init__
# self.x = Inner(**kwargs)
def add_two(self):
""" """
return self.x + 2
class Inner():
def __init__(self, x=2):
self.x = x
res = Outer(x=3).add_two()
# res = Outer({'x' : 3}).add_two()
print(res)
>> NameError: name 'Inner' is not defined
If I run the same code but make Inner() its own separate class (as opposed to a sub-class of Outer(), I receive the following error.
TypeError: super(type, obj): obj must be an instance or subtype of type
What is the cause of this error and how do I fix this?
Nesting classes in Python (or other languages) seldom make sense. In this case, it is not useful for anything at all.
If on the "Outer" class you want to have an associated instance of "Inner", that should be created as an instance attribute, on the __init__ method for Outer - like this:
class Outer():
def __init__(self, x):
self.x = Inner(x)
# self.x = Inner(**kwargs)
def add_two(self):
""" """
return self.x + 2
class Inner():
def __init__(self, x=2):
self.x = x
Now, taking a step by step look on your original code, and trying to understand better why it does not work:
In Python everything declared in the body of a class becomes an attribute of that class - a single copy of it will be (ordinarily) shared by all instances of that class. Declaring a whole class nested is syntactically legal but gains you nothing: the inner class is not "hidden" from the outside world by the language in any sense: not by the language, neither by the conventions usually followed by Python developers.
If you want users (i.e. other programmers, or yourself in code that makes use of this file), to create instances of "Outer" and refrain from creating instances of "Inner", simply prefix its name with an _. That is a convention in Python code, and developers usually will know that they should not trust any class, function, or other name that starts with a single _ to be safe for use in 3rd party code - that is the closest Python gets to "private" or "protected" members.
Now, getting to the line:
...
self.x = super(Inner, self).__init__
It again makes no sense. super or explicitly referencing a superclass are meant to call superclasses - that is, classes from which you inherit. You created no inheritance relationship in your code, rather one of composition. That is why you get that error message - if you are using the explicit version of super, the object you pass have to be a subclass of the class you are calling super on. And it is not the case here. (Also, doing it in this form, it does not call the method - just references it - all function or method calls are comitted by the use of ())
You can also make Outer inherit from Inner - in this case, Outer will "be" an Inner, no need to keep a reference to it in an attribute - self will mean both an Outer and an Inner class.
In this case, we need a reference to "Inner" when parsing the declaration of "Outer", so it needs to be defined first:
class _Inner():
def __init__(self, x=2):
self.x = x
class Outer(_Inner):
def __init__(self, x):
super().__init__(x)
def add_two(self):
""" """
return self.x + 2
Note the use of parameterless super - one of the major changes for Python 3. If you need to write code still compatible with Python 2, the parameters to super can be explicit, and the call would be super(Outer, self).__init__().
(Again, calling it _Inner will mean that users of your class should not inherit or instantiate from _Inner and should use Outer - and that is a convention in coding style rather than language syntax)

How may I turn a variable assignment into a methodcall in Python 3?

Let's say I have the following classes:
class Constants():
def __init__(self, constant=None):
self.value = constant
# Some magic goes here
class SomeConstants(Constants):
PROJECT_NAME = 'constants'
How can I make that definition turn programatically into
class SomeConstants(Constants):
#staticmethod
def PROJECT_NAME():
return SomeConstants('constants')
so that whenever I call SomeConstants.PROJECT_NAME, SomeConstants.PROJECT_NAME(), SomeConstants().PROJECT_NAME, or SomeConstants().PROJECT_NAME() I get the same result, namely an instance of ProjectConstants, having 'constants' as its value?
Edit
After John Kugelman's comment, I realize that calling SomeConstants.PROJECT_NAME, and getting an instance of ProjectConstants, having 'constants' as its value would be what I am looking for.
The magic method call() may be what you are looking for here.
The Enum class in Python does what I want.
Using enums, require some slight alterations, but for my intent and purposes, it solves the problem.

Having trouble returning through multiple classes in Python

I'm still learning and like to build things that I will eventually be doing on a regular basis in the future, to give me a better understanding on how x does this or y does that.
I haven't learned much about how classes work entirely yet, but I set up a call that will go through multiple classes.
getattr(monster, monster_class.str().lower())(1)
Which calls this:
class monster:
def vampire(x):
monster_loot = {'Gold':75, 'Sword':50.3, 'Good Sword':40.5, 'Blood':100.0, 'Ore':.05}
if x == 1:
loot_table.all_loot(monster_loot)
Which in turn calls this...
class loot_table:
def all_loot(monster_loot):
loot = ['Gold', 'Sword', 'Good Sword', 'Ore']
loot_dropped = {}
for i in monster_loot:
if i in loot:
loot_dropped[i] = monster_loot[i]
drop_chance.chance(loot_dropped)
And then, finally, gets to the last class.
class drop_chance:
def chance(loot_list):
loot_gained = []
for i in loot_list:
x = random.uniform(0.0,100.0)
if loot_list[i] >= x:
loot_gained.append(i)
return loot_gained
And it all works, except it's not returning loot_gained. I'm assuming it's just being returned to the loot_table class and I have no idea how to bypass it all the way back down to the first line posted. Could I get some insight?
Keep using return.
def foo():
return bar()
def bar():
return baz()
def baz():
return 42
print foo()
I haven't learned much about how classes work entirely yet...
Rather informally, a class definition is a description of the object of that class (a.k.a. instance of the class) that is to be created in future. The class definition contains the code (definitions of the methods). The object (the class instance) basically contains the data. The method is a kind of function that can take arguments and that is capable to manipulate the object's data.
This way, classes should represent the behaviour of the real-world objects, the class instances simulate existence of the real-world objects. The methods represent actions that the object apply on themselves.
From that point of view, a class identifier should be a noun that describes category of objects of the class. A class instance identifier should also be a noun that names the object. A method identifier is usually a verb that describes the action.
In your case, at least the class drop_chance: is suspicious at least because of naming it this way.
If you want to print something reasonable about the object--say using the print(monster)--then define the __str__() method of the class -- see the doc.

Resources