I'm having a hard time summarizing my question so I apologize if this is a duplicate.
I have a class like such:
class MyClass:
timer = 60
I want timer to represent an integer but also extend some custom methods. For example:
>>> c = MyClass()
>>> c.timer
60
>>> c.timer.wait() # This would wait 60 seconds
True
>>> c.timer
0
How can I do this in Python?
Not sure what you are trying to achieve, but your MyClass can be implemented as follows:
class MyClass:
def __init__(self):
self.a = 0
self.b = 0
def do_some_operation(self):
# do something using a and b
# and return True if success
self.a += 100;
return True
c = MyClass()
print(c.do_some_operation()) # True
print(c.a) # 100
Maybe you should try to make a class that simulates the integers:
class Integer:
value = 0
def __init__(self, value):
self.value = value
def __add__(self, other):
return Integer(self.value + other.value)
#Would need to do the other basic arithmetic things. I'll leave that to you...
def __str__(self):
return str(self.value)
def do_some_operation(self):
return True
class MyClass:
a = Integer(0)
b = Integer(0)
c = MyClass()
print c.a
print c.b
print c.a + c.b
print c.a.do_some_operation()
Gives:
0
0
0
True
I would be careful about doing this though. There may be another more suitable way.
Related
I am using Python 3.8.6 and this works fine
class A:
#property
def _a(self):
return getattr(self, '_a_', 0)
#_a.setter
def _a(self, value):
self._a_ = value
a = A()
print(a._a) # prints 0
a._a = 10
print(a._a) # prints 10 as expected
This doesn't work
class A:
#property
def _a(self):
return getattr(self, '__a', 0)
#_a.setter
def _a(self, value):
self.__a = value
a = A()
print(a._a) # prints 0
a._a = 10
print(a._a) # prints 0 again
That's mind blowing! the only difference between the first and second example is that the private attribute is __a instead of _a_
Any idea why? I wasn't able to figure it out
It's due to private name mangling, but it doesn't apply to the contents of string literals like the one you're passing to getattr().
Fortunately the fix is simple:
class A:
#property
def _a(self):
return getattr(self, '_A__a', 0)
#_a.setter
def _a(self, value):
self.__a = value
a = A()
print(a._a) # prints 0
a._a = 10
print(a._a) # prints 10 now
I am wondering how to print attribute(which is a list of another class) of a class one item in row. The code looks something like this:
class A:
def __init__(self, i):
self.index = i
def __str__(self):
return str(self.index)
__repr__ = __str__
class B:
def __init__(self):
self.b = []
def load(self):
for i in range(3):
a = A(i)
self.b.append(a)
def __str__(self):
# My 1st solution
return self.b
# My 2nd solution
for i in self.b:
print(i)
__repr__ = __str__
b = B()
b.load()
print(b) # TypeError: __str__ returned non-string (type list)
Expected output:
0
1
2
You can do something like this:
def __str__(self):
return '\n'.join([str(x) for x in self.b])
Which would make each <class '__main__.A'> inside self.b into a str before joining them with .join.
>>> print(b)
0
1
2
Assume this example:
class A(object):
def add(self, number):
self.n += number
B = type("B", (A,), {"n":3})
b = B()
b.add(5)
b.n
This code works for me and returns a b.n = 8 or b.n=3 after object creation, but if the class A is changed to
class A(object):
def__init__(self):
self.n = 0
def add(self, number):
self.n += number
B = type("B", (A,), {"n":3})
b = B()
b.add(5)
b.n
In this case the b.n is only 5, after object creation it seems that the n is taken from the base class and not from the newly created class. Is there a way to have the n object overwritten at creation time of object B ?
The dictionary passed as third argument to type are the class members. That is, your type invocation is equivalent to:
class B(A):
n = 3
A.__init__ is inherited, and it adds an instance variable. Instance variables shadow class variables, so b.n starts out as 0 (while B.n is indeed 3).
Note that the inheritance is irrelevant, the code below shows the same behavior:
class B(object):
n = 3
def __init__(self):
self.n = 0
def add(self, number):
self.n += number
#delnan gives an explanation of why this is happening.
The following shows how you can do what you're trying to do:
class A(object):
def __init__(self):
self.n = 0
def add(self, number):
self.n += number
def create_B(initial_n):
class B(A):
def __init__(self):
self.n = initial_n
return B
B = create_B(3)
b = B()
b.add(5)
print b.n
I have two classes. a and b.
In one of class a's methods, I created an object of class b. One of class b attributes takes a function. So say I gave it a random function but does this function of class b have access to class a's attribute? even though I didn't pass it in directly as a parameter?
class b:
def __init__(self):
self.attribute_function = None
class a:
def __init__(self):
self.temp = 10
self.counter = 0
def temp(self):
obj = b()
obj.attribute_function = lambda self: self.counter < self.temp
return obj.attribute_function()
if __name__ == "__main__":
#pass
obj = a()
print obj.temp()
In the above example, I tried to provide a really basic example, but if you run it, it doesn't work...
Revised Code, class a should look like this:
class a:
def __init__(self):
self.temp = 10
self.counter = 0
def temp(self):
obj = b()
obj.attribute_function = lambda args: self.counter < self.temp
return obj.attribute_function(1) # i added this 1 to fill in arg
This works:
class b:
def __init__(self):
self.attribute_function = None
class a:
def __init__(self):
self._temp = 10
self.counter = 0
def temp(self):
obj = b()
obj.attribute_function = lambda self=self: self.counter < self._temp
return obj.attribute_function()
if __name__ == "__main__":
obj = a()
print obj.temp()
On problem you had is self.temp = 10 which shadowed your method temp().
Another problem: lambda self: self.counter < self._temp. Your lambda function was expecting an argument. But omitting self is not a good idea lambda : self.counter < self._temp, because if you call obj.attribute_function() somewhere where self is not available or has changed - it will not find self or use another self. self=self fixes that.
But generally such magic is an anti-pattern. Tell us what are your trying to achieve, and there should be a better way to do what you want. Otherwise this kind of code will ensure many headaches.
I think this is a better solution (called strategy pattern):
class B:
def __init__(self, a):
self.a = a
def temp(self):
return self.a.temp()
class A:
def __init__(self):
self._temp = 10
self.counter = 0
def temp(self):
return self.counter < self._temp
if __name__ == "__main__":
obj = B(A())
print obj.temp()
Your example does not work because you have a name collision at temp
You have assigned temp to be both a method:
def temp(self):
and an attribute:
self.temp = 10
I am starting to work with classes in Python, and am learning how to create functions within classes. Does anyone have any tips on this sample class & function that I am testing out?
class test:
def __init__(self):
self.a = None
self.b = None
self.c = None
def prod(self):
return self.a * self.b
trial = test
trial.a = 4
trial.b = 5
print trial.prod
Ideally the result would be to see the number 20.
You need to:
Create an instance of test.
Invoke the prod method of that instance.
Both of these can be accomplished by adding () after their names:
trial = test()
trial.a = 4
trial.b = 5
print trial.prod()
Below is a demonstration:
>>> class test:
... def __init__(self):
... self.a = None
... self.b = None
... self.c = None
... def prod(self):
... return self.a * self.b
...
>>> trial = test()
>>> trial.a = 4
>>> trial.b = 5
>>> print trial.prod()
20
>>>
Without the parenthesis, this line:
trial = test
is simply assigning the variable trial to class test itself, not an instance of it. Moreover, this line:
print trial.prod
is just printing the string representation of test.prod, not the value returned by invoking it.
Here is a reference on Python classes and OOP.
Ideally you could also pass in the values to a, b, c as parameters to your object's constructor:
class test:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def prod(self):
return self.a * self.b
Then, constructing and calling the function would look like this:
trial = test(4, 5, None)
print trial.prod()