I found a task where I am asked to implement some object that repeats a string n times but condition is that this something must not be a function. I have tried the following:
class str_repeat:
def __init__(self,x,y):
self.s = x * y
def __repr__(self):
return self.s
but this did not work.Some Hints would help a lot
Humm! str_repeat must be a callable.
What do you think of:
str_repeat = str.__mul__
Related
I have just almost finished my assignment and now the only thing I have left is to define the tostring method shown here.
import math
class RegularPolygon:
def __init__(self, n = 1, l = 1):
self.__n = n
self.__l = l
def set_n(self, n):
self.__n = n
def get_n(self):
return self.__n
def addSides(self, x):
self.__n = self.__n + x
def setLength(self, l ):
self.__l = l
def getLength(self):
return self.__l
def setPerimeter(self):
return (self.__n * self.__l )
def getArea(self):
return (self.__l ** 2 / 4 * math.tan(math.radians(180/self.__n)))
def toString(self):
return
x = 3
demo_object = RegularPolygon (3, 1)
print(demo_object.get_n() , demo_object.getLength())
demo_object.addSides(x)
print(demo_object.get_n(), demo_object.getLength())
print(demo_object.getArea())
print(demo_object.setPerimeter())
Basically the tostring on what it does is return a string that has the values of the internal variables included in it. I also need help on the getArea portion too.
Assignment instructions
The assignment says
... printing a string representation of a RegularPolygon object.
So I would expect you get to choose a suitable "representation". You could go for something like this:
return f'{self.__n+2} sided regular polygon of side length {self.__l}'
or as suggested by #Roy Cohen
return f'{self.__class__.__name__}({self.__n}, {self.__l})'
However, as #Klaus D. wrote in the comments, Python is not Java, and as such has its own standards and magic methods to use instead.
I would recommend reading this answer for an explanation between the differences between the two built-in string representation magic-methods: __repr__ and __str__. By implementing these methods, they will automatically be called whenever using print() or something similar, instead of you calling .toString() every time.
Now to address the getters and setters. Typically in Python you avoid these and prefer using properties instead. See this answer for more information, but to summarise you either directly use an objects properties, or use the #property decorator to turn a method into a property.
Edit
Your area formula is likely an error with order-of-operations. Make sure you are explicit with which operation you're performing first:
return self.__l ** 2 / (4 * math.tan(math.radians(180/self.__n)) )
This may be correct :)
Hello im learning python and i get class topic.
I recived a error message like this:
"TypeError: __init__() missing 1 required positional argument: 'y'"
this is my code from shell:
class Vektor():
""" Bu bir vektör sınıfıdır"""
def __init__(self,x,y):
self.x = x
self.y = y
def boyu(self):
boy = (self.x**2+self.y**2)**0.5
return boy
def __repr__(self):
return ("%di + %dy" %(self.x, self.y))
def __sub__(self,digeri):
return Vektor(self.x - digeri.x, self.y - digeri.y)
def __add__(self,digeri):
return Vektor(self.x + digeri.x, self.y + digeri.y)
def __eq__(self,digeri):
if self.boyu() == digeri.boyu(): return True
def __mul__(self,digeri):
self.x = Vektor(self.x + digeri.x)
self.y = Vektor(self.y + digeri.y)
return Vektor(self.x*digeri.x,self.y*digeri.y)
When i try to create a C = A*B like this i get error:
TypeError: init() missing 1 required positional argument: 'y'
Im already thank you and i want to remind im a newbite in programming :))
How many arguments does Vektor.__init__ require? Ignoring self, it's two - x and y.
When you wrote return Vektor(self.x*digeri.x,self.y*digeri.y), you passed two arguments, so this works.
When you wrote self.x = Vektor(self.x + digeri.x), this doesn't work, because you don't pass a second argument for the y value.
When Python gave you the error, it should have included a line number, which is supposed to show where the error occurred. You didn't include that, but it was this line, wasn't it?
Since Vektor is supposed to contain two scalars and not sometimes replace them with two vectors, you could just write
self.x = self.x + digeri.x # still not a vector
self.y = self.y + digeri.y # also not a vector
but the more important lesson is to read the error message carefully. Everything you needed was there.
A note on operator semantics: since you wouldn't normally expect an expression like x = v * w to modify x, you shouldn't be mutating self inside the operator function anyway.
You return the resultant vector, which is enough. I showed you how to fix the syntax of those two lines, but you should really just remove them entirely.
And another note on vectors: overloading * isn't such an obvious win as it is for a scalar numeric type, because vectors usually have more than one possible type of product.
In __mul__ you do for some reason:
self.x = Vektor(self.x + digeri.x)
which is calling Vektor.__init__ providing only the positional argument x, with the value self.x + digeri.x, but nothing for y, thus the error.
Also this attempts to change the attribute x into an object from Vektor itself, I can't imagine that this is somehow what you want.
To me it is not clear what the 2 lines before the return statement in your __mul__ are supposed to do. Also both lines will produce the error you see.
Should your __mul__ be the dot product? If so, try:
return self.x*digeri.x + self.y*digeri.y
Another simplification to your class could be to allow iteration on your coords, like:
#property
def coords(self):
return self.x, self.y
def __iter__(self):
return self.coords.__iter__()
Then your dot product might just look like:
def dot(self, w):
"""
The dot product of self and other vector w.
"""
return sum([xi_s * xi_w for xi_s, xi_w in zip(self, w)])
There is VecPy, a very simple example class that does this kind of things. Maybe having a look can give you some more ideas.
The error is due to
self.x = Vektor(self.x + digeri.x)
When we call Vector like the way you write the syntax, it is thinking that you want to initialize it and it is expecting two inputs. Just get rid of the first two lines of mul function should fix the problem.
I'm trying to write an implementation of a genetic algorithm in python. It says there I am calling it with two arguments when only one is allowed, but I'm sure I'm not.
Here is the relevant code:
class GA:
def __init__(self, best, pops=100, mchance=.07, ps=-1):
import random as r
self.pop = [[] for _ in range(pops)]
if ps == -1:
ps = len(best)
for x in range(len(self.pop)): #Creates array of random characters
for a in range(ps):
self.pop[x].append(str(unichr(r.randint(65,122))))
def mutate(array):
if r.random() <= mchance:
if r.randint(0,1) == 0:
self.pop[r.randint(0, pops)][r.randint(0, ps)] +=1
else:
self.pop[r.randint(0, pops)][r.randint(0, ps)] -=1
This is the code when I initialize and call from the class:
a = GA("Hello",10,5)
a.mutate(a.pop)
which returns the following error from IDLE:
TypeError: mutate() takes exactly 1 argument (2 given)
How can I fix this?
Methods of a class are automatically passed the instance of the class as their first argument (it's named self by convention):
def mutate(self, array):
I'm fairly new to classes in python, so please be gentle. My script is a tad more complicated than this, but this is essentially what it boils down to:
class primary_state:
def __init__(self,x,y,z):
self.x = x
self.y = y
self.z = z
self.substates=[]
def add_substate(self,i,j,k):
self.substates.append(self.substate(i,j,k))
class substate:
def __init__(self,i,j,k):
self.i = i
self.j = j
self.k = k
state = primary_state(1,2,3)
state.add_substate(4,5,6)
state.add_substate(7,8,9)
Now my question is: is it possible to return an array of values from each object? So for example I'd like to do:
state.substates[:].i
and have it return the values of 4 and 7, but alas substates is a list so it can't handle it. There also must be a more efficient way to do this but I haven't quite figured that out yet. Any advice/thoughts would be greatly appreciated! Thanks.
Use a list comprehension.
[sub.i for sub in state.substates]
This is roughly equivalent to the following:
x = []
for sub in state.substates:
x.append(sub.i)
except shorter, and it's an expression that you can embed in other expressions instead of a series of statements.
You can get the list of substates by calling:
[substate.i for substate in self.substates]
list comprehensions are the way to do it as the other answers point out.
If the only job of the primary state class is to hold subclasses, you can make your class behave like an iterable. In the example you give this is mostly syntactic sugar, but it can be useful. Complete instructions on how to do it are here but it's pretty simple:
class PrimaryState(object): #always use "new style" classes! its 2013!
def __init__(self,x,y,z):
self.x = x
self.y = y
self.z = z
self.substates=[]
def __len__(self):
return len(self.substates)
def __getitem__(self, index):
return self.substates[index]
def __iter__(self):
for sub in substates: yield sub
def __contains__(self, item):
return item in self.substates
def add(self, item):
self.substates.append(item)
This way you can do:
primary = PrimaryState(1,2,3)
primary.add(SubState(4,5,6))
primary.add(SubState(7,8,9))
for item in primary:
print item
# Substate 4,5,6
# Substate 7,8,9
PS: Check out PEP-8, the standard python style guide for naming classes and so on. And use new style classes (inheriting from object). Down the road it's important!
I was thinking about how to use super to make a pipeline in python. I have a series of transformations I must do to a stream, and I thought that a good way to do it was something in the lines of:
class MyBase(object):
def transformData(self, x):
return x
class FirstStage(MyBase):
def transformData(self, x):
y = super(FirstStage, self).transformData(x)
return self.__transformation(y)
def __transformation(self, x):
return x * x
class SecondStage(FirstStage):
def transformData(self, x):
y = super(SecondStage, self).transformData(x)
return self.__transformation(y)
def __transformation(self, x):
return x + 1
It works as I intended, but there's a potential repetition. If I have N stages, I'll have N identical transformData methods where the only thing I change is the name of the current class.
Is there a way to remove this boilerplate? I tried a few things but the results only proved to me that I hadn't understood perfectly how super worked.
What I wanted was to define only the method __transformation and naturally inherit a transformData method that would go up in MRO, call that class' transformData method and then call the current class' __transformation on the result. Is it possible or do I have to define a new identical transformData for each child class?
I agree that this is a poor way of implementing a pipeline. That can be done with much simpler (and clearer) schemes. I thought of this as the least modification I could do on a existing model to get a pipeline out of the existing classes without modifying the code too much. I agree this is not the best way to do it. It would be a trick, and tricks should be avoided. Also I thought of it as a way of better understanding how super works.
Buuuut. Out of curiosity... is it possible to do it in the above scheme without the transformData repetition? This is a genuine doubt. Is there a trick to inherit transformData in a way that the super call in it is changed to be called on the current class?
It would be a tremendously unclear, unreadable, smart-ass trickery. I know. But is it possible?
I don't think using inheritance for a pipeline is the right way to go.
Instead, consider something like this -- here with "simple" examples and a parametrized one (a class using the __call__ magic method, but returning a closured function would do too, or even "JITing" one by way of eval).
def two_power(x):
return x * x
def add_one(x):
return x + 1
class CustomTransform(object):
def __init__(self, multiplier):
self.multiplier = multiplier
def __call__(self, value):
return value * self.multiplier
def transform(data, pipeline):
for datum in data:
for transform in pipeline:
datum = transform(datum)
yield datum
pipe = (two_power, two_power, add_one, CustomTransform(1.25))
print list(transform([1, 2, 4, 8], pipe))
would output
[2.5, 21.25, 321.25, 5121.25]
The problem is that using inheritance here is rather weird in terms of OOP. And do you really need to define the whole chain of transformations when defining classes?
But it's better to forget OOP here, the task is not for OOP. Just define functions for transformations:
def get_pipeline(*functions):
def pipeline(x):
for f in functions:
x = f(x)
return x
return pipeline
p = get_pipeline(lambda x: x * 2, lambda x: x + 1)
print p(5)
An even shorter version is here:
def get_pipeline(*fs):
return lambda v: reduce(lambda x, f: f(x), fs, v)
p = get_pipeline(lambda x: x * 2, lambda x: x + 1)
print p(5)
And here is an OOP solution. It is rather clumsy if compared to the previous one:
class Transform(object):
def __init__(self, prev=None):
self.prev_transform = prev
def transformation(self, x):
raise Exception("Not implemented")
def transformData(self, x):
if self.prev_transform:
x = self.prev_transform.transformData(x)
return self.transformation(x)
class TransformAdd1(Transform):
def transformation(self, x):
return x + 1
class TransformMul2(Transform):
def transformation(self, x):
return x * 2
t = TransformAdd1(TransformMul2())
print t.transformData(1) # 1 * 2 + 1