Python Forum
Do I have to pass 85 variables to function?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Do I have to pass 85 variables to function?
#1
Have a problem with a function. I am reading from a data frame and when the condition is met, I am putting data into a two dimensional array. There are about 85 data points. Question is, must I pass the data points to the function or is there an easier way to accomplish this.

#LOAD HORSE DATA INTO 2 DIMENSION ARRAY FOR DATA PROCESSING
def load_horse_data():

	horse_array[horse_count][0] = race_number
	horse_array[horse_count][1] = todays_purse



#READ FILE AND PULL OUT HORSES AND HORSE INFO FOR SELECTED RACE AND TRACK
		for i in range(0,len(xx)):
			if int(xx[hcount][1])== int(race_number):			 
				horses_name.insert(hcount, xx[hcount][18])
				horse_saddle.insert(hcount, xx[hcount][97])	
				load_horse_data()
				horse_count +=1				
			hcount+=1	  
race number I have as a global in bottom function just not showing it. So no problem in upper function Nputting race number in the array. But todays_purse throws an error as not defined. Bow I have 85 data points that will be put in array just as I am with the two I have listed so far. Do I have to pass all 85 to the function before I can put them in the array?

Thanks
Reply
#2
Why do you have all these, presumably 85, separate variables in the first place? Why isn't your data already in some collection (array, dict, whatever is appropriate) that you just pass to the function(s) as required?
Reply
#3
They are in a dictionary. The dictionary is 64 lines long. In the dictionary I only need in the first race just 6 lines, which I am pulling out. And in each line of the dictionary there are 85 data points that either are factors unto their own, or several data points need to be combined to create a manufactured factor. Those factors will be used to get ratings for each horse based on their rank for each factor.
Reply
#4
When I try and pass xx which is a dataframe I believe, I get the following message.

def load_horse_data(xx):

	horse_array[horse_count][0] = xx[hcount][race_number]
	horse_array[horse_count][1] = xx[hcount][todays_purse]
error message:

$ python pyfuncs.py
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Milford\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "pyfuncs.py", line 138, in select_track
load_track_to_Handi()
File "pyfuncs.py", line 110, in load_track_to_Handi
load_horse_data()
TypeError: load_horse_data() missing 1 required positional argument: 'xx'
Reply
#5
The error is clear: you aren't passing an argument to the function when you call it.

Also, xx is a poor name, as it tells you nothing about what that variable is or what it's for.
Reply
#6
(Sep-26-2020, 01:34 AM)Milfredo Wrote: They are in a dictionary.

I'm not sure they are. Nothing in the code you've shown is a dictionary — you're exclusively using lists.

A dictionary (actually, a dict) is a distinct type in Python, it's not merely an n-dimensional table where you've assigned certain meanings to each of the columns. Dictionaries are key-value tables where the keys can be anything — you aren't restricted to numeric positions. If I were defining a dict for the horse data you've shown, I'd set it up as something like:

horses = {
    first_horse_name: {
        "saddle": horse1_saddle,
        "race_number": horse1_race_number,
        "todays_purse": horse1_todays_purse,
        },
    second_horse_name: {
        "saddle": horse2_saddle,
        "race_number": horse2_race_number,
        "todays_purse": horse2_todays_purse,
        },
    # etc...
    }
(Mind you, that's just based on the information you've shown as being stored — it doesn't sound to me like it would make sense to store todays_purse for each horse, since isn't that a property of the race, or the track, or something like that? If it's not specific to the horse, it shouldn't be stored with each horse, because what if the values end up different?)

What I've actually defined here is a dict of dicts, with the outer dict keyed by the horse's name. (Though you could choose a different key, like saddle# or an ID of some sort, and move "name" to be a key of the inner dict.) The value for each of those keys is another dict, containing the parameters for that horse.

There are a lot of advantages to that approach, but the primary one is that you can dereference parameters by key instead of needing to use magic numbers. So, something like the horse_array[horse_count][0] dereference you do to set the first horse's race_number would instead become:

horses[horse_name]["race_number"] = race_number
And you don't have to worry about race_number always being at the 0 index in an array (without any way to verify that the value of horse_array[horse_count][0] actually corresponds to the race number).

The items in a dict (meaning, the individual key-value pairs) can also be modified en masse using the update method of the dict. So, if I have a horses dict with existing data, and I want to change the race_number and saddle for first_horse_name, I can do this:

horses[first_horse_name].update({
    "saddle": new_saddle,
    "race_number": new_race_number,
    })
An existing horses[first_horse_name]["saddle"] or horses[first_horse_name]{"race_number"] will be changed, or new items will be added if they don't already exist, without the rest of the horses[first_horse_name] data or any of the rest of horses being affected.

(Sep-26-2020, 01:34 AM)Milfredo Wrote: I only need in the first race just 6 lines, which I am pulling out. And in each line of the dictionary there are 85 data points that either are factors unto their own, or several data points need to be combined to create a manufactured factor. Those factors will be used to get ratings for each horse based on their rank for each factor.

Then the basic design of your function is inverted. If you have data you're being passed in a table (which is not a dictionary), and you need to process that table row by row to pull out certain data, then you should be doing something like this:

def extract_horse_data(row):
    # horse_key might first be extracted from row
    # and stored to a local variable, e.g.
    horse_key = row[0]

    # Then, process the other useful list indexes
    horses[horse_key]["name"] = row[18]
    horses[horse_key]["saddle"] = row[97]
    # Which could also be written...
    if horse_key not in horses:
        horses[horse_key] = {}
    horses[horse_key].update({
        "name": row[18],
        "saddle": row[97],
        })

def process_xx_table(xx):
    # Python has enumerate() to avoid manually keeping
    # track of variables like your 'hcount'
    # It outputs a pair of (index, value) for each of the
    # items in a list
    for i, horse_row in enumerate(xx):
        extract_horse_data(horse_row)
        # horse_row == xx[i] each time through the loop
        # so if you need to know 'i', pass it in...
        #   extract_horse_data(i, row)
        # with the definition above becoming...
        #   def extract_horse_data(horse_count, row):
The basic idea here is, the data that's needed by a function, gets passed into the function. By passing the entire row (containing all of the necessary variables) in its raw form, then processing it inside the function, you avoid having to create and then pass 85 different individual variables.

I seem to have tricked myself into losing my ability to edit the previous post, so just as a correction to my last Python code block, the first function should read:

def extract_horse_data(row):
    # horse_key might first be extracted from row
    # and stored to a local variable, e.g.
    horse_key = row[0]
 
    if horse_key not in horses:
        horses[horse_key] = {}
    # Then, process the other useful list indexes
    horses[horse_key]["name"] = row[18]
    horses[horse_key]["saddle"] = row[97]
    # Which could also be written...
    horses[horse_key].update({
        "name": row[18],
        "saddle": row[97],
        })
(You'd also have to deal with the initial creation of horses itself as a dict, before/when calling the function for the first time. It would have to be a global variable, since there's no other way in the code I've shown that extract_horse_data would be able to access it. Details of that nature left as an exercise for the reader.)

BTW, whether or not you take any of the other advice, you should know that using the insert() list method to add values the way you're doing is a bad idea. insert() is used to do exactly that, insert a value between others in an existing list. If your indexes ever get out of step with the contents, things get confusing real quick:
>>> horse_names = []
>>> horse_names.insert(0, "Trigger")
>>> horse_names.insert(0, "Silver")
>>> horse_names.insert(3, "Seabiscuit")
>>> print(horse_names)
['Silver', 'Trigger', 'Seabiscuit']
>>> print(horse_names[3])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
If all you want to do is add data to the end of the list, use append() instead:
>>> better = []
>>> better.append("Trigger")
>>> better.append("Silver")
>>> better.append("Seabiscuit")
>>> print(better)
['Trigger', 'Silver', 'Seabiscuit']
Reply
#7
(Sep-25-2020, 05:06 AM)Milfredo Wrote: Have a problem with a function. I am reading from a data frame and when the condition is met, I am putting data into a two dimensional array. There are about 85 data points. Question is, must I pass the data points to the function or is there an easier way to accomplish this.
As you use Pandas then there is probably a way to this with methods of Pandas DataFrame.
The you do not write code like this,but let Pandas 100's method handle this in the DataFrame.
(Sep-26-2020, 01:34 AM)Milfredo Wrote: Those factors will be used to get ratings for each horse based on their rank for each factor
Just to give a example of what i mean.
import pandas as pd

horses = {
    "Name": ["Goodspeed", "Horse killer9", "Speedy youngster"],
    "Year": ["7", "10", "5"],
    "Rating": ["8.8", "6.8", "5.2"],
}

df = pd.DataFrame(horses)
print(df)
Output:
Name Year Rating 0 Goodspeed 7 8.8 1 Horse killer9 10 6.8 2 Speedy youngster 5 5.2
So when have a data in a DataFrame can to all kind filter/ratings/rank stuff,
and the as example send to a dictionary df.to_dict() or many other formats Json,Excel,csv,Sql,Html...ect when finish.
Doing some stuff inside the DataFrame.
>>> df['Rating_Rank'] = df['Rating'].rank(ascending = 1)
>>> df = df.set_index('Rating_Rank')
>>> df
                         Name Year Rating
Rating_Rank                              
3.0                 Goodspeed    7    8.8
2.0             Horse killer9   10    6.8
1.0          Speedy youngster    5    5.2
>>> 
>>> df = df.sort_index() 
>>> df = df.reset_index()
>>> df
   Rating_Rank              Name Year Rating
0          1.0  Speedy youngster    5    5.2
1          2.0     Horse killer9   10    6.8
2          3.0         Goodspeed    7    8.8
>>> 
>>> df.to_dict()
{'Name': {0: 'Speedy youngster', 1: 'Horse killer9', 2: 'Goodspeed'},
 'Rating': {0: '5.2', 1: '6.8', 2: '8.8'},
 'Rating_Rank': {0: 1.0, 1: 2.0, 2: 3.0},
 'Year': {0: '5', 1: '10', 2: '7'}}
Reply
#8
Thank you guys for the response. I will look at your response closely so I can understand what's going on and what I need to do. Here is what I am doing with the info from the raw files I download.

  h = {'track' : line[0],
                    'race_number' : line[2], 
                    'todays_surface' : line[6],
                     'race_type' : line[8], 
					'todays_purse' : line[11],
					 'trn_starts_curmeet' : line[28],
					'trn_wins_curmeet' : line[29],
					'jock_sts_curmeet' : line[34],
					'jock_wins_curmeet' : line[35],
					'trn_starts_prevyear' : line[1151],
					'trn_wins_prevyear' : line[1152],
					'jock_sts_prevyear' : line[1161],
					'jock_wins_prevyear' : line[1162],
					'trn_starts_curyear' : line[1146],
					'trn_wins_curyear' : line[1147],
					'jock_sts_curyear' :  line[1156],
					'jock_wins_curyear':  line[1157],
					'morn_line': line[43],
					'horse_name' : line[44],
					'year_of_birth' : line[45],
					'hstarts_todays_dist' : line[64],
					'hwins_todays_dist ' : line[65],
					'hstarts_todays_track' : line[69],
					'hwins_todays_track' :line[70],
					'hstarts_turf' : line[74],
					'hwins_turf' : line[75],
					'hstarts_mud' : line[79],
					'hwins_mud' : line[80],
					'hstarts_cur_yr' : line[84],
					'hwins_cur_yr' : line[85],
					'hstarts_prev_yr' : line[90],
					'hwins_prev_yr' : line[91],
					'hstarts_life' : line[96],
					'hwins_life' : line[97], 
					'days_since' : line[223],
					'power_rating' : line[250],
					'dist_yards1' : line[315],
					'dist_yards2' : line[316],
					'dist_yards3' : line[317],
					'dist_yards4' : line[318],
					'dist_yards5' : line[319],
					'dist_yards6' : line[320],
					'dist_yards7' : line[321],
					'dist_yards8' : line[322],
					'dist_yards9' : line[323],
					'dist_yards10' : line[324],
					'surface1' : line[325],
					'surface2' : line[326],
					'surface3' : line[327],
					'surface4' : line[328],
					'surface5' : line[329],
					'surface6' : line[330],
					'surface7' : line[321],
					'surface8' : line[332], 
					'surface9' : line[333],
					'surface10' : line[334],
					'entrants1' : line[345],
					'entrants2' : line[346],
					'entrants3' : line[347],
					'entrants4' : line[348],
					'entrants5' : line[349],
					'entrants6' : line[350],
					'entrants7' : line[351],
					'entrants8' : line[352],
					'entrants9' : line[353],
					'entrants10' : line[354],
					'first_call1' :  line[575],
					'first_call2' : line[576],
					'first_call3' : line[577],
					'first_call4' : line[578],
					'first_call5' : line[579],
					'first_call6' : line[580],
					'first_call7' : line[581],
					'first_call8' : line[582],
					'first_call9' : line[583],
					'first_call10' : line[584],
					'second_call1' : line[585],
					'second_call2' : line[586],
					'second_call3' : line[587],
					'second_call4' : line[588],
					'second_call5' : line[589],
					'second_call6' : line[590],
					'second_call7' : line[591],
					'second_call8' : line[592],
					'second_call9' : line[593],
					'second_call0' : line[594],
					'finish_Position' : line[615],
					'last_peed' : line[845],
					'speed_2back' : line[846],
					'speed_3back' : line[847],
					'speed_4back' : line[848],
					'speed_5back' : line[849],
					'speed_6back' : line[850],
					'speed_7back' : line[851],
					'speed_8back' : line[852],
					'speed_9back' : line[8853],
					'speed_10back' : line[854],
					'bestSpeed_Life' : line[1327],
					'bestSpeed_Fasttrack' : line[1177],
					'bestSpeed_turf' : line[1178],
					'bestSpeed_offtrack' : line[1179],
					'bestSpeed_dist' : line[1180],
					'race_conditions' : line[15],
					'todays_race_classification' : line[10], 
                    'saddle_cloth' : line[42]
                     
 
                 
                        }
Reply
#9
(Sep-26-2020, 01:28 PM)Milfredo Wrote:
            'dist_yards1' : line[315],
            'dist_yards2' : line[316],
            'dist_yards3' : line[317],
            'dist_yards4' : line[318],
            'dist_yards5' : line[319],
            'dist_yards6' : line[320],
            'dist_yards7' : line[321],
            'dist_yards8' : line[322],
            'dist_yards9' : line[323],
            'dist_yards10' : line[324],

One thing you might consider, for runs like this that always have the same number of data points, is to keep the dictionary element as a single list of N values. So,
h["dist_yards"] = [ line[315], line[316], .... line[324] ]

# Which, if they're all adjacent in the source data,
# you can even assign using a list slice:

h["dist_yards"] = line[315:324]
And so on for the other multi-value parameters. Then you'd just access them as,
h["dist_yards"][0] through h["dist_yards"][9]. (Or in any combinations, again using slices if appropriate:

first_three_dist_yards = h["dist_yards"][0:2]

Correction: I screwed up my slice syntax, as usual.

# Make that
h["dist_yards"] = line[315:325]  # Yes, one higher than the last element

# And
first_three_dist_yards = h["dist_yards"][0:3]
Reply
#10
I guess you take/parse this data from web-site?
Here some tricks info what Pandas can do.
So if any site has a table on there web-site,Pandas can pull out whole table or tables.
This way can save a lot work,bye trying to recreate the table manually.

So a demo just a random Horse site .
import pandas as pd
pd.set_option('display.expand_frame_repr', False)

df = pd.read_html("https://en.wikipedia.org/wiki/List_of_leading_Thoroughbred_racehorses")
df = df[0]

>>> df.head()
   Wins          Horse           Bred Details  Foaled                                 Pedigree and notes
0    54        Kincsem        Hungary    ch m    1874        Cambuscan (GB) x Water Nymph by Cotswold[9]
1    25   Black Caviar      Australia    br m    2006       Bel Esprit x Helsinge by Desert Sun (GB)[10]
2    19  Peppers Pride  United States    B.f.    2003   Desert God x Lady Pepper by Chili Pepper Pie[11]
3    18        Eclipse  Great Britain   Ch.c.    1764          Marske x Spilletta by Regulus[12][13][14]
4    18        Karayel         Turkey    B.h.    1970  Prince Tudor (GB) x Linda (TUR) by Cihangir (G...
So have have the whole table,check if some clean up is needed with .dtypes.
>>> df.dtypes
Wins                   int64
Horse                 object
Bred                  object
Details               object
Foaled                 int64
Pedigree and notes    object
dtype: object
So all is okay,as Wins and Folead has type int64.
The can start to doing stuff with the DataFrame.
How many horses has 15 or more wins after 1950?
>>> df[(df['Wins'] > 15) & (df['Foaled'] > 1950)]
   Wins          Horse           Bred Details  Foaled                                 Pedigree and notes
1    25   Black Caviar      Australia    br m    2006       Bel Esprit x Helsinge by Desert Sun (GB)[10]
2    19  Peppers Pride  United States    B.f.    2003   Desert God x Lady Pepper by Chili Pepper Pie[11]
4    18        Karayel         Turkey    B.h.    1970  Prince Tudor (GB) x Linda (TUR) by Cihangir (G...
7    16          Ribot  Great Britain    B.c.    1952   Tenerani (ITY) x Romanella (ITY) by El Greco[19]
Say i want Json format for this.
>>> df_1950 = df[(df['Wins'] > 15) & (df['Foaled'] > 1950)]
>>> df_1950.to_json()
('{"Wins":{"1":25,"2":19,"4":18,"7":16},"Horse":{"1":"Black '
 'Caviar","2":"Peppers '
 'Pride","4":"Karayel","7":"Ribot"},"Bred":{"1":"Australia","2":"United '
 'States","4":"Turkey","7":"Great Britain"},"Details":{"1":"br '
 'm","2":"B.f.","4":"B.h.","7":"B.c."},"Foaled":{"1":2006,"2":2003,"4":1970,"7":1952},"Pedigree '
 'and notes":{"1":"Bel Esprit x Helsinge by Desert Sun (GB)[10]","2":"Desert '
 'God x Lady Pepper by Chili Pepper Pie[11]","4":"Prince Tudor (GB) x Linda '
 '(TUR) by Cihangir (GB). Triple Crown winner.[15]","7":"Tenerani (ITY) x '
 'Romanella (ITY) by El Greco[19]"}}')

>>> import json
>>> 
>>> wins_after_1950 = df_1950.to_json()
>>> json.loads(wins_after_1950)
{'Bred': {'1': 'Australia',
          '2': 'United States',
          '4': 'Turkey',
          '7': 'Great Britain'},
 'Details': {'1': 'br m', '2': 'B.f.', '4': 'B.h.', '7': 'B.c.'},
 'Foaled': {'1': 2006, '2': 2003, '4': 1970, '7': 1952},
 'Horse': {'1': 'Black Caviar',
           '2': 'Peppers Pride',
           '4': 'Karayel',
           '7': 'Ribot'},
 'Pedigree and notes': {'1': 'Bel Esprit x Helsinge by Desert Sun (GB)[10]',
                        '2': 'Desert God x Lady Pepper by Chili Pepper Pie[11]',
                        '4': 'Prince Tudor (GB) x Linda (TUR) by Cihangir '
                             '(GB). Triple Crown winner.[15]',
                        '7': 'Tenerani (ITY) x Romanella (ITY) by El '
                             'Greco[19]'},
 'Wins': {'1': 25, '2': 19, '4': 18, '7': 16}}
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  How to pass variables from one class to another hobbyist 16 423 Sep-23-2021, 01:34 PM
Last Post: hobbyist
  Regex - Pass Flags as a function argument? muzikman 6 346 Sep-06-2021, 03:43 PM
Last Post: muzikman
  Possible to dynamically pass arguments to a function? grimm1111 2 610 Feb-21-2021, 05:57 AM
Last Post: deanhystad
  Pass by object reference when does it behave like pass by value or reference? mczarnek 2 869 Sep-07-2020, 08:02 AM
Last Post: perfringo
  print function help percentage and slash (multiple variables) leodavinci1990 3 854 Aug-10-2020, 02:51 AM
Last Post: bowlofred
  Pass integers to datetime.date function florian 3 972 Jul-18-2020, 04:43 AM
Last Post: scidam
  How to pass multiple arguments into function Mekala 4 961 Jul-11-2020, 07:03 AM
Last Post: Mekala
  Issues with storing variables outside of a function cerulean747 7 1,597 Apr-30-2020, 08:46 AM
Last Post: DeaD_EyE
  Pass Arguments to Function phillyfa 2 812 Mar-27-2020, 12:05 PM
Last Post: phillyfa
  Where to put the global keyword when assigning variables outside a function? new_to_python 8 1,208 Feb-09-2020, 02:05 PM
Last Post: new_to_python

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020