I have a class a defined like this:
class a:
def __init__(self, w, x, y, z):
self.w = w
self.x = x
self.y = y
self.__z = z
I also have another class b which inherits a defined like this:
class b(a):
def __init__(self, w, x, y, z, t):
super().__init__(w, x, y, z)
self.__t = t
Now if I had access w, x, y from within b, I could simply do:
self.w
self.x
self.y
But I can't do self.z or self.__z to access z. So my question is how can you access dunder values such as z from within class b
(I know python doesn't really have private variables and I could do self._a__z from within class b to access z but I'm looking for methods which would allow me to just do something like self.z to access z from inside b)
There are a variety of ways you could solve the problem by changing the API of class a to expose it's __z attribute in some more inheritance-friendly way. For instance, you could make the actual mangled attribute name an implementation detail and have the public API be a property:
class a:
def __init__(self, w, x, y, z):
self.w = w
self.x = x
self.y = y
self.__z = z
#property
def z(self):
return self.__z
#z.setter
def z(self, value):
self.__z = value
But unless you're doing some validation or modification of the value somewhere in the property's code, you probably should just do away with the double-underscores and let the child class access self.z like it can w, x and y. The simplest solution is to replace self.__z = z with self.z = z. You can always change it later to use a property if you find you do need validation or something.
If you just want to hint that z is not part of the wider public API, but only for subclasses and other code that knows about the intimate details of a's design, consider using a single underscore: self._z = z. This has no special effects in the interpreter, but the single-underscore serves as a sort of documentation that _z is an internal attribute and you should only mess with it if you know what you're doing.
You could do something like this if you want to keep your code clean:
class a:
def __init__(self, w, x, y, z):
self.w = w
self.x = x
self.y = y
self.__z = z
def get_field(self):
return self.__z
class b(a):
def __init__(self, w, x, y, z, t):
super().__init__(w, x, y, z)
self.__t = t
def ChildMethodWhichUsingParentField(self):
return self.get_field()
c = b(1,2,3,4,5)
print(c.ChildMethodWhichUsingParentField())
Output
4
Similarly, you can use a setter to change its value:
class a:
def __init__(self, w, x, y, z):
self.w = w
self.x = x
self.y = y
self.__z = z
def get_field(self):
return self.__z
def set_field(self,z):
self.__z = z
class b(a):
def __init__(self, w, x, y, z, t):
super().__init__(w, x, y, z)
self.__t = t
def ChildMethodWhichUsingParentField(self):
return self.get_field()
def ChildMethodWhichSettingParentField(self,z):
self.set_field(z)
c = b(1,2,3,4,5)
print(c.ChildMethodWhichUsingParentField())
c.ChildMethodWhichSettingParentField(10)
print(c.ChildMethodWhichUsingParentField())
Output
4
10
Related
class parent:
#abstractmethod
def process(self, x, y, z):
pass
def post_process(self):
self.process(x, y, z)
class child1(parent):
def process(self, x, y, z):
# do stuff with x and y, and ignore z
class child1(parent):
def process(self, x, y, z):
# do stuff with x, y, z
This is an existing design in the codebase I am working in. I don't like it for readability because the variable z isn't used for all child classes, and I suspect it was designed this way so that post_process doesn't need to check which child class is calling.
I am thinking of changing it to:
class parent:
def post_process(self):
if isinstance(self, child1):
self.process(x, y)
elif isinstance(self, child2):
self.process(x, y, z)
class child1(parent):
def process(self, x, y):
# do stuff with x and y
class child1(parent):
def process(self, x, y, z):
# do stuff with x, y, z
This does the case work of checking which child class is calling post_process, but I feel it is better for readability and avoids having to pass in unnecessary arguments.
Are there other ways besides this to resolve this issue?
I'm stuck on a problem in Python... (i'm an absolute beginner but i need to do a little
environmental science model..)
so the problem is I have:
class C:
def __init__(self, x, y, z):
self.x = x
self.y = self.x * 8
self.z = self.y * 9 + 0.5
self.w = self.z +2
one = C(5,8,12)
two = C(2,12,12)
three = C(1,2,3)
So... i want to change the self.z but only for the object three
(i want it to be self.z = 12 * self.x );
I have to call it in self.w so i can't modify it after my istances...
do you have any suggestion to a beginner?
Thank you so much and have a nice day!
A few notes. First you are not actually using the arguments of y or z that are passed in __init__(self, x, y, z).
To allow on the fly overloading, you may want to break out the individual assignments into their own methods so it is easier to change the behavior you want.
Below you can pass in a custom function that will be applied to the x value when calculating z.
class C:
def __init__(self, x, custum_fn_z=None):
self.x = x
self.y = self.calc_y()
self.z = self.calc_z(custum_fn_z)
self.w = self.calc_w()
def calc_y(self):
return self.x * 8
def calc_z(self, custom_fn_z=None):
if custom_fn_z:
return custom_fn_z(self.x)
return self.y * 9 + 0.5
def calc_w(self):
return self.z +2
to use it:
one = C(5)
two = C(2)
three = C(1, lambda x: 12*x)
I am trying to make an attribution of an attribution in python.
Is there a way to do so:
class Foo():
def __init__(self, x, y):
self.x = x
self.x.y = y
I have no idea how to do it, I checked for some examples. But I have not found any example similar.
Not exactly clear what you need you can do something like this (for example):
class Bar(object):
def __init__(self, y=None):
self.y = y
class Foo(object):
def __init__(self, x, y):
self.x = x
self.x.y = y
if __name__ == '__main__':
x = Bar()
y = 1
foo = Foo(x,y)
Say I have a class definition which takes some arguments and creates additional data with it, all within the __init__ method:
class Foo():
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
self.bar = generate_bar(x, y, z)
def generate_bar(self, x, y, z):
return x+y+z
I only want to run the generate_bar() method once, when an instance of the class is created, so it wouldn't make sense for that method to be callable on the instance. Is there a sleeker way to ensure that a method is only available to __init__, or do I just have to assume anyone who looks at my code will understand that there's never a situation in which it would be appropriate to call generate_bar() on an instance of the class?
If you are not using any instance state, just make it a separate function:
def _generate_bar(x, y, z):
return x + y + z
class Foo():
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
self.bar = _generate_bar(x, y, z)
The leading underscore, by convention, signals it is an internal function not to be used by external consumers of your module.
You could nest the function inside the __init__ but this doesn't really help with readability:
class Foo():
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def generate_bar():
return x + y + z
self.bar = generate_bar()
Here generate_bar() doesn't even need arguments, it could access x, y and z from the enclosing scope.
For "hidden" functions, it is customary to use a single underscore to signify your intent:
def _generate_bar(self, x, y, z): ...
These are still accessible, but are not visible via tab completion.
See this SO explanation:
class foo:
def __init__(self):
self.response = self._bar()
def _bar(self):
return "bar"
f = foo()
>>> f.response
bar
You can verify yourself that the function _bar is not visible to the object via tab completion
Here is an example which creates a point as p=Point(x, y). Assume that I have some array ppp=(x, y) where x and y are numbers and I want to make it of class Point but in the way: p=Point(ppp). I can do either one or another way but not both simultaneously. Is it possible to have both ways?
There are two different ways to acquire the result, the first is to analyse arguments that you pass to __init__ and in dependence of their quantity and type - choose a decision what are you using to instantiate class.
class Point(object):
x = 0
y = 0
def __init__(self, x, y=None):
if y is None:
self.x, self.y = x, x
else:
self.x, self.y = x, y
The other decision is to use classmethods as instantiators:
class Point(object):
x = 0
y = 0
#classmethod
def from_coords(cls, x, y):
inst = cls()
inst.x = x
inst.y = y
return inst
#classmethod
def from_string(cls, x):
inst = cls()
inst.x, inst.y = x, x
return inst
p1 = Point.from_string('1.2 4.6')
p2 = Point.from_coords(1.2, 4.6)
If you know that you have a tuple/list while creating the instance, you can do: p = Point(*ppp), where ppp is the tuple.
class Point:
def __init__(self, x, y=None):
if isinstance(x, tuple):
self.x, self.y = x
else:
self.x = x
self.y = y
Yes:
class Point(object):
def __init__(self, x, y=None):
if y is not None:
self.x, self.y = x, y
else:
self.x, self.y = x
def __str__(self):
return "{}, {}".format(self.x, self.y)
print Point(1,2)
# 1, 2
print Point((1,2))
# 1, 2
I would guess that your looking for a way to overload your constructor, as is common in statically typed languages such as C++ and Java.
This is not possible in Python. What you can do is provide different keyword argument combinations, something like:
class Point(object):
def __init__(self, x=None, y=None, r=None, t=None):
if x is not None and y is not None:
self.x = x
self.y = y
elif r is not None and t is not None:
# set cartesian coordinates from polar ones
Which you would then use as:
p1 = Point(x=1, y=2)
p2 = Point(r=1, t=3.14)