Defining dictionaries within classes by referencing lists [duplicate] - python

This question already has answers here:
Accessing class variables from a list comprehension in the class definition
(8 answers)
Closed 2 years ago.
Basically, why do these work:
class MyClass:
Dict={['A','B','C'][i]:{['a','b','c'][j]:[1,2,3][j] for j in range(3)} for i in range(3)}
and
class MyClass:
Table = ['A','B','C']
Dict={Table[0]:'a',Table[1]:'b',Table[2]:'c'}
but not this one?
class MyClass:
Table = ['A','B','C']
Dict={Table[i]:['a','b','c'][i] for i in range(3)}
I'm trying to consolidate a bunch of arrays, interpolation functions, and solvers by putting them all in classes. Each array contains a number of different properties so I figured the best way to sort this data was through nested dictionaries (Many of the tables aren't complete so I can't use numpy arrays or even lists very effectively because the indices change depending on the line of the data). I've worked out all the other kinks, but for some reason moving it into a class gives me an error:
NameError: name 'Table' is not defined
I'm an engineering student and basically only learned how to use scipy solvers and integrators; everything else is self taught. Don't be afraid to tell me I'm doing everything wrong :)

I think you are trying to do a Dictionary Comprehension, but weird enough, this message error you receive does not make much sense to me.
Anyway, with this implementation it worked just fine for me:
class MyClass:
Table = ['A','B','C']
Dict= {i:j for i,j in zip(Table, ['a','b', 'c'])}

This is a class variable + comprehension scope issue. Table is not defined inside your dictionary comprehension, and in the other definition which uses Table you are not doing a comprehension.
You may want to use __init__ here.

Related

When is it appropriate to organize code using a class with Python? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
While I have a good amount of experience using Python, I found that sometimes it's quite difficult to determine if relevant functions and attributes should be put inside a class. More specifically, I have a function that uses the attributes of the class, and the following functions sequentially use the returned value of the previous function. For example Function 1 --> Function 2 --> Function 3 and so forth with each function returning something.
I wish to understand if it makes sense to use a class in situations like this as it is a common occurrence with me. I want to make sure that the object (sales table) is created in a way that's logical and clean.
So far I've created just a simple class with some attributes and instance methods. I'm not sure how else I can go about it. I have looked up numerous posts on Stacks, articles and many other resources. I believe I have a decent understanding the purpose of a class but less so on when it's appropriate to use it.
To be clear, I'm not asking for help on the functions themselves or their logic (although I appreciate any suggestions!). I just want to know if using a class is the way to go. I did not include any code within the functions as I don't think their logic is relevant to my question (I can add if necessary!)
class SalesTable:
def __init__(self, banner, start_year, start_month, end_year, end_month):
"""These attributes act as filters when searching for the relevant data."""
self.banner = banner
self.start_year = start_year
self.start_month = start_month
if not end_year:
self.end_year = start_year
else:
self.end_year = end_year
if not end_month:
self.end_month = start_month
else:
self.end_month = end_month
def sales_periods(self):
"""Will create a dict with a key as the year and each year will have a list of months as the value. The
stated attributes are used ONLY here as filters to determine what years and months are included"""
pass
def find_sales_period_csv(self):
"""Using the dictionary returned from the function above, will search through the relevant directories and
subdirectories to find all the paths for individual csvs where the sales data is stored as determined by the
value in the dictionary and store the paths in a list"""
pass
def csv_to_df(self):
"""Using the list returned from the function above, will take each csv path in the list and convert them into a
dataframe and store those dateframes in another list"""
pass
def combine_dfs(self):
"""Using the list return from the function above, will concatenate all dfs into a single dataframe"""
def check_data(self):
"""Maybe do some checking here to ensure all relevant data concatenated properly (i.e total row count etc.)"""
Ideally I like to return a sales table through the last function (combine_dfs) following the sequence of functions. I can accomplish this task quite easily however, I'm not sure this is the best way I should structure my script or if it logically makes sense, despite it working as I want.
Since only sales_periods actually uses the instance attributes, and it returns a dict, not another instance of SalesTable, all the other methods can be moved out of the class and defined as regular functions:
class SalesTable:
def __init__(self, banner, start_year, start_month, end_year, end_month):
...
def sales_periods(self):
# ...
return some_dict
def find_sales_period_csv(dct):
return some_list
def csv_to_df(lst):
return some_list
def combine_dfs(lst):
return some_df
def check_data(df):
pass
And you'll call them all in a chained fashion:
x = SalesTable(...)
check_data(combine_dfs(csv_to_df(find_sales_period_csv(x.sales_periods()))))
Now take a closer look at your class: you only have two methods, __init__ and sales_periods. Unless __init__ does something expensive that you don't want to repeat (and you would call sales_periods on the same instance multiple times), the entire class can be reduced to a single function that combines __init__ and the sales_period method:
def sales_periods(banner, start_year, start_month, end_year, end_month):
...
return some_dict
check_data(combine_dfs(csv_to_df(find_sales_period_csv(sales_periods(...)))))
Ideally there are two main uses for a class:
1) To prevent repetition. If you create the same object multiple times than it should be in a class.
2) To group things together. It is a lot easier to read someones code if all the related functions and attributes are grouped together. This also makes maintainability and portability easier.
It is common for methods to call each other within a class since methods should ideally not be longer than 30 lines (though different groups have different standards). If you are calling methods only from within a class than that method should be private and you should append __ (two underscores) before that method.
If a bunch of data and functions seem to live together, which is to say you typically refer to them both at the same time, then you have good reason to think you may have an object on your hands.
Another good reason is if there's a natural name for the object. Weird, I know, but it really is a useful guiding principle.
Reading up on SOLID may also give you some food for thought.
People new to OOP tend to create too many classes (I know I did in the beginning). One problem with that is code readability: when code uses a custom class, it's often necessary to read the class definition to figure out what the class is supposed to do. If the code uses built-in types only, it's usually easier to figure out. Also, the complex internal state that is a natural feature of classes often is a source of subtle bugs and makes code more difficult to reason about.
This book is quite helpful
Each of your methods above look like they relate to the class. So lets say you had defined a bunch of functions outside the class, and you were passing the same set of ten variables as arguments to each of them. That would be a sign that they should be in the class. Accessing and modifying too many variables and passing them to other functions as arguments instead of having them as class attributes which get modified inside each of the methods would be a sign that you had failed to take advantage of one of the benefits of classes. In that book, I remember a section where they went into detail about various signs that your code needs OOP.

Avoiding Assigning Classes to Multiple Variables

I would like to make a program where I have multiple times I use a class. I don't want to have to create tons of variables such as through a11=animal() a12=animal(). I also would prefer not to have to have so many variables to manage even if they are created by an exec() in a loop. Is there any way to assign classes to dictionary key, list places, or use another easy way to manage them. Thanks!
You should be able to create instances of classes with any data structure. For example:
my_list = []
for i in range(10):
#Animal() is a class you've defined elsewhere
my_list.append(Animal())
Now the my_list variable should contain 9 instances of your Animal class
You also assign these to a dictionary, if that is what you want.

Python - Instantiating lists,dicts, and objects with a string [duplicate]

This question already has answers here:
Using a string variable as a variable name [duplicate]
(3 answers)
Closed 6 years ago.
Python 3.4.2 question, I have extensively looked for an answer to this, cannot find it.
I am trying to create python objects (or whatever you would call lists, dicts, and classe/object instantiations) by assigning strings to the definition. Or put differently, I want to use strings on the left hand side of the assign equation.
For instance, if we have a class, and an assignment/instantiation:
class char_info:
def __init__(self):
self.name = 'Joe'
self.mesh = 'Suzanne'
newchar = char_info()
print (newchar.name)
Joe
I would like to use using a string from another source (say a list) as the instantiated name, instead of "newchar". However, I am not sure the syntax. I need to reference this string on the left hand side of the equation. Furthermore, how do I reference this in later code since I wouldn't know the name beforehand, only at runtime?
Obviously this doesn't work:
list = ['Bob', 'Carol', 'Sam']
# list[0] = char_info() #this doesn't work, it would
# try assigning the value of char_info() to the item in [0]
str(list[0]) = char_info() #also doesn't work, obviously
print (str(list[0]) #obviously this is wrong, but how do you reference?
location: :-1
Error: File "\Text", line 2
SyntaxError: can't assign to function call
What I want is to have say, a loop that iterates over a list/dict and uses those strings to instantiate the class. Is there any way to do this? Special syntax I am not aware of?
By the way, this same thing should be the solution to do the same thing with creating list names, dict names, etc. Heck, even something simple like enumerating a variable name or assigning variables out of a list. How do you dynamically define the assignment name?
You can use exec i.e. exec(list[0] + "=char_info()") but this is a bad idea. Using a dictionary is better:
chars = {}
chars[list[0]] = char_info()
What I want is to have say, a loop that iterates over a list/dict and
uses those strings to instantiate the class. Is there any way to do
this?
class char_info:
def __init__(self, name):
self.name = name
list_names = ['Bob', 'Carol', 'Sam']
list_char_info = [char_info(name) for name in list_names]
The above code will instantiate a class for each name in the list of names

What are the benefits of using objects over using dict pseudo-objects? [duplicate]

This question already has answers here:
Dictionary vs Object - which is more efficient and why?
(8 answers)
Closed 9 years ago.
Refer to the following code as an example:
import numpy as np
N = 200
some_prop = np.random.randint(0,100, [N, N, N])
#option 1
class ObjectThing():
def __init__(self, some_prop):
self.some_prop = some_prop
object_thing = ObjectThing(some_prop)
#option 2
pseudo_thing = {'some_prop' : some_prop }
I like the structure that option 1 provides, it makes the operation of an application more rigid and whatnot. However, I'm wondering if there are other more absolute benefits that I'm not aware of.
The obvious advantage of using objects is that you can extend their functionality beyond simply storing data. You could, for instance, have two attributes, and define and __eq__ method that uses both attributes in some way other than simply comparing both of them and returning False unless both match.
Also, once you've got a class defined, you can easily define new instances of that class that will share the structure of the original, but with a dictionary, you'd either have to redefine that structure or make a copy of some sort of the original and then change each element to match the values you want the new pseudo-object to have.
The primary advantages of dictionaries are that they come with a variety of pre-defined methods (such as .items()), can easily be iterated over using in, can be conveniently created using a dict comprehension, and allow for easy access of data "members" using a string variable (though really, the getattr function achieves the same thing with objects).
If you're using an implementation of Python that includes a JIT compiler (e.g. PyPy), using actual objects can improve the compiler's ability to optimize your code (because it's easier for the compiler to reason about how members of an object are utilized, unlike a plain dictionary).
Using objects also allows for subclassing, which can save some redundant implementation.

Best way to define multidimensional dictionaries in python? [duplicate]

This question already has answers here:
What is the best way to implement nested dictionaries?
(22 answers)
Closed 9 years ago.
I'm currently using the method below to define a multidimensional dictionary in python. My question is: Is this the preferred way of defining multidimensional dicts?
from collections import defaultdict
def site_struct():
return defaultdict(board_struct)
def board_struct():
return defaultdict(user_struct)
def user_struct():
return dict(pageviews=0,username='',comments=0)
userdict = defaultdict(site_struct)
to get the following structure:
userdict['site1']['board1']['username'] = 'tommy'
I'm also using this to increment counters on the fly for a user without having to check if a key exists or is set to 0 already. E.g.:
userdict['site1']['board1']['username']['pageviews'] += 1
Tuples are hashable. Probably I'm missing the point, but why don't you use a standard dictionary with the convention that the keys will be triples? For example:
userdict = {}
userdict[('site1', 'board1', 'username')] = 'tommy'
You can create a multidimensional dictionary of any type like this:
from collections import defaultdict
from collections import Counter
def multi_dimensions(n, type):
""" Creates an n-dimension dictionary where the n-th dimension is of type 'type'
"""
if n<=1:
return type()
return defaultdict(lambda:multi_dimensions(n-1, type))
>>> m = multi_dimensions(5, Counter)
>>> m['d1']['d2']['d3']['d4']
Counter()
This is a pretty subjective question from my perspective. For me, the real question would be at what point do you promote this nested data structure to objects with methods to insulate you from changes. However, I've been known to create large prototyping namespaces with the following:
from collections import defaultdict
def nesteddict():
return defaultdict(nesteddict)
This is highly subjective - but if your dict is getting to be more than 2-n deep, I would revert to creating a class and defining methods/properties to do what you want.
I think your end goal would be to create a "multi-column" data structure so you can store any number of attributes for a particular object (in this case, a site). Creating a site class would accomplish that and then you can stick instances wherever you would any other object (variable) - with some noted exceptions.

Categories

Resources