Replacing variable with function/class indicating dynamic value - python

In my program, I draw some quads. I want to add the functionality for them to scale up, then down, then go back to being static (to draw attention). In the quads I have:
self.scale = 10
Making scale change according to sin would be nice. But adding frequency, amplitude and logic to my already bloated quad class is something I take as a challenge to avoid.
Something like this:
class mysin:
def __init__(self):
self.tick = 0.0
self.freq = 1.0
self.ampl = 1.0
def update(self, amount):
self.tick += amount
def value(self):
return math.sin(self.tick)
That class would also add itself to the logic system (getting update calls every frame). I would then do:
quad.scale = 10 # for static quad
quad.scale = mysin() # for cool scaling quad
The problem is that some calculations expect scale to hold a value. I could of course add another class where value() returns a (previously saved) constant value and adapt all the calculations.
What I want to know now is... does this have a name, is it a valid technique? I read the wiki article on functional programming and this idea sprung to mind as a wacky implementation (although Im not sure it qualifies as FP). I could very well have been driven mad by that article. Put me back in line fellow coders.

The distinction between
quad.scale= 10
and
quad.scale= MySin()
Is minor. Within the Quad class definition the "scale" attribute can be a property with proper getter and setter functions.
class Quad( object ):
#property
def scale( self ):
return self._scale
#scale.setter
def set_scale( self, value ):
# handle numeric and MySin() values appropriately.
Alternate version with the explicit property function (which I prefer).
class Quad( object ):
def get_scale( self ):
return self._scale
def set_scale( self, value )
# Handle numeric and MySin() values
scale = property( get_scale, set_scale )
Any other class should NOT know or care what type of value scale has. If some client does this
quad.scale * 2
Then you have design issues. You haven't properly encapsulated your design and Quad's client classes are too friendly with Quad.
If you absolutely must do this -- because you can't write a method function of Quad to encapsulate this -- then you have to make MySin a proper numeric class so it can respond to quad.scale * 2 requests properly.

It sounds like you want your quads to be dumb, and to have an animator class which is smart. So,here are some suggestions:
Give the quads an attribute which indicates how to animate them (in addition to the scale and whatever else).
In an Animator class, on a frame update, iterate over your quads and decide how to treat each one, based on that attribute.
In the treatment of a quad, update the scale property of each dynamically changing quad to the appropriate float value. For static quads it never changes, for dynamic ones it changes based on any algorithm you like.
One advantage this approach is that it allows you to vary different attributes (scale, opacity, fill colour ... you name it) while keeping the logic in the animator.

It's sort of like lazy-evaluation. It is definitely a valid tecnique when used properly, but I don't think this is the right place to use it. It makes the code kind of confusing.

It sure is a valid technique, but a name? Having an object.value() instead of an int? Uhm. Object orientation? :)
If the methods that use this value requires an integer, and won't call any method on it, you could in fact create your own integer class, that behaves exactly like an integer, but changes the value.

Related

Django: DRY code with property and queryset that have the exact same role?

In my Django code, for OrderedArticle objects I need to compute a hist_price which is the multiplication of 2 fields: hist_unit_price * quantity.
The first way I did it was a simple property:
class OrderedArticle(Model):
#property
def hist_price(self):
return self.hist_unit_price * self.quantity
Then, I realised that when I need to make extensive computing of these prices, I can't use this property for performance reason, and instead I must compute hist_price at a database level. That's why I wrote a custom queryset for this:
class OrderOperationQuerySet(Queryset):
#staticmethod
def _hist_price(orderable_field): # can be an OrderedArticle or another object here
return ExpressionWrapper(
F(f'{orderable_field}__hist_unit_price') * F(f'{orderable_field}__quantity'),
output_field=DecimalField())
Currently, both hist_price property and _hist_price queryset are used in my code.
Question
This works well, but I'm annoyed to write the same business logic twice. I have a feeling I'm not doing it "the right way" here.
I think I should ensure at a code level, that no matter if I use the property or the queryset, it always returns the same result.
In this specific case, the business logic is a simple multiplication between two decimals, so it should be OK, but I'll have other cases in my code where it's way more complex.
Do you see a way to improve my code? Thanks.
This idea is similar to "hybrid attributes" from SQLAlchemy which have been asked about before - I wasn't super satisfied with any of the answers from that chain of threads (stuff like storing this computed value in an extra field on the table and always making sure to keep it updated).
You could have some internal function that your property and ExpressionWrapper function both use, as long as the required operators are overloaded to accept either the actual values or the F() objects (e.g. basic mathematical operators).
def multiplication(x, y):
return x * y # trivial here but it could be any mathematical expression really
def _hist_price(orderable_field):
return ExpressionWrapper(
multiplication(
F(f"{orderable_field}__hist_unit_price"),
F(f"{orderable_field}__quantity")
),
output_field=DecimalField()
)
#property
def hist_price(self):
return multiplication(self.hist_unit_price, self.quantity)
If it gets more complex than basic numerical operations in one of these hybrid functions and you want to avoid duplicate business logic, you would need to write a wrapper func that could resolve to the correct output using the python function for the property caller, and the function that can operate on F objects for the query-set caller to maintain operator overloading. But this will lead to code which introspects arguments to work out what to do, which can be unintuitive, so it's a trade off either way really.
In rough pseudocode one of these custom functions would be like
def _hybrid_lower(value):
if isinstance(value, F): # maybe F would be sufficient or some other class higher in the hierarchy
# https://docs.djangoproject.com/en/2.2/ref/models/expressions/#func-expressions
return Func(value, function='LOWER')
else:
return value.lower()
and then you could use this custom function in your function that the property and queryset both call. Some duplication of code might not be the worst trade-off if you do start needing really complex functions as both database operations and Python.

Getter/setter but for nested attributes?

Suppose I have two classes. The simple Square class:
class Square:
def __init__(self, side):
self.side = side
And the slightly more complex MyClass class:
class MyClass:
def __init__(self, square=None):
if square is None:
self.square = Square()
else:
self.square = square
self.rounded_side = round(self.square.side)
I instantiate a MyClass object like so:
myObj = MyClass()
In this situation, how can one achieve the following behavior?
Changing myObj.rounded_side to X, automatically changes myObj.square.side also to X.
Changing myObj.square.side to X, automatically changes myObj.rounded_side to round(X).
If possible, in a way that doesn't require any modifications to the Square class (this is a simplified version of the problem I'm currently facing; in the original version, I don't have access to the code for Square).
What I tried so far:
My first attempt was to transform rounded_side into a property. That makes it possible to obtain behavior 1. However, I fail to see how I can transform square also into a property, in a way that makes it possible to obtain behavior 2.
I also thought about making MyClass inherit from Square, so that both attributes are in the same depth, but then I'd lose some the desired structure of my class (I rather have the user access myObj.square.side, than myObj.side)
If someone is interested, the actual problem I'm facing:
I'm writing a game in pygame, and my Player class has an attribute for its position, which is an array with two floats (2D position). This is used for determining where the player is, and for deciding how to update it's position in the next update step of the game's physics.
However, I also want to have a Rect attribute in the Player class (which holds the information about a rectangle around the player's image), to be used when displaying the player in the screen, and when inferring collisions. The Rect class uses integers to store the position of the rectangle (pixel coordinates).
So as to be able to store the position information of the player in a float, but also use the Rect class for convenience, I thought about having this dependency between them, where changing one alters also the other accordingly.
As you've said, make rounded_side a property, but have it access the value in self.square for both getting and setting.
#property
def rounded_side(self):
return self.square.side
#rounded_side.setter
def rounded_side(self, side):
self.square.side = side
Now, setting rounded_side will use the setter which sets the value in square; setting the value on square directly will mean that it would be looked up from there by the property getter.

How can I combine (or make operations) between attributes of different classes (without specifying instances yet)?

First of all, I am a total newbie. Thanks for your patience.
I am designing a piece of software to calculate insulation materials and amounts on different houses.
I have a class House(), which holds attributes like roof_area and wall_area.
I have a class Insulator(), which holds attributes like thickness and area (the area the packaged material covers)
Now I want to know how many packages of the insulator I should buy in order to cover the whole roof area.
So, the operation would be:
House.roof_area / Insulator.area = insulator_packages_needed_for_roof
The thing is I can't do that operation:
AttributeError: type object 'House' has no attribute 'roof_area'.
Of course I could do it a an instance scope, but I don't want to specify an instance yet, as this operation should be done for any instance of the Class that gets build in the future. Should I use inheritance? My feeling is that, given that Insulator and House are totally different things, they shouldn't be mixed by inheritance, but I am just a beginner.
It doesn't make any sense to try to compute the number of insulation packages you need to cover the roof of a house, without using any instances of your House or Insulator classes. It only makes sense if you have one instance of each.
You can, however, write the code to do the calculation before you've created the instances. Just put it in a function that takes the instances as arguments:
def roof_insulation_packages(house, insulator): # args are instances of House and Insulator
return house.roof_area / insulator.area # do the calculation and return it
It might make more sense for the function to be a method of one of the classes. I'd even suggest that Insulator instances might be a good candidates to be instance attributes of the House. That would look something like this:
class House():
def __init__(self, roof_area, roof_insulator, wall_area, wall_insulator):
self.roof_area = roof_area
self.roof_insulator = roof_insulator
self.wall_area = wall_area
self.wall_insulator = wall_insulator
def calculate_roof_insulation_packages(self):
return self.roof_area / self.roof_insulator.area
def calculate_wall_insulation_packages(self, insulator):
return self.wall_area / self.wall_insulator.area
You'd create the house instance with something like this (I'm making up the arguments to the Insulator class, so don't pay too much attention to that part):
good_roof_insulation = Insulator(4, 5) # nonsense args
cheap_wall_insulation = Insulator(5, 12)
my_house = House(100, good_roof_insulation, 87, cheap_wall_insulation)
If you want to use attributes without creating an instance you should use class attributes.
class House(object):
roof_area = 10 # Or whatever you see fit.
roof_surface = 20
class Insulator(object):
thickness = 10 # Or whatever you see fit.
surface = 20
This way you can access the attributes by typing 'House.roof_area' for example.
Although, I don't see why you cannot create an instance. It would prevent harcoding in class attributes and would in your case be much easier.
Also, your operation is not valid syntax, but maybe you just showed pseudo-code. Proper syntax would be:
insulator_packages_needed_for_roof = House.roof_area / Insulator.area

Looking for a data type able to hold only specific values

I have recently started with Python again, and I am trying to write a module where lots of problems of the following kind occur:
An object Problem can hold a variable Unit. Unit can only be either "inches", "millimeters" or "meters".
The module is supposed to be used by others, so I want the most easily usable solution to this. If possible I want the user to receive an error if they try to assign anything but one of those values.
I see this would be possible with objects where I define a unitClass class that inherits to daughter classes inchesClass, millimetersClass and metersClass. I would then make an instance of each, that the user can assign to the variable in question. But I think this might be confusing, unless that is a standard way to go about such a problem?
The other solution I came up with was set methods but since I don't use them for other variables, I wanted to avoid them in this case as well if possible.
Is there another way to do this using just the modules provided by a standard python installation?
Regards,
RTT
In other languages (namely java), this kind of structure is called an enum or enumeration. Specifically because you enumerate the possible values for something.
In python 3, you can import enum and use it like so:
from enum import Enum
class Color(Enum):
red = 1
green = 2
blue = 3
There's a post that goes more in depth here: How can I represent an 'Enum' in Python?
If you want an example of how to extend this to your specific case I'd do it like so, by creating a Unit enum:
class Unit(Enum):
inches, millimeters, meters = range(3)
class Problem(object):
def __init__(self, units):
self.unit = getattr(Unit(), units)
If I understand you correctly, you want to restrict the possible values for a property of an object without usimgna setter function. In Python you can have getters/setters that behave like usual properties. You can do:
class Problem(object):
#property
def unit(self):
return self._unit
#unit.setter
def unit(self, val):
if val in ["inches", "millimeters", "meters"]:
self._unit = val
I changed Unit because variables that are not types vor singletons usually shouldn't start in upper case.

Class design: methods that share a lot of the same code

I want to create a class with two methods at this point (I also want to be able to
alter the class obviously).
class ogrGeo(object):
def __init__(self):
pass
def CreateLine(self, o_file, xy):
#lots of code
def CreatePoint(self, o_file, xy):
# lot's of the same code as CreateLine(),
# only minor differences
To keep things as clean and to to repeat as
less code as possible I'm asking for some advise. The two methods CreateLine()
and CreatePoint() share a lot of code. To reduce redundance:
Should a define third method that both methods can call?
In this case you could still call
o = ogrGeo()
o.CreateLine(...)
o.CreatePoint(...)seperatly.
Or should I merge them into one method? Is there another solution I haven't thought about or know nothing about?
Thanks already for any suggestions.
Whether you should merge the methods into one is a matter of API design. If the functions have a different purpose, then you keep them seperate. I would merge them if client code is likely to follow the pattern
if some_condition:
o.CreateLine(f, xy)
else:
o.CreatePoint(f, xy)
But otherwise, don't merge. Instead, refactor the common code into a private method, or even a freestanding function if the common code does not touch self. Python has no notion of "private method" built into the language, but names with a leading _ will be recognized as such.
It's perfectly normal to factor out common code into a (private) helper method:
class ogrGeo(object)
def __init__(self):
pass
def CreateLine(self, o_file, xy):
#lots of code
value = self._utility_method(xy)
def CreatePoint(self, o_file, xy):
# lot's of the same code as CreateLine(),
# only minor differences
value = self._utility_method(xy)
def _utility_method(self, xy):
# Common code here
return value
The method could return a value, or it could directly manipulate the attributes on self.
A word of advice: read the Python style guide and stick to it's conventions. Most other python projects do, and it'll make your code easier to comprehend for other Python developers if you do.
For the pieces of code that will overlap, consider whether those can be their own separate functions as well. Then CreateLine would be comprised of several calls to certain functions, with parameter choices that make sense for CreateLine, meanwhile CreatePoint would be several function calls with appropriate parameters for creating a point.
Even if those new auxiliary functions aren't going to be used elsewhere, it's better to modularize them as separate functions than to copy/paste code. But, if it is the case that the auxialiary functions needed to create these structures are pretty specific, then why not break them out into their own classes?
You could make an "Object" class that involves all of the basics for creating objects, and then have "Line" and "Point" classes which derive from "Object". Within those classes, override the necessary functions so that the construction is specific, relying on auxiliary functions in the base "Object" class for the portions of code that overlap.
Then the ogrGeo class will construct instances of these other classes. Even if the ultimate consumer of "Line" or "Shape" doesn't need a full blown class object, you can still use this design, and give ogrGeo the ability to return the sub-pieces of a Line instance or a Point instance that the consumer does wish to use.
It hardly matters. You want the class methods to be as usable as possible for the calling programs, and it's slightly easier and more efficient to have two methods than to have a single method with an additional parameter for the type of object to be created:
def CreateObj(self, obj, o_file, xy) # obj = 0 for Point, 1 for Line, ...
Recommendation: use separate API calls and factor the common code into method(s) that can be called within your class.
You as well could go the other direction. Especially if the following is the case:
def methA/B(...):
lots of common code
small difference
lots of common code
then you could do
def _common(..., callback):
lots of common code
callback()
lots of common code
def methA(...):
def _mypart(): do what A does
_common(..., _mypart)
def methB(...):
def _mypart(): do what B does
_common(..., _mypart)

Categories

Resources