How to implement a sole class of methods inside an external class - python

I have an external class to represent my data idk. Inside the class idk I want to have another class change which will contain various methods to change instances of the class idk. What I've tried is below. Note: this is a simplified example of my actual code
class idk:
def __init__(self):
self.x=1
self.y=2
class change:
def func(self):
self.x=10
self.y=100
var=idk()
var.change.func()
print(var.x, var.y)
However this gives the error:
TypeError: func() missing 1 required positional argument 'self'
How do I change the code to make it work?

Well, first of all, your are getting this error because you are accessing the func function as a class attribute and not by an instance of it (putting a class definition inside another class won't make it an instance).
If it makes sense, you cloud put those "change methods" in the idk class directly (that would be a normal approach):
class idk:
def __init__(self):
self.x = 1
self.y = 2
def func(self):
self.x = 10
self.y = 100
var = idk()
var.func()
print(var.x, var.y) # Output: 10 100
If you really want/need to separate those methods, you could do another class. The way I would implement that class is with static methods where all of them recieve an idk instance as the first parameter:
class idk:
def __init__(self):
self.x = 1
self.y = 2
class idkChanger:
#staticmethod
def func(idk_obj):
idk_obj.x = 10
idk_obj.y = 100
var = idk()
idkChanger.func(var)
print(var.x, var.y) # Output: 10 100
If you really really want/need to have that "changer" class inside of the idk class you can define it there, but this is not common at all. Also, you will have to pass the instance as well, that Changer class:
class idk:
def __init__(self):
self.x = 1
self.y = 2
class Changer:
#staticmethod
def func(idk_obj):
idk_obj.x = 10
idk_obj.y = 100
var = idk()
idk.Changer.func(var)
print(var.x, var.y) # Output: 10 100
Final notes:
You could not mark (decorate) the func as static and it will work the same, but this will bring more confution for several reasons (e.g., you would tecnically saying that func is an instance method. Which is not, because the objects you want to change are not Change's instances but idk's).

Related

Circular attributes in Python

I am working with several classes, with each having it's own attributes.
Trying to avoid to pass a lot of variables when calling sub_functions, I would rather call classe's attributes.
As an example, let's concider 2 classes such as :
class Class_A(object):
def __init__(self, element_b):
self.value_specific_to_a = 1
self.element_b = element_b
def element_a_can_do(self):
print(self.element_b.value_specific_to_b)
class Class_B(object):
def __init__(self):
self.element_a = None
self.value_specific_to_b = 2
def add_a(self, element_a):
self.element_a = element_a
def element_b_can_do(self):
print(self.element_a.value_specific_to_a)
item_b = Class_B()
item_a = Class_A(item_b)
item_b.add_a(item_a)
I think that it is pointer's addresses of those classes that are save to each other, but I wonder if it can cause any issue/leak in my code.

pass arguments inside splitted methods

I need to split class methods in several files. Functionality need to by that I can pass inside method all variables defined in self and receive new self variables defined inside the method.
My attempt:
Below code works, but I don't know if this is the best/proper solution.
Base:
from calculate_function import function
class Data():
def __init__(self):
self.y = -2
self.x = 1
self.z, self.result = function(self)
calculate_function.py:
def function(self):
z = 2
result = z + self.x
return z, result
For above I pass self inside new function for collect all init variables, then define new self variable/results.
There will by much more functions inside different files that will done some calculations and create new variables for instance of class.
Question
What I need is to pass each created self variable to each function.
For above code the solution is proper defined or there is better option to this?
If you want to externalize some part of your class code to external functions, it's better to write those as pure functions and keep the attribute access (and even more attributes updates) within the class code itself - this makes the code much easier to test, read and maintain. In you case this would looks like:
from calculate_function import function
class Data():
def __init__(self):
self.y = -2
self.x = 1
self.z, self.result = function(self.x)
calculate_function.py:
def function(x):
z = 2
result = z + x
return z, result
The points here are that 1/ you can immediatly spot the creation of attributes z and result and 2/ you can test function() without a Data instance.
I need to split class methods in several files.
This often means your class has too many responsabilities. Some parts of it can be delegated to pure functions like shown above. Some other parts, that need access to a common subset of your class attributes, can be delegated to other, smaller, specialized classes - but preferably using composition / delegation instead of inheritance (depending on concrete use cases of course).
You dont need pass self inside the function
Why not do it like this:
class Data():
def __init__(self):
self.y = -2
self.x = 1
self.function()
def function(self):
self.z = 2
self.result = self.z + self.x
Do wish to use another Class function or just a stand alone function?
Here is solution, using class inheritance:
-- function1.py --
class FunctionClass1():
def function1(self):
self.result = self.x + self.y
-- function2.py --
class FunctionClass2():
def function2(self):
self.result = self.result + self.z
-- data.py --
from function1 import FunctionClass1
from function2 import FunctionClass2
class Data(FunctionClass1, FunctionClass2):
def __init__(self):
self.x = 1
self.y = 2
self.z = 3
self.function1()
self.function2()

Calling class-specific method from another class

I am working in a class called AlgoSystem, which is given strategy_0 and strategy_1 as inputs under initialization as well as the number of strategies (2 in this case). The strategy classes are stored in a dictionary called "strategies" within the AlgoSystem. Both strategy_0 and strategy_1 are different classes themselves, but both with a function called "__on_tick". These functions I want to call from within the AlgoSystem class.
My current attempt to do this is seen below:
class AlgoSystem:
def __init__(self, strategy_0, strategy_1, numstrategies):
self.var= 1
self.strategies = {0 : strategy_0,
1 : strategy_1}
self.num_strategies = numstrategies
def start(self):
for i in range(self.num_strategies):
self.strategies[i].__on_tick(self.var)
class Strategy_zero:
def __init__(self, x):
self.x = x
def __on_tick(self, var):
self.x = self.x + var
print(self.x)
class Strategy_one:
def __init__(self, y):
self.y = y
def __on_tick(self, var):
self.y = self.y - var
print(self.y)
strategy_0 = Strategy_zero(2)
strategy_1 = Strategy_one(4)
num_strategies = 2
system = AlgoSystem(strategy_0, strategy_1, 2)
system.start()
When I run the code above, I am given the error:
Strategy_zero' object has no attribute '_AlgoSystem__on_tick'
Apparently I'm not calling the class-functions "__on_tick" properly. How should I do this? I need to do it in a way, so I keep track on the changes of the two sub-classes (strategy_0 and strategy_1) through my defined dictionary within AlgoSystem: "strategies".
The double underscore prefix is specifically designed to prevent you from doing exactly what you are doing.
There is no reason for you to use it here. Remove the prefix and can your methods just on_tick.
Double underscore names are hidden names (hidden by obfuscation). I suggest having your on_tick method be called on_tick and try again.
The following code might help clarify what's going on with name-mangling.
class A:
def __mangled(self):
print "Class A name-mangled method"
class B:
def __init__(self):
a = A()
try:
a.__mangled()
except AttributeError:
# an attempt to access a name-mangled method assumes that
# the '_{class_name}' prefix should use 'B' as the class name
print "A instance has no attribute '_B__mangled'"
a._A__mangled()
# prints "Class A name-mangled method"
getattr(a, '_{}__mangled'.format(a.__class__.__name__))()
# same thing, but can be done without knowing the class name
B()
So, you could update self.strategies[i].__on_tick(self.var) to be:
strat = self.strategies[i]
getattr(strat, '_{}__on_tick'.format(strat.__class__.__name__)(self.var)
But, it would probably be best to not precede __on_tick with a double-underscore since it is intended to be accessed outside the class/instance.

How to refer to a child class from a parent method?

In the following sample, is there a magic word I can put in place of <ChildClass> that works like the opposite of super?
class Parent(object):
def __init__(self):
print <ChildClass>.x
class someChild(Parent):
x = 10
It is a stupid example, but it shows my intention. By the way, using someChild will not work, because there are many child classes.
The only solution I can think of is to have a constructor in every child class that calls the constructor of Parent with a reference to itself (or even to pass x), but I would like to avoid having a constructor at all in each child.
What is wrong with just using self.x?
class Parent(object):
x = None # default value
def __init__(self):
print self.x
class someChild(Parent):
x = 10
def __init__(self):
Parent.__init__(self)
class otherChild(Parent):
x = 20
def __init__(self):
Parent.__init__(self)
a = someChild()
# output: 10
b = otherChild()
# output: 20
Note how this works even if Parent has a class attribute x as well (None in the above example)- the child's takes precedence.
self.x will work if the instance doesn't have an x attribute.
type(self).x if the instance has an x attribute and you want the class's value, essentially skipping over the instance.

How can I get parent class' self?

class Test1:
def __init__(self):
self.x = 1
class Test2(Test1):
# how can I get parent class's self.x ??
# exactly here not def __init__(self) or other methods in Test2..
Please... I spent hours figuring out how to get parent class' self! and failed..
I need a python expert!
Do you want something like this?
class Test1:
def __init__(self):
self.x = 1
class Test2(Test1):
def __init__(self):
Test1.__init__(self)
print self.x
a = Test2()
You can access self.x inside Test2, because the Test2 object has the x attribute. It is created in Test1 initializer.
Edit: After the author explaining my misunderstanding, it is not possible to do what is asked, because x is an instance member, and not a class one. See gecco's answer.
This is not possible. self.x is an instance variable. Instance variables can only be accessed from within instance-methods. Outside methods you are in a static context.
You can do this (pure class-variables (not instance)):
class Test1:
x = 1
class Test2:
y = Test1.x
At the point of class-definition there is no object, so there is no self - self only has a meaning inside member-functions. What do you want with self.x in the class-definition anyway?

Categories

Resources