ste4lth
ste4lth

Reputation: 129

Is there a way how to get rid of arguments in python methods?

Is there a way how to simplify this static methods in python? I'm looking to reduce typing of the arguments every time I need to use a function.

class Ibeam:
  def __init__ (self, b1, tf1, tw, h, b2, tf2, rt, rb):
    self.b1 = b1
    self.tf1 = tf1
    self.tw = tw
    self.h = h
    self.b2 = b2
    self.tf2 = tf2
    self.rt = rt
    self.rb = rb

  def area (b1, tf1, tw, h, b2, tf2, rt, rb):
    dw = h - tf1 - tf2
    area = b1*tf1+tw*dw+b2*tf2+2*circularspandrel.area(rt)+2*circularspandrel.area(rb)
    return area

  def distToOriginZ (b1, tf1, tw, h, b2, tf2, rt, rb):
    dw = h - tf1 - tf2
    Dist = collections.namedtuple('Dist', 'ytf1 yw ytf2')
    dist = Dist(ytf1 = h - rectangle.centroid(b1,tf1).ez, yw = rectangle.centroid(tw,dw).ez + tf2, ytf2 = rectangle.centroid(b2,tf2))
    return dist

  def areaMoment (b1, tf1, tw, h, b2, tf2, rt, rb):
    dw = h - tf1 - tf2
    sum = (rectangle.area(b1, tf1)*Ibeam.distToOriginZ(b1, tf1, tw, h, b2, tf2, rt, rb).ytf1) + (rectangle.area(tw, dw)*Ibeam.distToOriginZ(b1, tf1, tw, h, b2, tf2, rt, rb).yw) + (rectangle.area(b2,tf2)*Ibeam.distToOriginZ(b1, tf1, tw, h, b2, tf2, rt, rb).ytf2)
    return sum

  def centroidZ (b1, tf1, tw, h, b2, tf2, rt, rb):
    ez = Ibeam.areaMoment (b1, tf1, tw, h, b2, tf2, rt, rb)/Ibeam.area(b1, tf1, tw, h, b2, tf2, rt, rb)
    return ez

Upvotes: 0

Views: 59

Answers (3)

Boendal
Boendal

Reputation: 2526

I'm not sure if it's what you are looking for:

But for me it looks like you want to have a class and use the functions in it.

class Ibeam:
  def __init__ (self, b1, tf1, tw, h, b2, tf2, rt, rb):
    self.b1 = b1
    self.tf1 = tf1
    self.tw = tw
    self.h = h
    self.b2 = b2
    self.tf2 = tf2
    self.rt = rt
    self.rb = rb

  def area (self):
    dw = self.h - self.tf1 - self.tf2
    area = self.b1*self.tf1+self.tw*dw+self.b2*self.tf2+2*circularspandrel.area(self.rt)+2*circularspandrel.area(self.rb)
    return area

  def distToOriginZ (self):
    dw = self.h - self.tf1 - self.tf2
    Dist = collections.namedtuple('Dist', 'ytf1 yw ytf2')
    dist = Dist(ytf1 =self. h - rectangle.centroid(self.b1,self.tf1).ez, yw = rectangle.centroid(self.tw,dw).ez + self.tf2, ytf2 = rectangle.centroid(self.b2,self.tf2))
    return dist

  def areaMoment (self):
    dw = self.h - self.tf1 - self.tf2
    sum = (rectangle.area(self.b1, self.tf1)*self.distToOriginZ().ytf1) + (rectangle.area(self.tw, dw)*self.distToOriginZ()) + (rectangle.area(self.b2,self.tf2)*self.distToOriginZ().ytf2)
    return sum

  def centroidZ (self):
    ez = self.areaMoment ()/self.area()
    return ez

Now you can do the following:

beam = Ibeam(1,1,1,1,1,1,1,1)
print(beam.area())
print(beam.distToOriginZ())
print(beam.areaMoment())
print(beam.centroidZ())

With this you don't have to write that many parameters and you use proper capsulation.

With this approach you create a Class Ibeam with properties. And in this approach you are even using this properties. Before you didn't use them at all. The disadvantage is you have to create a class before, if that is not what you want use the approach with default variable and declare it static.

Upvotes: 1

exhuma
exhuma

Reputation: 21737

When having functions with many arguments it might be useful to think about "related" arguments and group them together. For example, consider a function that calculates the distance between two points. You could write a function like the following:

def distance(x1, y1, x2, y2):
   ...
   return distance

print(distance(1, 2, 3, 4))

In that case, the values x1, y1 and x2, y2 are both very closely related together. you could group these together. Python gives you many options, some more expressive, some less expressive.

Your code examples look very similar, and I believe you could benefit from grouping them together.

The advantages of grouping related variables together are mainly that you reduce the number of required arguments (what you ask for), but most importantly it gives you a chance to document these variables by giving them better names.

"""
Simple Tuples
"""

def distance(point_a, point_b):
   x1, y1 = point_a
   x2, y2 = point_b
   ...
   return distance

print(distance((1, 2), (3, 4)))

This is a quick-win, but it is not very expressive. So you could spice this up with named-tuples (typed or untyped) or even a full-blown object. For example:

"""
Simple named tuples (very similar to tuples, but better error-messages/repr)
"""

from collections import namedtuple

Point = namedtuple('Point', 'x, y')

def distance(point_a, point_b):
   x1, y1 = point_a
   x2, y2 = point_b
   ...
   return distance

print(distance(Point(1, 2), Point(3, 4)))
"""
Typed named tuples (in case you want to use typing)
"""

from typing import NamedTuple

Point = NamedTuple('Point', [
   ('x', float),
   ('y', float),
])

def distance(point_a: Point, point_b: Point) -> float:
   x1, y1 = point_a
   x2, y2 = point_b
   ...
   return distance

print(distance(Point(1, 2), Point(3, 4)))
"""
Custom Object
"""

class Point:
   def __init__(self, x, y):
      self.x = x
      self.y = y

def distance(point_a: Point, point_b: Point) -> float:
   x1, y1 = point_a.x, point_a.y
   x2, y2 = point_b.x, point_b.y
   ...
   return distance

print(distance(Point(1, 2), Point(3, 4)))

Upvotes: 0

ldz
ldz

Reputation: 2215

You could use good default values if such exist.

def area(b1=None, tf1=None, tw=None, h=None, b2=None, tf2=None, rt=None, rb=None):
    ....

An even better solution would be to design your class in a way that it does not require so many parameters.

Upvotes: 1

Related Questions