code critique requested - just 60 lines

Lie Ryan lie.1296 at gmail.com
Thu Oct 2 14:03:08 EDT 2008


On Thu, 02 Oct 2008 07:51:30 -0700, Terrence Brannon wrote:

> Hi, I would like some feedback on how you would improve the following
> program:
> http://www.bitbucket.org/metaperl/ptc_math/src/21979c65074f/payout.py
> 
> Basically, using non-strict dictionary keys can lead to bugs, so that
> worried me. Also, I'm not sure that my code is as crisp and concise as
> it could be. I also did not like the long string representation in the
> Scenerio class. It is hard to read and error-prone to code.
> 
> Any feedback on how you would've written this differently is welcome,
> either by commenting below, or by checking out the repo and checking it
> back in!
> 
> class Rates:
> 
>     def __init__(self, per_click, per_ref_click):
>         self.per_click = per_click
>         self.per_ref_click = per_ref_click

You could use a better name, something that contains "price" or "cost" or 
something on that line, it is not immediately obvious what is per_click.

>     def __str__(self):
>         return 'per_click: %.2f per_ref_click: %.2f' %
> (self.per_click, self.per_ref_click)
> 
> 
> ad_rate = 200 # 2 dollars for 100 clicks
> 
> # http://code.activestate.com/recipes/278259/ def sumDict(d):
>     return reduce(lambda x,y:x+y, d.values())
> 
> 
> rates = {}
> rates['std']  = Rates(per_click=1,    per_ref_click=0.5) rates['vip']  =
> Rates(per_click=1.25, per_ref_click=1.25)

It's not a really good idea to interleave module-level code and class/
function declarations. Python's code usually put all module-level code 
below all declarations. (of course there are exceptions too, such as 
higher level functions, although now there are decorators to avoid it)

> class Scenario:
> 
> 
> 
>     def __init__(self, std_clicks, vip_clicks, upline_status):
>         self.clicks = {}
>         self.payout = {}
>         self.ad_rate = 200
> 
>         self.clicks['std'] = std_clicks
>         self.clicks['vip'] = vip_clicks
>         self.upline_status = upline_status
> 
>     def calc_profit(self):
>         for member_type in rates:

Global variables... avoid them unless you have to...
It's better (in this case) to pass rates to the __init__ function.

>             self.payout[member_type] = self.clicks[member_type] *
> rates[member_type].per_click
>         if self.upline_status is None:
>             self.payout['upline'] = 0
>         else:
>             self.payout['upline'] = sumDict(self.clicks) *
> rates[upline_status].per_ref_click
>             #print "rates: %s self.clicks: %d upline payout: %.1f\n" %
> (rates[upline_status], sumDict(self.clicks), self.payout['upline'])
>         return ad_rate - sumDict(self.payout)
> 
> 
>     def __str__(self):
>         profit = self.calc_profit()
>         return 'upline_status: %s upline_payout: %.1f\n\tstd_clicks:
> %d std_payout %.1f vip_clicks: %d vip_payout: %.1f\n\t\tProfit: %.1f \n'
> % (self.upline_status, self.payout['upline'], self.clicks['std'],
> self.payout['std'], self.clicks['vip'], self.payout['vip'], profit)

Ewww.... NEVER WRITE A LINE THAT LONG... (and with \n)
Instead python have multi-line string: '''blah blah''' or """blah blah"""
 
A good practice is to limit a line to be < 80 chars.

> scenario = []
> 
> for upline_status in [None, 'std', 'vip']:

rather than using None, you should use another string (perhaps 'N/A', 
'Nothing'), this way the code in your class above wouldn't have to 
special case None.

>     for vip_clicks in [0, 25, 50, 75, 100]:
>         std_clicks = 100 - vip_clicks
>         scenario.append(Scenario(std_clicks, vip_clicks,
> upline_status))
> 
> # really, we could've printed the objects as they were made, but for
> debugging, I kept creation and
> # printing as separate steps
> for s in scenario:
>     print s

Separating object creation (model) and printing (view) is a good thing, 
it's a step toward MVC (Model, View, Controller).

Your code could use some documentation/comments.




More information about the Python-list mailing list