I'd like to create a class that can use the current version of the data inputted to it.
I've tried:
class DisplayUpdatedNum:
def __init__(self, number):
self.the_num = number
def print_num(self):
print(f'the number is {self.the_num}')
my_num = 1
class_inst = DisplayUpdatedNum(my_num)
class_inst.print_num()
# requested output: the number is 1
my_num = 1905
class_inst.print_num()
# requested output: the number is 1905
This doesn't work, I get the original input number (1) when calling class_inst.print_num() even after changing my_num
Is there a pythonic solution to this?
in my opinion, what you are trying to do is a bad design (as already mentioned):
Attention: (bad solution)
num = 10
class DispalyUpdateNum(object):
global num
def print_num(self):
print(num)
c = DispalyUpdateNum()
c.print_num()
num = 100
c.print_num()
>>>10
>>>100
Much better would be if you use the #property, something like this :
class DispalyUpdateNum(object):
#property
def value(self):
return self._value
#value.setter
def value(self, value):
self._value = value
print("The number is %s" % self._value)
c = DispalyUpdateNum()
c.value = 100
c.value = 10000
c.value = 777
>>> The number is 100
>>> The number is 10000
>>> The number is 777
Would this solution fit in your code is up to you, good luck :)
The class does not have the responsibility to be aware of the changes of a variable at the global level. In fact one of the principles of OOP is to encapsulate the variables that give context to the class (data attributes). There is no pythonic way, but there a straightforward OOP way:
from numbers import Real
class DisplayUpdatedNum:
def __init__(self, number):
self._the_num = number
#property
def num(self):
return self._the_num
#num.setter
def num(self,value):
if not isinstance(value,Real):
raise TypeError('Not a valid numeric type!') #you have now the chance to do some validations here (if you need to)
self._the_num = value
def print_num(self):
print(f'the number is {self._the_num}')
Now you can instaciate your custom class, and when you want to change the valua of the _the_num pseudo-private attr, you just call the num interface that gives you the property class with his getter and setter:
my_num = 1
class_inst = DisplayUpdatedNum(my_num)
class_inst.print_num()
# requested output: the number is 1
my_num = 1905
class_inst.num = my_num
class_inst.print_num()
# requested output: the number is 1905
# Try the basic validation
my_mun = '1905'
class_inst.num = my_num
class_inst.print_num()
# requested output: TypeError: Not a valid numeric type!
Also if you want a little bit further in OOP and combinate it to pythonic ways to do this kind of thing, you could read up about data desciptors
Related
I'm in doubt with this program of mine with inheritance, I don't know if I understand the concept wrong or the code is wrong (maybe both), but I really need some help.
The other functions are working, the only problem is when I try to access the Saving class function by the Account (Subclass).
class Savings:
def __init__(self):
self.money = 0
self.statement = []
def apply(self, value):
self.money += value
self.statement.append(("Apply", f"${value}"))
class Accounts(Savings):
def __init__(self, client: Client, bank: Bank):
super().__init__()
#other variables
def change_money(self):
print("3 - Apply in Savings")
choose = int(input("Choose: "))
elif choose == 3:
value = float(input("Value to apply: $").replace(",", "."))
super().apply(value)
print(super().money)
else:
pass
And when I try to access the money variable, it says
super().money
AttributeError: 'super' object has no attribute 'money'
I made a test using only Accounts as Object and the money variable changed,
Input:
a = Accounts()
a.change_money()
a.money
Output
3 - Apply in Savings
Choose: 3
Value to apply: $100
100.0
but Accounts and Savings are different classes and I need to access it and change from the Subclass
Please, can anyone help me ?
You can use self.apply(value) instead:
class Savings:
def __init__(self):
self.money = 0
self.statement = []
def apply(self, value):
self.money += value
self.statement.append(("Apply", f"${value}"))
class Accounts(Savings):
def change_money(self):
value = float(input("Value to apply: $"))
self.apply(value)
print(self.money)
a = Accounts()
a.change_money() # input, say, 10
print(a.statement) # [('Apply', '$10.0')]
Your object a inherits the method apply attached to itself, so a can call its own method by self.apply.
You don’t need to call super as it is a pre defined function and is part of the savings accounts class. Just call self.apply(value)
With my limited understanding of #property,#setter, and #getter, I came up with following code.
class BitCounts:
sign_bit = 0
exponent_bits = 0
mantissa_bits = 0
_total_bits = 0
#property
def total_bits(self):
return self._total_bits
#total_bits.setter
def total_bits(self):
self._total_bits = self.sign_bit + self.exponent_bits + self.mantissa_bits
class Single(BitCounts):
sign_bit = 1
offset = 0x7F
exponent_bits = 8
mantissa_bits = 23
_total_bits = BitCounts.total_bits
class Double(BitCounts):
sign_bit = 1
offset = 0x400
exponent_bits = 11
mantissa_bits = 52
_total_bits = BitCounts.total_bits
My intention is to use the subclass Single and Double in other functions as a set of options like so, for example:
def some_function(option=Single):
print("exponent bit counts are: %d", option.exponent_bits)
print("mantissa bit counts are: %d", option.mantissa_bits)
print("total bit counts are: %d", option.total_bits)
I would like total_bits to be automatically recalculated using values from subclass Single or Double.
I am trying to avoid extra functions to perform the calculation at subclass level.
With above codes, by calling Single.total_bits, or Double.total_bits, I am only getting a message saying <property object at 0x000002258DF7CB30>, what did I do wrong, and how can I fix it?
The way you are using subclasses with hard-coded static values suggests these should be instances not subclasses. This is also suggested by your temptation to use self even though you haven't made any instances. self refers to a particular instance.
Also, setters typically take a value as an argument. You don't have that in your setter because total_bits is completely dependent on other values. As such you should just move your setter calculation to the getter and return the result of the calculation.
Consider:
class BitCounts:
def __init__(self, sign,offset, exponent, mantissa):
self.sign_bit = sign
self.offset = offset
self.exponent_bits = exponent
self.mantissa_bits = mantissa
#property
def total_bits(self):
return self.sign_bit + self.exponent_bits + self.mantissa_bits
# now make two instances:
single = BitCounts(1, 0x7F, 8, 23 )
double = BitCounts(1, 0x400, 11, 52)
print(single.total_bits)
# 32
print(double.total_bits)
# 64
You can use:
class Single(BitCounts):
sign_bit = 1
offset = 0x7F
exponent_bits = 8
mantissa_bits = 23
_total_bits = BitCounts.total_bits
def get_total_bits(self):
# Update values here, example below
self._total_bits = self._total_bits + 1
return self._total_bits
Then call:
option = Single()
option.get_total_bits()
The problem here is that you are trying to call an instance method from a class.
class A:
#property
def foo(self):
return 1
print(A.foo) # prints an object of function "foo"
print(A().foo) # prints "1"
To accomplish this, at least from my knowledge you need to use a metaclass similar to what they do here: Per-class #property decorator in Python
Hi I am learning about OOP and classes and have some confusion regarding the implementation of classes. Below, I have two sets of identical codes with slight differences in the way I am trying to run them after defining the methods in the class. I am just unsure as to why the first code runs and the second one doesnt as I feel like I am doing the same thing? Also, upon running the first code I get 'None' after the loop has finished, any ideas why that takes place? In addition to this, I know that there are iterators that you can use but just wondering if the method used below to loop through stuff is incorrect or problematic?
class i:
def __init__(self,number):
self.number=number
def fun(self):
for i in range(self.number):
print(i)
kj=i(9)
print(kj.fun())
class i:
def __init__(self,number):
self.number=number
def fun(self):
for i in range(self.number):
print(i)
kj=i()
print(kj.fun(9))
In python, class names are typically capitalized. This avoids the problem here where you define a class with the same name are your index variable.
Also, if you want to print a result of a method, then have the method return a value rather than having it print each value.
Putting these concepts together, I would change
class i:
def __init__(self, number):
self.number = number
def fun(self):
for i in range(self.number):
print(i)
kj=i(9)
print(kj.fun())
to
class I:
def __init__(self, number):
self.number = number
def fun(self, number=None):
if not number:
number = self.number
return list(range(number))
kj = I(9)
numbers = kj.fun()
# if you want to print the list
print(numbers)
# if you want to print individual values
print(*numbers)
# if you want to print one number per line
print('\n'.join(numbers))
The following code illustrates the syntax better with type hint:
class i:
def __init__(self,number: int) -> "i":
self.number=number
def fun(self) -> None:
for i in range(self.number):
print(f"fun - i")
kj=i(9)
print(kj.fun())
The output
-> fun - 0
-> fun - 1
-> fun - 2
-> fun - 3
-> fun - 4
-> fun - 5
-> fun - 6
-> fun - 7
-> fun - 8
-> None
We see that the output 1 - 8 is from within the function
And None is because the fun() method has None return by default.
The second code will have the following error
TypeError: __init__() missing 1 required positional argument: 'number'
because to initialise the class it expects the number input. The fact that you want to pass the parameter on the 'fun' method call, it means to expect the number on class initialisation is redundant;
One can do the following instead:
class i:
def __init__(self):
pass
def fun(self, number: int):
for i in range(number):
print(i)
kj = i()
print(kj.fun(9))
I'm still new to python and this is probably going be one of those (stupid) boring questions. However, any help will be much appreciated. I'm programing something that involves many variables and I've decided to use a class to encapsulate all variables (hopefully making it easier to "read" for me as time passes), but it's not working as I thought it will. So, without further ado here is a part of the class that captures the gist.
import numpy as np
class variable:
def __init__(self, length):
self.length = length # time length`
def state_dynamic(self):
length = self.length
return np.zeros((2, np.size(length)))
def state_static(self):
length = self.length
return np.zeros((2, np.size(length)))
def control_dynamic(self):
length = self.length
return np.zeros((2, np.size(length)))
def control_static(self):
length = self.length
return np.zeros((2, np.size(length)))
def scheduling(self):
length = self.length
return np.zeros(np.size(length))
def disturbance(self):
length = self.length
dummy = np.random.normal(0., 0.1, np.size(length))
for i in range(20):
dummy[i+40] = np.random.normal(0., 0.01) + 1.
dummy[80:100] = 0.
return dummy
I've also tried this one:
import numpy as np
class variable:
def __init__(self, type_1, type_2, length):
self.type_1 = type_1 # belongs to set {state, control, scheduling, disturbance}
self.type_2 = type_2 # belongs to set {static, dynamic, none}
self.length = length # time length
def type_v(self):
type_1 = self.type_1
type_2 = self.type_2
length = self.length
if type_1 == 'state' and type_2 == 'dynamic':
return np.zeros((2, np.size(length)))
elif type_1 == 'state' and type_2 == 'static':
return np.zeros((2, np.size(length)))
elif type_1 == 'control' and type_2 == 'dynamic':
return np.zeros((2, np.size(length)))
elif type_1 == 'control' and type_2 == 'static':
return np.zeros((2, np.size(length)))
elif type_1 == 'scheduling' and type_2 == 'none':
return np.zeros(np.size(length))
elif type_1 == 'disturbance' and type_2 == 'none':
dummy = np.random.normal(0., 0.1, np.size(length))
for i in range(20):
dummy[i+40] = np.random.normal(0., 0.01) + 1.
dummy[80:100] = 0.
return dummy
Now, using the first one (the outcome is the same for the second class as well), when I write the following, say:
In [2]: time = np.linspace(0,10,100)
In [5]: v = variable(time)
In [6]: v1 = v.state_dynamic
In [7]: v1.size
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/home/<ipython-input-7-e6a5d17aeb75> in <module>()
----> 1 v1.size
AttributeError: 'function' object has no attribute 'size'
In [8]: v2 = variable(np.size(time)).state_dynamic
In [9]: v2
Out[9]: <bound method variable.state_dynamic of <__main__.variable instance at 0x3ad0a28>>
In [10]: v1[0,0]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/home/<ipython-input-10-092bc2b9f982> in <module>()
----> 1 v1[0,0]
TypeError: 'instancemethod' object has no attribute '__getitem__'
I was hoping that by writing
variable(length).state_dynamic
I'll access
np.zeros((2, np.size(length)))
Anyway, if I made something utterly stupid please let me know :) and feel free to give any kind of advice. Thank you in advance for your time and kind attention. Best regards.
EDIT #1:
#wheaties:
Thank you for a quick reply and help :)
What I'm currently trying to do is the following. I have to plot several "variables", e.g., state, control, dropouts, scheduling and disturbances. All the variables depend on three parameters, namely, dynamic, static and horizon. Further, state and control are np.zeros((2, np.size(length))), dropouts and scheduling are np.zeros(np.size(length)) and disturbance has specific form (see above). Initially, I declared them in the script and the list is very long and looks ugly. I use these variables to store responses of dynamical systems considered and to plot them. I don't know if this is a good way of doing this and if you have any suggestion please share.
Thanks again for your help.
Do you mean you want named access to a bunch of state information? The ordinary python idiom for class variables would look like this:
class Variable(object):
def __init__ (self, state_dynamic, state_static, control_static, control_dynamic, scheduling):
self.state_dynamic = state_dynamic
self.state_static = state_static
self.control_static = control_static
self.control_dynamic = control_dynamic
self.scheduling = control_dynamic
Which essentially creates a bucket with named fields that hold values you put in via the constructor. You can also create lightweight data classes using the namedtuple factory class, which avoids some of the boilerplate.
The other python idiom that might apply is to use the #property decorator as in #wheaties answer. This basically disguises a function call to make it look like a field. If what you're doing can be reduced to a functional basis this would make sense. This is an example of the idea (not based on your problem set, since I'm not sure I grok what you're doing in detail with all those identical variables) -- in this case I'm making a convenience wrapper for pulling individual flags out that are stored in a python number but really make a bit field:
class Bits(object):
def __init__(self, integer):
self.Integer = integer # pretend this is an integer between 0 and 8 representing 4 flags
#property
def locked(self):
# low bit = locked
return self.Integer & 1 == 1
#property
def available(self):
return self.Integer & 2 == 2
#property
def running_out_of_made_up_names(self):
return self.Integer & 4 == 4
#property
def really_desperate_now(self):
return self.Integer & 8 == 8
example = Bits(7)
print example.locked
# True
print example.really_desperate_now
# False
A method in Python is a function. If you want to get a value from a member function you have to end it with (). That said, some refactoring may help eliminate boilerplate and reduce the problem set size in your head. I'd suggest using a #property for some of these things, combined with a slight refactor
class variable:
def __init__(self, length):
self.length = length # time length`
#property
def state_dynamic(self):
return self.np_length
#property
def state_static(self):
return self.np_length
#property
def control_dynamic(self):
return self.np_length
#property
def control_static(self):
return self.np_length
#property
def scheduling(self):
return self.np_length
#property
def np_length(self):
return np.zeros(2, np.size(self.length))
That way you can use those functions as you would a member variable like you tried before:
var = variable(length).state_dynamic
What I can't tell from all this is what the difference is between all these variables? I don't see a single one. Are you assuming that you have to access them in order? If so, that's bad design and a problem. Never make that assumption.
I am writing a program to add to and update an address book. Here is my code:
EDITED
import sys
import os
list = []
class bookEntry(dict):
total = 0
def __init__(self):
bookEntry.total += 1
self.d = {}
def __del__(self):
bookEntry.total -= 1
list.remove(self)
class Person(bookEntry):
def __init__(self, n):
self.n = n
print '%s has been created' % (self.n)
def __del__(self):
print '%s has been deleted' % (self.n)
def addnewperson(self, n, e = '', ph = '', note = ''):
self.d['name'] = n
self.d['email'] = e
self.d['phone'] = ph
self.d['note'] = note
list.append()
def updateperson(self):
key = raw_input('What else would you like to add to this person?')
val = raw_input('Please add a value for %s' % (key))
self.d[key] = val
def startup():
aor = raw_input('Hello! Would you like to add an entry or retrieve one?')
if aor == 'add':
info = raw_input('Would you like to add a person or a company?')
if info == 'person':
n = raw_input('Please enter this persons name:')
e = raw_input('Please enter this persons email address:')
ph = raw_input('Please enter this persons phone number:')
note = raw_input('Please add any notes if applicable:')
X = Person(n)
X.addnewperson(n, e, ph, note)
startup()
When I run this code I get the following error:
in addnewperson
self.d['name'] = n
AttributeError: 'Person' object has no attribute 'd'
I have two questions:
UPDATED QUESTIONS
1. why isnt the d object being inherited from bookentry()?
I know this question/code is lengthy but I do not know where to go from here. Any help would be greatly appreciated.
The addnewperson shoud have 'self' as first argument; actually, the name doesn't matter ('self' is just a convention), but the first argument represent the object itself. In your case, it's interpreting n as the "self" and the other 3 as regular arguments.
____del____ must not take arguments besides 'self'.
Edit: BTW I spotted a few other problems in your example, that maybe you're not aware of:
1) d in bookentry is a class member, not an instance member. It's shared by all bookentry's instances. To create an instance member, use:
class bookentry(dict):
def __init__(self,n):
self.d = {}
# rest of your constructor
2) you're trying to access d directly (as you would do in Java, C++ etc), but Python doesn't support that. You must have a 'self' parameter in your methods, and access instance variables through it:
class person(bookentry):
def foo(self,bar):
self.d[bar] = ...
person().foo(bar)
Update: for the last problem, the solution is to call the super constructor (which must be done explicitly in Python):
class Person(bookEntry):
def __init__(self, n):
super(Person, self).__init__()
self.n = n
print '%s has been created' % (self.n)
A brief explanation: for people with background in OO languages without multiple inheritance, it feels natural to expect the super type constructor to be called implicitly, automatically choosing the most suitable one if no one is mentioned explicitly. However, things get messy when a class can inherit from two or more at the same time, for this reason Python requires the programmer to make the choices himself: which superclass constructor to call first? Or at all?
The behavior of constructors (and destructors) can vary wildly from language to language. If you have further questions about the life cycle of Python objects, a good place to start would be here, here and here.
why isnt the d object being inherited from bookentry()?
That's because __init__ of the bookEntry is not called in the __init__ of the Person:
super(Person, self).__init__()
BTW, why inherit from dict if its functionality is not used? It's better to remove it and inherit from object instead (also class names are usually CamelCased):
class BookEntry(object):