I am new to python and i have a quick question.
How can I avoid repeating my self when I declare the Class instances x1 x2 ..
I tried it with a list but then I wasn't able to create a file for each object after.
And not all parameters are the same for my objects, d[0] is counting up.
Any smart idea to get rid of repeating myself here?
thanks in advance
class TestClass(object):
def __init__(self, a, b, c: int):
self.a = a
self.b = b
self.c = c
def __str__(self):
return f" a= {self.a} b = {self.b} c = {self.c}"
def func1():
a = input("a: ")
b = input("b: ")
return a, b
def func2():
return 100, 90, 80, 70
c = func1()
d = func2()
x1 = TestClass(c[0], c[1], d[0])
x2 = TestClass(c[0], c[1], d[1])
x3 = TestClass(c[0], c[1], d[2])
x4 = TestClass(c[0], c[1], d[3])
h = {"a": x1,"b": x2, "c": x3, "d": x4}
for key, value in h.items():
with open(f"Name {key}.txt","w") as f:
f.write(str(value))
OUTPUT:
#a: Anton
#b: Bernd
#
# four files Name a - d.txt were created
# file 1: a= Anton b = Bernd c = 100
# file 2: a= Anton b = Bernd c = 90
# file 3: a= Anton b = Bernd c = 80
# file 4: a= Anton b = Bernd c = 70
You should iterate on the return value (tuple) of the func2 function (so on the d variable) with the enumerate function. The enumerate function returns the value and the related index of the iterator (Eg.: https://realpython.com/python-enumerate/). Then you can add the element for your (empty) dict. You should use the chr function to define the letters based on the index. The lowercase a is the 97.
Related code part:
c = func1()
d = func2()
h = {}
for idx, value in enumerate(d):
h[chr(97 + idx)] = TestClass(c[0], c[1], d[idx])
for key, value in h.items():
with open(f"Name {key}.txt", "w") as f:
f.write(str(value))
NOTE:
I have written a more compact version of code. You can check it if you are interested in it.
Code:
class TestClass(object):
def __init__(self, a, b, c: int):
self.a = a
self.b = b
self.c = c
def __str__(self):
return f" a= {self.a} b = {self.b} c = {self.c}"
a, b, h, d = input("a: "), input("b: "), {}, [100, 90, 80, 70]
result = [(chr(97 + idx), TestClass(a, b, d[idx])) for idx, value in enumerate(d)]
for item in result:
with open(f"Name {item[0]}.txt", "w") as f:
f.write(str(item[1]))
Quick answer
Use a Function, when you need to do something that's going to take you a lot of Typing or you need to do something repeatedly then pack it into a function.
def create_func(fun_1, fun_2):
result = {}
acii_n = 97
for item in fun_2:
name = chr(acii_n)
acii_n += 1
class_instance = TestClass(fun_1[0], fun_1[1], item)
result.setdefault(name, class_instance)
return result
h = create_func(c, d)
for key, value in h.items():
with open(f"Name {key}.txt","w") as f:
f.write(str(value))
chr(i) Function. You can see that I call the function starting at int 97.
That's because the ASCII value is the letter a --> asciitable.com.
Additional improvements
Funny enough the solution I gave, which is use a function, is also the exact opposite that I can suggest you to do for improve your script, which is remove the functions :).
class TestClass(object):
def __init__(self, a, b, c: int):
self.a = a
self.b = b
self.c = c
def __str__(self):
return f" a= {self.a} b = {self.b} c = {self.c}"
def create_instances(fun_2):
a = input("a: ")
b = input("b: ")
user_values = [a, b]
result = {}
ascii_n = 97
for item in fun_2:
name = chr(ascii_n)
ascii_n += 1 # Step on the next charactes
class_instance = TestClass(user_values[0], user_values[1], item)
result.setdefault(name, class_instance)
return result
int_values = [100, 90, 80, 70] # Just pack it into a list
all_instances = create_instances(int_values)
for key, value in all_instances.items():
with open(f"Name {key}.txt","w") as f:
f.write(str(value))
Using a Dictionary Comprehension
Very Powerful Tool, fast (can run Faster the For loops) and super Pythonic :) Python Dictionary Comprehension.
class TestClass(object):
def __init__(self, a, b, c: int):
self.a = a
self.b = b
self.c = c
def __str__(self):
return f" a= {self.a} b = {self.b} c = {self.c}"
int_values = [100, 90, 80, 70]
a = 'Python'
b = 'WOOW'
user_values = [a, b]
ascii_n = 97
result = {chr(ascii_n+idx): TestClass(user_values[0], user_values[1], item) for idx, item in enumerate(int_values)}
for key, value in result.items():
with open(f"Name {key}.txt","w") as f:
f.write(str(value))
Related
I would like to have users enter specific values and then the system computes numerous results based on what these - My program is getting very complicated with just a few functions. I have included an example with 3 simple functions and 6 variables with the following relationships:
The Code I have is as follows:
class MyCalculator:
def __init__(self):
self.a = None
self.b = None
self.c = None
self.d = None
self.e = None
self.f = None
def set(self, field, val):
if field == "a": self.a = val
if field == "b": self.b = val
if field == "c": self.c = val
if field == "d": self.d = val
if field == "e": self.e = val
for i in range(10): # circle round a few times to ensure everything has computed
if self.a and self.b:
self.c = self.a * self.b
if self.a and self.c:
self.b = self.c / self.a
if self.b and self.c:
self.a = self.c / self.b
if self.b and self.d:
self.e = self.b + self.d
if self.e and self.b:
self.d = self.e - self.b
if self.e and self.d:
self.b = self.e - self.d
if self.c and self.e:
self.f = self.c / self.e
if self.f and self.e:
self.e = self.f * self.e
if self.f and self.c:
self.e = self.c / self.f
def status(self):
print(f"a = {self.a} b = {self.b} c = {self.c} d = {self.d} e = {self.e} f = {self.f} ")
Then If i run the following code:
example1 = MyCalculator()
example1.set("a", 5)
example1.set("e", 7)
example1.set("c", 2)
example1.status()
This will print out a = 5.0 b = 0.40000000000000036 c = 2.0000000000000018 d = 6.6 e = 7.0 f = 0.285714285714286
I would like a much simpler way to achieve the same result using something like sympy and numpy but so far I cant find anything that will work
There's a live version of this solution online you can try for yourself
Here's a complete solution that uses Sympy. All you need to do is enter your desired expressions in the exprStr tuple at the top of the MyCalculator definition, and then all of the dependency satisfaction stuff should take care of itself:
from sympy import S, solveset, Symbol
from sympy.parsing.sympy_parser import parse_expr
class MyCalculator:
# sympy assumes all expressions are set equal to zero
exprStr = (
'a*b - c',
'b + d - e',
'c/e - f'
)
# parse the expression strings into actual expressions
expr = tuple(parse_expr(es) for es in exprStr)
# create a dictionary to lookup expressions based on the symbols they depend on
exprDep = {}
for e in expr:
for s in e.free_symbols:
exprDep.setdefault(s, set()).add(e)
# create a set of the used symbols for input validation
validSymb = set(exprDep.keys())
def __init__(self, usefloat=False):
"""usefloat: if set, store values as standard Python floats (instead of the Sympy numeric types)
"""
self.vals = {}
self.numify = float if usefloat else lambda x: x
def set(self, symb, val, _exclude=None):
# ensure that symb is a sympy Symbol object
if isinstance(symb, str): symb = Symbol(symb)
if symb not in self.validSymb:
raise ValueError("Invalid input symbol.\n"
"symb: %s, validSymb: %s" % (symb, self.validSymb))
# initialize the set of excluded expressions, if needed
if _exclude is None: _exclude = set()
# record the updated value of symb
self.vals[symb] = self.numify(val)
# loop over all of the expressions that depend on symb
for e in self.exprDep[symb]:
if e in _exclude:
# we've already calculated an update for e in an earlier recursion, skip it
continue
# mark that e should be skipped in future recursions
_exclude.add(e)
# determine the symbol and value of the next update (if any)
nextsymbval = self.calc(symb, e)
if nextsymbval is not None:
# there is another symbol to update, recursively call self.set
self.set(*nextsymbval, _exclude)
def calc(self, symb, e):
# find knowns and unknowns of the expression
known = [s for s in e.free_symbols if s in self.vals]
unknown = [s for s in e.free_symbols if s not in known]
if len(unknown) > 1:
# too many unknowns, can't do anything with this expression right now
return None
elif len(unknown) == 1:
# solve for the single unknown
nextsymb = unknown[0]
else:
# solve for the first known that isn't the symbol that was just changed
nextsymb = known[0] if known[0] != symb else known[1]
# do the actual solving
sol = solveset(e, nextsymb, domain=S.Reals)
# evaluate the solution given the known values, then return a tuple of (next-symbol, result)
return nextsymb, sol.subs(self.vals).args[0]
def __str__(self):
return ' '.join(sorted('{} = {}'.format(k,v) for k,v in self.vals.items()))
Testing it out:
mycalc = MyCalculator()
mycalc.set("a", 5)
mycalc.set("e", 7)
mycalc.set("c", 2)
print(mycalc)
Output:
a = 5 b = 2/5 c = 2 d = 33/5 e = 7 f = 2/7
One of the neat things about Sympy is that it uses rational math, which avoids any weird rounding errors in, for example, 2/7. If you'd prefer to get your results as standard Python float values, you can pass the usefloat flag to MyCalculator:
mycalc = MyCalculator(usefloat=True)
mycalc.set("a", 5)
mycalc.set("e", 7)
mycalc.set("c", 2)
print(mycalc)
Output:
a = 5.0 b = 0.4 c = 2.0 d = 6.6 e = 7.0 f = 0.2857142857142857
In [107]: a=2.
In [108]: a=5.
In [109]: b=0.4
In [110]: c=lambda: a*b
In [111]: d=6.6
In [112]: e=lambda: b+d
In [113]: f=lambda: c()/e()
In [114]: print(a,b,c(), d, e(), f())
5.0 0.4 2.0 6.6 7.0 0.2857142857142857
You can probably capture the above logic in a class.
It would be possible to hold 'variables' as _a, _b and _d. Then a(), b() and d() could be functions that return _a etc...
More a pointer than a whole answer but it may help.
Using a structure like that below it would be possible to create a situation where you always call a function and not need to know when to use a and c() but always use a() and c().
In [121]: def var(init=0.0):
...: def func(v=None):
...: nonlocal init
...: if v==None: return init
...: init=v
...: return func
...:
In [122]: a=var(100.)
In [123]: a()
Out[123]: 100.0
In [124]: a(25.)
In [125]: a()
Out[125]: 25.0
Both functions do the same thing.
def function1(self):
a = self.get_a()
b = self.get_b()
c = self.get_c()
r = None
if a:
r = a
if b:
r = b
if c:
r = c
else:
print("c not set.")
else:
print("b not set.")
else:
print("a not set.")
return r
def function2(self):
a = self.get_a()
b = self.get_b()
c = self.get_c()
r = None
if not a:
print("a not set.")
return r
r = a
if not b:
print("b not set.")
return r
r = b
if not c:
print("c not set.")
r = c
return r
function1() creates very long lines the more if's are nested which conflicts with PEP8's line-length limit of 78.
function2() might be harder to read/understand and has more return statements. Line length is no problem here.
Which one is more pythonic?
One of the principals of Pythonic code is "flat is better than nested". On this basis, I'll say function2() is objectively more Pythonic. This can be seen in PEP-20: The Zen of Python:
The Zen of Python
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
This can be seen by typing import this inside the Python interpreter.
As #Will's answer suggests, flat is better. However the code doesn't look very pretty anyways. How about a more compact type of code?
looking at these quotes from #Will's answer:
Readability counts.
Beautiful is better than ugly.
from collections import OrderedDict
def function3():
my_dictionary=OrderedDict()
my_dictionary['a'] = self.get_a()
my_dictionary['b'] = self.get_b()
my_dictionary['c'] = self.get_c()
# ...
r = None
for name in my_dictionary.keys():
value = my_dictionary[name]
if not value:
print("%s not set." % name)
return r
r = value
return r
Surely this can be improved even more
You can use the evaluation rules of the and and or operators, for example:
>>> None or 4 or None or 5
4
>>> 4 and 5
5
So you'd have something like:
def function3(self):
a = self.get_a()
b = self.get_b()
c = self.get_c()
return (a and b and c) or (a and b) or a or None
And I'd recommend factoring out you I/O from your logical code.
I suggest function_4 displayed below together with the questions (non-idetnically working!) functions and one of DomTomCat's answer:
#! /usr/bin/env python
from __future__ import print_function
from collections import OrderedDict # Only used in function_3
def function_4(self):
"""Iterate over call results in FIFO on False or if sequence
exhausted, return None or previous value if that evaluates to true."""
functors = (
self.get_a,
self.get_b,
self.get_c,
)
request_targets = (
'a',
'b',
'c',
)
response_value = None
for functor, request_target in zip(functors, request_targets):
current_response = functor()
if not current_response:
print(request_target, "not set.")
return response_value
else:
response_value = current_response
return response_value
class Foo(object):
"""Mock the thingy ..."""
def __init__(self, a, b, c):
self._a, self._b, self._c = a, b, c
def __repr__(self):
return (
"Foo(" + str(self._a) + ", " + str(self._b) + ", " +
str(self._c) + ")")
def get_a(self):
return self._a
def get_b(self):
return self._b
def get_c(self):
return self._c
def function_1(self):
a = self.get_a()
b = self.get_b()
c = self.get_c()
r = None
if a:
r = a
if b:
r = b
if c:
r = c
else:
print("c not set.")
else:
print("b not set.")
else:
print("a not set.")
return r
def function_2(self):
a = self.get_a()
b = self.get_b()
c = self.get_c()
r = None
if not a:
print("a not set.")
return r
r = a
if not b:
print("b not set.")
return r
r = b
if not c:
print("c not set.")
r = c
return r
def function_3(self):
my_dictionary = OrderedDict()
my_dictionary['a'] = self.get_a()
my_dictionary['b'] = self.get_b()
my_dictionary['c'] = self.get_c()
# ...
r = None
for name in my_dictionary.keys():
value = my_dictionary[name]
if not value:
print("%s not set." % name)
return r
r = value
def main():
""""Drive the investigation."""
fixtures = (
(1, 42, 3.1415),
(0, 42, 3.1415),
(1, 0, 3.1415),
(1, 42, 0),
)
functors = (
function_1,
function_2,
function_3,
function_4,
)
for fixture in fixtures:
foo = Foo(*fixture)
print("\nFixture:", foo)
for i, functor in enumerate(functors, start=1):
print("Functor[%d]:" % (i,))
print(functor(foo))
if __name__ == '__main__':
main()
On my machine the fixtures produce the following behaviour/output when being called:
Fixture: Foo(1, 42, 3.1415)
Functor[1]:
3.1415
Functor[2]:
3.1415
Functor[3]:
None
Functor[4]:
3.1415
Fixture: Foo(0, 42, 3.1415)
Functor[1]:
a not set.
None
Functor[2]:
a not set.
None
Functor[3]:
a not set.
None
Functor[4]:
a not set.
None
Fixture: Foo(1, 0, 3.1415)
Functor[1]:
b not set.
1
Functor[2]:
b not set.
1
Functor[3]:
b not set.
1
Functor[4]:
b not set.
1
Fixture: Foo(1, 42, 0)
Functor[1]:
c not set.
42
Functor[2]:
c not set.
0
Functor[3]:
c not set.
42
Functor[4]:
c not set.
42
[Finished in 0.0s]
Here is what I would do without removing the print statements
def function1(self):
a = self.get_a()
b = self.get_b()
c = self.get_c()
r = None
inputValues = [a, b, c]
setValues = [i for i in inputValues if i]
for index, value in inputValues:
if len(setValues) <= index or setValues[index] != value:
print(f'{value} is not set.')
else:
r = value
return r
The function2 looks good enough to go.
Here my code:
class typeE:
def __init__(self):
self.u = 0
self.v = 0
self.w = 0
def readData():
global n
global m
global e
e = [typeE]
c = -2
f = open(fi, 'r')
for line in f:
print e[0]
c += 1
ln = [int(i) for i in line.split()]
if c == -1:
n = ln[0]
m = ln[1]
else:
e[c].u = ln[0]
e[c].v = ln[1]
e[c].w = ln[2]
f.close()
Do you have any idea how to make a record like this in Python?
type
typeE = record
u, v, w: longint;
end;
Python is not Pascal. You don't create an "array of records" but a "list of objects" (which can be instances custom class, but in your case could as well be plain dicts).
Also, globals are a bad idea whatever the language, it's always better to use true functions (functions that return a result depending on their input, instead of mutating or rebinding global variables).
The pythonic version of your code (error handling set aside) would look something like this:
class TypeE(object):
def __init__(self, u=0, v=0, w=0):
self.u = u
self.v = v
self.w = w
def __repr__(self):
return "<TypeE({u}, {v}, {w})>".format(**self.__dict__)
def to_int(line):
return [int(i) for i in line.strip().split()]
def read_data(src):
records = []
with open(src, 'r') as f:
headers = to_int(f.next())[:2]
for line in f:
records.append(TypeE(*ln[:3]))
return headers, records
def main():
(m,n), e = read_data("/path/to/your/file")
# now do something with m, n and e
print m, n, e
if __name__ == "__main__":
main()
The code which I wanna improved now looks something like below,
which f0 and f1(or more than 2 function) need the same variables.
I have to code about 50 lines to describe the variable setting at each function.
how can I do this more pythontic?
--f0.py
import csv
def gen(csv_f):
# var define
for row in csv.DictReader(open(csv_f)):
c += row['x']
...
a = 1
b = 2
...
# do sth in f0
xx = a + b
...
str = ...
return str
--f1.py
import csv
def gen(csv_f):
# var define
for row in csv.DictReader(open(csv_f)):
c += row['x']
...
a = 1
b = 2
...
# do sth in f1
xx = a*b + b
...
str = ...
return str
--genstr.py
from f0 import *
from f1 import *
f = open('xxx.x','w')
f.write(f0.gen(1)+f1.gen(1))
f.close()
(I don't really know how to use class, but I found this could help my problem
just describe maybe it will help understanding my question )
I try to do it with class, so i can access by inherit conf.
I know I can access by 'self.a', but is there any way I can direct use 'a' in the function?
--conf.py
class conf:
def __init__(self, csv_f):
# var define
for row in csv.DictReader(open(csv_f)):
c += row['x']
...
self.a = 1
self.b = 2
...
--f0.py
import conf
class f0(conf):
def __init__(self):
config.__init__(self, csv_f) #this line is not correct
def gen():
# var set
c = self.c
a = self.a
b = self.b
# do sth in f0
xx = a + b
...
str = ...
return str
--f1.py
import conf
class f1(conf):
def __init__(self):
config.__init__(self, csv_f) #this line is not correct
def gen():
# var set
c = self.c
a = self.a
b = self.b
# do sth in f1
xx = a + b
...
str = ...
return str
--genstr.py
from f0 import *
from f1 import *
f = open('xxx.x','w')
f.write(f0.gen(1)+f1.gen(1))
f.close()
The code is slightly confusing and i'm not sure what exactly you are trying, but here are some general help.
This code:
for row in csv.DictReader(open(csv_f)):
c += row['x']
Will append the content of coloumn x to c.
import conf
class f0(conf):
def __init__(self, csv_f):
super(f0,self).__init__(self) # Fixed
self.csv_f = csv_f
def gen(self):
# var set
c = self.c #
a = self.a
b = self.b
# do sth in f0
xx = a + b
Instead of c = self.c you can use self.c where ever you need c.
from f0 import *
from f1 import *
f = open('xxx.x','w')
f.write(f0(filename).gen()+f1(filename).gen())
f.close()
Your first two functions differ in these lines:
xx = a + b
vs.
xx = a*b + b
You can pass in this as as additional argument.
def gen(csv_f, f):
# var define
for row in csv.DictReader(open(csv_f)):
c += row['x']
...
a = 1
b = 2
...
# use the passed function
xx = f(a, b)
...
return str
l0 = lambda a, b: a + b
l1 = lambda a, b: a * b + b
# call gen with one of these lambdas as the second argument
gen(1, l0)
gen(1, l1)
I'd like to see the values of t when the values of AlfaSegundo, AlfaMinuto and AlfaHora are the same.
def PosicaodoponteiroSegundo(t):
AlfaSegundo = 6 * t % 360
return AlfaSegundo
def PosicaodoponteiroMinuto(t):
AlfaMinuto = t / 10 % 360
return AlfaMinuto
def PosicaodoponteiroHora(t):
AlfaHora = t / 120 % 360
return AlfaHora
a = PosicaodoponteiroSegundo(t)
b = PosicaodoponteiroMinuto(t)
c = PosicaodoponteiroHora(t)
def Instantes(a, b, c):
a = b
b = c
return t
print Instantes(a, b, c)
What should I do?
Thanks.
I do not think this does what you think it does
def Instantes(a, b, c):
a = b
b = c
return t
print Instantes(a, b, c)
Within the function, a, b, and c all refer to the values that you passed in. Effectively you could replace print Instantes(a, b, c) with print t
All you have to do here is say:
if a == b == c:
print t
EDIT:
Because you are using the mod, you can never reverse the function. What you can do instead is write a function that takes t and passes it to your other functions.
def some_function(t):
segundo = PosicaodoponteiroSegundo(t)
minuto = PosicaodoponteiroMinuto(t)
hora = PosicaodoponteiroHora(t)
if segundo == minuto == hora:
print(t)
a = PosicaodoponteiroSegundo(t) = (6 * t) % 360
b = PosicaodoponteiroMinuto = (t / 10) % 360
c = PosicaodoponteiroHora = (t / 120) % 360
for now you can probably ignore the modulo's
a = 6*t
b = t/10
c = t/120
this leads to solve for t S.T.
t = a/6.0
t = b*10
t = c*120
unfortunately this does ignore the modulo 360 which is likely unrecoverable as well as the truncation of your division so t=a/6.0 is likely your best bet