Related
I have a method that builds a laptop's attributes, but only if the attributes are present within a row that is given to the method:
def build_laptop_attributes desk_id, row, laptop
attributes = {}
attributes[:desk_number] = room_id if laptop && desk_id
attributes[:status] = row[:state].downcase if row[:state]
attributes[:ip_address] = row[:ip_address] if row[:ip_address]
attributes[:model] = row[:model] if row[:model]
attributes
end
Currently, RuboCop is saying that the Metric/AbcSize is too high, and I was wondering if there is an obvious and clean way to assign these attributes?
Style Guides Provide "Best Practices"; Evaluate and Tune When Needed
First of all, RuboCop is advisory. Just because RuboCop complains about something doesn't mean it's wrong in some absolute sense; it just means you ought to expend a little more skull sweat (as you're doing) to see if what you're doing makes sense.
Secondly, you haven't provided a self-contained, executable example. That makes it impossible for SO readers to reliably refactor it, since it can't currently be tested without sample inputs and expected outputs not provided in your original post. You'll need those things yourself to evaluate and refactor your own code, too.
Finally, the ABC Metric looks at assignments, branches, and conditionals. You have five assignments, four conditionals, and what looks liks a method call. Is that a lot? If you haven't tuned Rubocop, the answer is "RuboCop thinks so." Whether or not you agree is up to you and your team.
If you want to try feeding Rubocop, you can do a couple of things that might help reduce the metric:
Refactor the volume and complexity of your assignments. Some possible examples include:
Replace your postfix if-statements with safe navigators (&.) to guard against calling methods on nil.
Extract some of your branching logic and conditionals to methods that "do the right thing", potentially reducing your current method to a single assignment with four method calls. For example:
attributes = { desk_number: location, status: laptop_status, ... }
Replace all your multiple assignments with a deconstructing assignment (although Rubocop often complains about those, too).
Revisit whether you have the right data structure in the first place. Maybe you really just want an OpenStruct, or some other data object.
Your current code seems readable, so is the juice really worth the squeeze? If you decide that RuboCop is misguided in this particular case, and your code works and passes muster in your internal code reviews, then you can tune the metric's sensitivity in your project's .rubocop.yml or disable that particular metric for just that section of your source code.
After reading #Todd A. Jacobs answer, you may want (or not) to write something like this:
def build_laptop_attributes desk_id, row, laptop
desk_number = room_id if laptop && desk_id
{
desk_number: desk_number,
status: row[:state]&.downcase,
ip_address: = row[:ip_address],
model: row[:model]
}.compact
end
This reduces has the advantage of reducing the number of calls to []=, as well as factorizing many ifs in a single compact.
In my opinion, it is more readable because it is more concise and because the emphasis is completely on the correspondence between your keys and values.
Alternative version to reduce the amount of conditionals (assuming you are checking for nil / initialized values):
def build_laptop_attributes desk_id, row, laptop
attributes = {}
attributes[:desk_number] = room_id if laptop && desk_id
attributes[:status] = row[:state]&.downcase
attributes[:ip_address] = row[:ip_address]
attributes[:model] = row[:model]
attributes.compact
end
There is an additional .compact as a cost of removing assignments checks.
Tldr: how do I 'include Shoes methods' into the Array class and classes ive created, with minimal code, without totally restructuring everything?
I've written a functioning program in Ruby, and now I want to make a Shoes app from it.
I'm having the problem described at the beginning of the manual - Shoes.app is a sort of block in itself, so self always refers to it, and Shoes methods like "para" aren't necessarily going to be available everywhere the way "puts" is in Ruby. But I'm not smart enough to fix it (I've only just got my head around using self and return in pure Ruby, bear with me)
For example, I've created a new method for Array: putdata, which loops through a student's test score array displaying each automatically as a list:
self.each do |ea|
puts/para "#{ea.topic}: #{ea.score}"
end
Works in ruby. Doesn't work in Shoes: Array class doesn't have access to the method para. I've tried:
making Array < Shoes (it really doesn't like that)
adding stack.app do...end at various places in the program (no impact)
trying to call Shoes::para instead of para (farts)
I've tried using require 'file with all my classes and methods in.rb' instead of the same code in the file (reports no method for class)
tried requiring my code directly before calling a method, to ensure my code is in the scope of Shoes (reports no method for class)
making my custom classes (Course and Student) < Shoes, so it'd have access to its methods (causes a runtime error)
I've got it to function by:
1. Removing this bit of code from the Array class, and making it a floating/generic method rather than an Array method
2. Private method error --> then rephrasing it so instead of an Array method (array.putdata) it's a generic method which takes an array as an argument (putdata(array))
But I really, really don't want to go through my code and individually un-organise it like this.
It's my first 1000 line program, with 42 methods, and I worked hard on making it as maintainable and neat as possible, with everything tucked away in classes or methods for easy upkeep. I got it from everything in massive, step-by-step generic methods down to lots of snappy ones, which seemed a bit more like how OOP is meant to go. Now the only way I can see to make this work is to UN-OOP it, and have no class methods or anything.
I was hoping I could Shoes the program fairly seamlessly from this tidy, functional back-end: the Ruby program has lots of "if string == "SAVE", save(student); else...", so I was hoping to straightforwardly pop in "button.click {save(student)}" with the same back code.
#
Is there something fundamental I'm missing to let me do this? And can I fix the para problem easily, seeing as all my classes contain ways of displaying their own data? I'd like to copypasta "include 'Shoes methods'" at the top of each class and be done.
Or do I need to be writing with the GUI in mind from the start in future?
(Info about my program:
Layout is a series of pages, linked from a sidebar, using index with linked pages as copied straight from the Nobody Knows Shoes book, or the class-book sample.
Students can input their new levels, and view a readout of their current progress.
There are generic methods for major "parts" of the program, which have things like the title of the page and some instructions, and which then call on student objects or Module methods to do the things as instructed by the user.
Higher up: student is a custom class, with methods like "save", "display flattened data ", "add one to your level IF this ELSE don't", and associated bits of data, like an array with all their course objects in.
Each course is also a custom class ("Module"), which has the score, the module name etc as variables, and some tiny methods like display formatted name, or add one to this module.)
I'm glad to see a question about shoes, it's been a long time.
You'r new on SO so first: your question is way too elaborated, too much to read and far too little information to help you.
You need to provide piecess of code that give error or don't do what you expect, things we can take over and try. This means extracting from your code tests or pieces of code that run by themself and show the problem.
We also need to know which Ruby version and which version and color of shoes you are using. The example I'll be using is green shoes.
I'm sure the following isn't exactly what you were after but I've made a sample based on your description of an Array that needs to be listed both by puts and para.
Change the question or make a new one if this is not what you are after.
require 'green_shoes'
s = Struct.new(:topic, :score)
s1 = s.new("test1", 1)
s2 = s.new("test2", 2)
A = [s1, s2]
class Array
def putsdata(shoes = nil)
if shoes.class == Shoes::App
self.each do |ea|
shoes.para "#{ea.topic}: #{ea.score}"
end
else
self.each do |ea|
puts "#{ea.topic}: #{ea.score}"
end
end
end
end
A.putsdata
# gives in the console
# test1: 1
# test2: 2
Shoes.app do
A.putsdata(self)
end
# gives in a graphic window
# test1: 1
# test2: 2
The puts also works in the shoes block, but of course the result doesn't come in the graphic window but on the console where you started, after the first list.
I'm trying to optimize a given object oriented code in matlab. It is an economical model and consists of a Market and Agents. The time consuming part is to update certain attributes of all Agents during each timestep which is implemented in a for loop.
However, I fail to vectorize the object oriented code.
Here is an example (Note, the second thing that slows down the code so far is the fact, that new entries are attached to the end of the vector. I'm aware of that and will fix that also):
for i=1:length(obj.traders)
obj.traders(i).update(obj.Price,obj.Sentiment(end),obj.h);
end
Where update looks like
function obj=update(obj,price,s,h)
obj.pos(end+1)=obj.p;
obj.wealth(end+1)=obj.w(1,1,1);
obj.g(end+1)=s;
obj.price=price;
obj.Update_pos(sentiment,h);
if (obj.c)
obj.Switch_Pos;
end
...
My first idea was to try something like
obj.traders(:).update(obj.Price,obj.Sentiment(end),obj.h);
Which didn't work. If someone has any suggestions how to vectorize this code, while keeping the object oriented implementation, I would be very happy.
I cannot provide a complete solution as this depends on the details of your implementation, but here are some tips which you could use to improve your code:
Remembering that a MATLAB object generally behaves like a struct, assignment of a constant value to a field can be done using [obj.field] =deal(val); e.g.:
[obj.trader.price] = deal(obj.Price);
This can also be extended to non-constant RHS, using cell, like so:
[aStruct.(fieldNamesCell{idx})] = deal(valueCell{:}); %// or deal(numericVector(:));
To improve the update function, I would suggest making several lines where you create the RHS vectors\cells followed by "simultaneous" assignment to all relevant fields of the objects in the array.
Other than that consider:
setfield: s = setfield(s,{sIndx1,...,sIndxM},'field',{fIndx1,...,fIndxN},value);
structfun:
s = structfun(#(x)x(1:3), s, 'UniformOutput', false, 'ErrorHandler', #errfn);
"A loop-based solution can be flexible and easily readable".
P.S.
On a side note, I'd suggest you name the obj in your functions according to the class name, which would make it more readable to others, i.e.:
function obj=update(obj,price,s,h) => function traderObj=update(traderObj,price,s,h)
I'm learning Ruby through 'Learn to Program' by Chris Pine. I'm trying to cope without global variables. I have a sloppy looking command prompt blackjack program (can't split yet) My first three methods illustrate the problem I'm having. In Pascal I would have used global variables, and used methods to manipulate those global variables. It would look something like this (using ruby pseudo language)
$deck_of_cards = []
$player_hand = []
$dealer_hand = []
def create_deck
$deck_of_cards = #numbers 1-52
end
def shuffle_deck
$deck_of_cards = #shuffled up deck of cards
end
def opening_deal
2.times do
$player_hand.push $deck_of_cards.pop
$dealer_hand.push $deck_of_cards.pop
end
end
create_deck
shuffle_deck
opening_deal
and I would end up with a shuffled deck, a player hand, and a dealer hand.
Taking away global variables, the first two methods now look like this:
def create_deck deck_of_cards
deck_of_cards = #numbers 1-52
return deck_of_cards
end
def shuffle_deck deck_of_cards
deck_of_cards = #shuffled up deck of cards
return deck_of_cards
end
deck = create_deck([])
deck = shuffle_deck(deck)
which feels a little odd but I could get used to it.
But I'm completely stuck on the last method, which would need to return two variables, player_hand and dealer_hand. I could push those two arrays into another array and return that, but that doesn't seem like it's simplifying anything.
Is there a general strategy for dealing with this, or does each situation have its own unique solution?
Another situation that comes to mind is a chess program. Why would it not make sense to make the chess board a global variable since almost all methods in a chess program would need to use it's value?
The short answer: Objects. Object oriented programming allows you to encapsulate data so that it doesn't pollute the global namespace. As your projects grow larger, it becomes unmaintainable to have all your data in the global namespace. Objects allow you to group data and methods into meaningful units, which can then be re-used and maintained more easily.
So for instance with the example you provided we could make deck and hand objects. This then allows us to create multiple deck and hands easily because these objects encapsulate and manage their data.
As a rough outline of how you might organize your classes / methods:
class Deck
def shuffle
end
def draw_hand
end
end
class Hand
end
class Card
end
In general, using object oriented programming techniques you would define classes and create objects of those classes and then pass around those objects. You can think of objects as sort of like arrays in that they can contain lots of related data, but better than arrays in that the data elements can have names and can be any type and do not need to be the same type and they come with named functions for operating on the data. (Actually, in Ruby, Array elements can be any type and do not need to be the same type, and the same is true of Hash elements plus Hash elements have names, but Ruby is special that way. Few other languages allow that.)
Keeping it simple, though, you can continue your program like this:
def opening_deal deck_of_cards
player_hand = []
dealer_hand = []
2.times do
player_hand.push deck_of_cards.pop
dealer_hand.push deck_of_cards.pop
end
return player_hand, dealer_hand
end
player_hand, dealer_hand = opening_deal deck
It is a bad habit to have global variables, but it is not bad to have global constants, or in other words, constants defined in the main name space. When in need of a global variable, you can always define a constant in the main name space. Mutable objects like string, hash, array can be modified even if it is a constant. If that is not enough and you need more complicated things, then you can define a module (which is a special case of constants), and define methods on that module to have access to the things you want to do, and encapsulate the complicated information inside that module using instance variables.
I have a class that is provided to me by an external library. I have created a subclass of this class. I also have an instance of the original class.
I now want to turn this instance into an instance of my subclass without changing any properties that the instance already has (except for those that my subclass overrides anyway).
The following solution seems to work.
# This class comes from an external library. I don't (want) to control
# it, and I want to be open to changes that get made to the class
# by the library provider.
class Programmer(object):
def __init__(self,name):
self._name = name
def greet(self):
print "Hi, my name is %s." % self._name
def hard_work(self):
print "The garbage collector will take care of everything."
# This is my subclass.
class C_Programmer(Programmer):
def __init__(self, *args, **kwargs):
super(C_Programmer,self).__init__(*args, **kwargs)
self.learn_C()
def learn_C(self):
self._knowledge = ["malloc","free","pointer arithmetic","curly braces"]
def hard_work(self):
print "I'll have to remember " + " and ".join(self._knowledge) + "."
# The questionable thing: Reclassing a programmer.
#classmethod
def teach_C(cls, programmer):
programmer.__class__ = cls # <-- do I really want to do this?
programmer.learn_C()
joel = C_Programmer("Joel")
joel.greet()
joel.hard_work()
#>Hi, my name is Joel.
#>I'll have to remember malloc and free and pointer arithmetic and curly braces.
jeff = Programmer("Jeff")
# We (or someone else) makes changes to the instance. The reclassing shouldn't
# overwrite these.
jeff._name = "Jeff A"
jeff.greet()
jeff.hard_work()
#>Hi, my name is Jeff A.
#>The garbage collector will take care of everything.
# Let magic happen.
C_Programmer.teach_C(jeff)
jeff.greet()
jeff.hard_work()
#>Hi, my name is Jeff A.
#>I'll have to remember malloc and free and pointer arithmetic and curly braces.
However, I'm not convinced that this solution doesn't contain any caveats I haven't thought of (sorry for the triple negation), especially because reassigning the magical __class__ just doesn't feel right. Even if this works, I can't help the feeling there should be a more pythonic way of doing this.
Is there?
Edit: Thanks everyone for your answers. Here is what I get from them:
Although the idea of reclassing an instance by assigning to __class__ is not a widely used idiom, most answers (4 out of 6 at the time of writing) consider it a valid approach. One anwswer (by ojrac) says that it's "pretty weird at first glance," with which I agree (it was the reason for asking the question). Only one answer (by Jason Baker; with two positive comments & votes) actively discouraged me from doing this, however doing so based on the example use case moreso than on the technique in general.
None of the answers, whether positive or not, finds an actual technical problem in this method. A small exception is jls who mentions to beware of old-style classes, which is likely true, and C extensions. I suppose that new-style-class-aware C extensions should be as fine with this method as Python itself (presuming the latter is true), although if you disagree, keep the answers coming.
As to the question of how pythonic this is, there were a few positive answers, but no real reasons given. Looking at the Zen (import this), I guess the most important rule in this case is "Explicit is better than implicit." I'm not sure, though, whether that rule speaks for or against reclassing this way.
Using {has,get,set}attr seems more explicit, as we are explicitly making our changes to the object instead of using magic.
Using __class__ = newclass seems more explicit because we explicitly say "This is now an object of class 'newclass,' expect a different behaviour" instead of silently changing attributes but leaving users of the object believing they are dealing with a regular object of the old class.
Summing up: From a technical standpoint, the method seems okay; the pythonicity question remains unanswered with a bias towards "yes."
I have accepted Martin Geisler's answer, because the Mercurial plugin example is a quite strong one (and also because it answered a question I even hadn't asked myself yet). However, if there are any arguments on the pythonicity question, I'd still like to hear them. Thanks all so far.
P.S. The actual use case is a UI data control object that needs to grow additional functionality at runtime. However, the question is meant to be very general.
Reclassing instances like this is done in Mercurial (a distributed revision control system) when extensions (plugins) want to change the object that represent the local repository. The object is called repo and is initially a localrepo instance. It is passed to each extension in turn and, when needed, extensions will define a new class which is a subclass of repo.__class__ and change the class of repo to this new subclass!
It looks like this in code:
def reposetup(ui, repo):
# ...
class bookmark_repo(repo.__class__):
def rollback(self):
if os.path.exists(self.join('undo.bookmarks')):
util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
return super(bookmark_repo, self).rollback()
# ...
repo.__class__ = bookmark_repo
The extension (I took the code from the bookmarks extension) defines a module level function called reposetup. Mercurial will call this when initializing the extension and pass a ui (user interface) and repo (repository) argument.
The function then defines a subclass of whatever class repo happens to be. It would not suffice to simply subclass localrepo since extensions need to be able to extend each other. So if the first extension changes repo.__class__ to foo_repo, the next extension should change repo.__class__ to a subclass of foo_repo and not just a subclass of localrepo. Finally the function changes the instanceø's class, just like you did in your code.
I hope this code can show a legitimate use of this language feature. I think it's the only place where I've seen it used in the wild.
I'm not sure that the use of inheritance is best in this case (at least with regards to "reclassing"). It seems like you're on the right track, but it sounds like composition or aggregation would be best for this. Here's an example of what I'm thinking of (in untested, pseudo-esque code):
from copy import copy
# As long as none of these attributes are defined in the base class,
# this should be safe
class SkilledProgrammer(Programmer):
def __init__(self, *skillsets):
super(SkilledProgrammer, self).__init__()
self.skillsets = set(skillsets)
def teach(programmer, other_programmer):
"""If other_programmer has skillsets, append this programmer's
skillsets. Otherwise, create a new skillset that is a copy
of this programmer's"""
if hasattr(other_programmer, skillsets) and other_programmer.skillsets:
other_programmer.skillsets.union(programmer.skillsets)
else:
other_programmer.skillsets = copy(programmer.skillsets)
def has_skill(programmer, skill):
for skillset in programmer.skillsets:
if skill in skillset.skills
return True
return False
def has_skillset(programmer, skillset):
return skillset in programmer.skillsets
class SkillSet(object):
def __init__(self, *skills):
self.skills = set(skills)
C = SkillSet("malloc","free","pointer arithmetic","curly braces")
SQL = SkillSet("SELECT", "INSERT", "DELETE", "UPDATE")
Bob = SkilledProgrammer(C)
Jill = Programmer()
teach(Bob, Jill) #teaches Jill C
has_skill(Jill, "malloc") #should return True
has_skillset(Jill, SQL) #should return False
You may have to read more about sets and arbitrary argument lists if you aren't familiar with them to get this example.
This is fine. I've used this idiom plenty of times. One thing to keep in mind though is that this idea doesn't play well with old-style classes and various C extensions. Normally this wouldn't be an issue, but since you are using an external library you'll just have to make sure you're not dealing with any old-style classes or C extensions.
"The State Pattern allows an object to alter its behavior when its internal state changes. The object will appear to change it's class." - Head First Design Pattern. Something very similar write Gamma et.al. in their Design Patterns book. (I have it at my other place, so no quote). I think that's the whole point of this design pattern. But if I can change the class of an object at runtime, most of the time i don't need the pattern (there are cases when State Pattern does more than simulate a class change).
Also, changing class at runtime doesn't always work:
class A(object):
def __init__(self, val):
self.val = val
def get_val(self):
return self.val
class B(A):
def __init__(self, val1, val2):
A.__init__(self, val1)
self.val2 = val2
def get_val(self):
return self.val + self.val2
a = A(3)
b = B(4, 6)
print a.get_val()
print b.get_val()
a.__class__ = B
print a.get_val() # oops!
Apart from that, I consider changing class at runtime Pythonic and use it from time to time.
Heheh, fun example.
"Reclassing" is pretty weird, at first glance. What about the 'copy constructor' approach? You can do this with the Reflection-like hasattr, getattr and setattr. This code will copy everything from one object to another, unless it already exists. If you don't want to copy methods, you can exclude them; see the commented if.
class Foo(object):
def __init__(self):
self.cow = 2
self.moose = 6
class Bar(object):
def __init__(self):
self.cat = 2
self.cow = 11
def from_foo(foo):
bar = Bar()
attributes = dir(foo)
for attr in attributes:
if (hasattr(bar, attr)):
break
value = getattr(foo, attr)
# if hasattr(value, '__call__'):
# break # skip callables (i.e. functions)
setattr(bar, attr, value)
return bar
All this reflection isn't pretty, but sometimes you need an ugly reflection machine to make cool stuff happen. ;)
This technique seems reasonably Pythonic to me. Composition would also be a good choice, but assigning to __class__ is perfectly valid (see here for a recipe that uses it in a slightly different way).
In ojrac's answer, the break breaks out of the for-loop and doesn't test any more attributes. I think it makes more sense to just use the if-statement to decide what to do with each attribute one at a time, and continue through the for-loop over all attributes. Otherwise, I like ojrac's answer, as I too see assigning to __class__ as weird. (I'm a beginner with Python and as far as I remember this is my first post to StackOverFlow. Thanks for all the great information!!)
So I tried to implement that. I noticed that dir() doesn't list all the attributes. http://jedidjah.ch/code/2013/9/8/wrong_dir_function/ So I added 'class', 'doc', 'module' and 'init' to the list of things to add if they're not there already, (although they're probably all already there), and wondered whether there were more things dir misses. I also noticed that I was (potentially) assigning to 'class' after having said that was weird.
I will say this is perfectly fine, if it works for you.