6
\$\begingroup\$

I'm writing a Python script to randomly generate C functions. This is my first time using classes in Python and I'm basically doing my best to pretend I'm using Java.

I'm looking for a review of my OOP, Python style, and in general whether or not I'm doing things in the "Pythonic" way, whatever that means.

import random
import sys
import string
# writes text to a stored outputString
# fetch the outputString later for outputting
class Output:
 def __init__(self):
 self.clear()
 def clear(self):
 self.outputString = ''
 self.__lineStart = True
 self.lineCount = 0
 self.nestingLevel = 0 
 def __write(self, str):
 self.outputString += str 
 def line(self):
 self.__write('\n')
 self.__lineStart = True
 self.lineCount += 1
 def output(self, str):
 # start each line with tabs equal to nesting level 
 if(self.__lineStart == True):
 for q in range(0, self.nestingLevel):
 self.__write('\t')
 self.__lineStart = False
 self.__write(str)
 def incNesting(self):
 self.nestingLevel += 1
 def decNesting(self):
 self.nestingLevel -= 1
class Variables:
 def __init__(self, varCount):
 if varCount > 26:
 raise Exception('Don\'t you think you\'re being a bit too aggressive?')
 self.varCount = varCount
 lowercase = list(string.ascii_lowercase)
 self.variables = lowercase[0:varCount]
 def Rand(self, count = 1):
 if count > self.varCount:
 raise Exception('Variables.Rand requested more variables than available')
 elif count == 1:
 return random.choice(self.variables)
 elif count > 1:
 return random.sample(self.variables, count)
 else:
 raise Exception('Variables.Rand invalid argument')
 def InitStatement(self, out):
 out.output('int ')
 vars = []
 for var in self.variables:
 vars.append('%s = %i' % (var, random.randint(-0xFFFFFFF, 0xFFFFFFF)))
 out.output(', '.join(vars))
 out.output(';')
 out.line() 
class Action:
 def __init__(self, variables, output):
 self.variables = variables
 self.out = output
 self.labelCount = 0
class ControlSelector:
 @staticmethod
 def RandomControl(output, variables):
 controlType = random.choice(ControlType.implementedTypes)
 return ControlType.Make(controlType, output, variables)
class ControlType:
 STATEMENT = 1
 CONDITIONAL = 2
 GOTO = 3
 CALLGEN = 4
 CALLREAL = 5
 CALLAPI = 6
 STOP = 7
 allTypes = [STATEMENT, CONDITIONAL, GOTO, CALLGEN, CALLREAL, CALLAPI, STOP]
 implementedTypes = [STATEMENT, CONDITIONAL, STOP]
 @staticmethod
 def Make(controlType, output, variables): # factory pattern .. I think
 if(controlType == ControlType.STATEMENT):
 return StatementControl(output, variables)
 elif(controlType == ControlType.CONDITIONAL):
 return ConditionalControl(output, variables)
 elif(controlType == ControlType.STOP):
 return StopControl(output, variables)
 else:
 raise Exception('ControlType.Make bad argument')
 def __init__(self, output, variables):
 self.out = output
 self.variables = variables
 def Exec(self):
 raise NotImplementedError("")
 def PutCode(self): 
 control = ControlSelector.RandomControl(self.out, self.variables)
 control.Exec()
class PutCodeControl(ControlType):
 def Exec(self):
 self.PutCode()
class StatementControl(ControlType):
 def PutAssignment(self):
 dest, src = self.variables.Rand(2)
 self.out.output(src + ' = ' + dest + ';')
 self.out.line() 
 def Exec(self):
 self.PutAssignment()
 self.PutCode()
class ConditionalControl(ControlType):
 def PutConditional(self):
 first, second = self.variables.Rand(2)
 self.out.output('if(')
 self.out.output(first + ' == ' + second)
 self.out.output('){')
 self.out.line() 
 def PutCloseBrace(self):
 self.out.output('}')
 self.out.line()
 def PutIf(self):
 self.PutConditional()
 self.out.incNesting()
 self.PutCode()
 self.PutCloseBrace()
 self.out.decNesting() 
 def Exec(self):
 self.PutIf()
 self.PutCode()
class StopControl(ControlType):
 def Exec(self):
 return
class Function:
 totalFuncCounter = 0
 def __init__(self):
 self.funcNum = Function.totalFuncCounter
 Function.totalFuncCounter += 1
 self.variables = Variables(8)
 self.out = Output()
 self.name = 'RandFunc' + str(self.funcNum)
 self.action = Action(self.variables, self.out)
 def __FunctionHeader(self):
 self.out.output('int ' + self.name + '()')
 self.out.line()
 self.out.output('{')
 self.out.line()
 def __FunctionFooter(self):
 retval = self.variables.Rand()
 self.out.output('return ' + retval + ';')
 self.out.line()
 self.out.output('}')
 self.out.line() 
 def __Generate(self): 
 # int functionname()
 # {
 self.__FunctionHeader()
 # int a = 1, b = 2, etc
 self.variables.InitStatement(self.out)
 # [function body]
 PutCodeControl(self.out, self.variables).Exec()
 # return a;
 self.__FunctionFooter()
 def Generate(self, minLines = None):
 if minLines == None:
 minLines = 1 # < 1 will cause errors
 while self.out.lineCount < minLines:
 self.out.clear()
 self.__Generate()
 def OutputString(self):
 return self.out.outputString
def PrintLongFunction():
 func = Function()
 func.Generate(minLines = 50)
 sys.stdout.write(func.OutputString())
if __name__ == "__main__":
 PrintLongFunction()

Sample output is available here.

200_success
145k22 gold badges190 silver badges478 bronze badges
asked May 10, 2014 at 19:26
\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

Welcome to python :)

pep8

If you want to go "pythonic" you may want to read pep8. It is the common coding guideline in the world of python.

Python Version

I assume you are writing python3 (your code works in 2.x and 3.x). If you are targeting 2.x you should add explicit inheritance from object. (keyword: new-style classes)

Doc-Strings

Doc-strings (the python equivalent to java-doc comments) are strings inside the block you comment:

class Output:
 """writes text to a stored outputString
 fetch the outputString later for outputting"""

underscores

def __write(self, str):
 self.outputString += str

In your use case there is no reason to prefix functions with __. It is not just a convention but does have a meaning for the interpreter as well.

shadowing built-in

Don't use str as variable name. There is a built-in type called str.

ControlSelector.RandomControl

If you want a function you make a function - not a method. There is no reason for having the class ControlSelector.

def random_control(output, variables):
 controlType = random.choice(ControlType.implementedTypes)
 return ControlType.Make(controlType, output, variables)

minLines == None

The line

if minLines == None:

was suggested to be replaced with

if not minLines:

be aware that this changes the behavior in case of Generate(minLines=0) since if not 0 is True while 0 == None evaluates to False. If you want to check for None use is:

if minLine is None:

The __main__ pattern

if __name__ == "__main__":
 PrintLongFunction()

Awesome. Using the __name__ == "__main__" pattern is something you should get used to. Great start.

answered May 13, 2014 at 16:05
\$\endgroup\$
3
\$\begingroup\$

In class Output:

def output(self, str):
 # start each line with tabs equal to nesting level 
 if(self.__lineStart == True):
 for q in range(0, self.nestingLevel):
 self.__write('\t')
 self.__lineStart = False
 self.__write(str)

can be rewritten as

def output(self, str):
 if self.__lineStart:
 self.__write('\t' * self.nestingLevel)
 self.__lineStart = False
 self.__write(str)

You thus remove the useless parenthesis of if condition and make the code shorter and cleaner.

You also can rewrite

Exception('Don\'t you think you\'re being a bit too aggressive?') 

as

Exception("Don't you think you're being a bit too aggressive?")

Some list comprehension :

vars = []
for var in self.variables:
 vars.append('%s = %i' % (var, random.randint(-0xFFFFFFF, 0xFFFFFFF)))

is equivalent to

vars = ['%s = %i' % (var, random.randint(-0xFFFFFFF, 0xFFFFFFF))
 for var in self.variables]

Replace

if minLines == None:

with

if not minLines:
answered May 11, 2014 at 4:39
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.