Reducing syntactic cruft when a method accesses instance variables? - python

The following code is a simplified example of a task I'm working on, using Python, that seems to be a natural fit for an OOP style:
class Foo:
def __init__(self):
self.x = 1
self.y = 1
self.z = 1
def method(self):
return bar(self.x,self.y,self.z)
def bar(x,y,z):
return x+y+z
f = Foo()
print(f.method())
In the example code above, I have three instance variables in my object, but in my actual application it would be more like 10 or 15 variables, and if I implement what I have in mind in this style, then I'm going to end up with a lot of code that looks like this:
return bar(self.a.self.b,self.c,self.d,self.e,self.f,self.g,self.h,self.i)
Wow, it sure would be nice to be able to write this in a style more like this:
return bar(a,b,c,d,e,f,g,h,i)
That would be a lot more concise and readable. One way to do this might be to rewrite bar so that it takes a Foo object as an input rather than a bunch of scalar variables, but I would prefer not to do that. Actually, that would just push the syntactic cruft down into the bar function, where I guess I would have code that looked like this:
def bar(f):
return f.a+f.b+f.c
Is there a nicer way to handle this? My understanding is that without the "self.", I would be referencing class variables rather than instance variables. I thought about using a dictionary, but that seems even cruftier, with all the ["a"] stuff. Might there be some automated way to take a dictionary with keys like "a","b","c",... and kind of unload the values into local variables named a, b, c, and so on?

I think you're going about this the wrong way. You're correct that your examples are hard to read, but I don't think the root cause is Python's syntax. An argument list that contains 10-15 variables is going to be difficult to read in any programming languages. I think the problem is your program's structure. Instead of trying to find ways around Python's syntax and conventions, consider trying to refactor your program so your classes don't need so many attributes, or refactor your methods so they don't need to return so many attributes.
Unfortunately I can't help you do that without seeing the full version of your code, but Code Review Stack Exchange would be a good place to get some help with that. Reducing the number of values returned and not coming up with unconventional ways to list and manipulate your attributes will make your code easier to read and maintain, both for others and yourself in the future.

Well, you could do it like so if you really wanted to, but I would advice against it. What if you add a field to your class and so on? Also it just makes things more complicated.
class Foo:
def __init__(self):
self.x = 1
self.y = 1
self.z = 1
def method(self):
return bar(**vars(self)) # expand all attributes as arguments
def bar(x,y,z):
return x+y+z
f = Foo()
print(f.method())

You can use __dict__ to create attributes from data of varying length, and then use classmethod to sum the attributes passed:
import string
class Foo:
def __init__(self, data):
self.__dict__ = dict(zip(string.ascii_lowercase, data))
#classmethod
def bar(cls, instance, vals = []):
return sum(instance.__dict__.values()) if not vals else sum(getattr(instance, i) for i in vals)
f = Foo(range(20))
print(Foo.bar(f))
print(Foo.bar(f, ['a', 'c', 'e', 'k', 'm']))
Output:
190
28

Related

Why wrap a single static method in a class?

I'm reading some code where the author is using a coding style with which I am unfamiliar; they put absolutely every function definition into a class. For example (details removed so as to not identify the author and codebase):
class CSVChecker:
#staticmethod
def is_ok(file):
#some stuff that could return False
return True
and that's the end of this class. Many similar. No __init__ or self. Usage: if CSVChecker.is_ok(afile)
Is this just an odd stylistic quirk carried over to Python from some other language? Or is there a Pythonic reason for this, rather than just def csv_check_file_ok(file): at the top level of the file?
#deceze probably has the answer in his comment. Some of these function-objects are indeed stored in lists, and some elements of the lists may be instances of "proper" objects. Stripped down to the absolute basics:
class F1:
def __init__(self, a):
self.max=a
def ok(self, x):
return x < self.max
class F2:
#staticmethod
def ok(x):
return x > 0
elsewhere
checkers = []
...
checkers.append( F1(i+j) )
checkers.append( F2 )
....
if ( all( check.ok(x) for check in checkers )
Personally I'd not have bothered with #staticmethod and just written the classes that didn't need any initialization with a dummy def __init__(self): pass and instantiate F2() Also there's probably some carry-over of style from another language (Java?) because not all the single-static-method function objects are used in this way. There again, if the author thought that they might be so used in the future, or might acquire the need to be instantiated with parameters, it makes sense.
Anyway, I've learned something and hopefully others will do in future.
EDIT added later: this usage accomplishes the same as what might have been done using functools.partial
def f1( x, max=None ):
return x < max
#elsewhere ...
checkers.append( functools.partial( f1, max=i+j ))
Now pondering which is best. Also how this usage of classes fits into the "inheritance, composition, aggregation" classification of objects. And whether it's an exception to
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.

Overriding an inner function of a method in python

That is a kind of best practices question.
I have a class structure with some methods defined. In some cases I want to override a particular part of a method. First thought on that is splitting my method to more atomic pieces and override related parts like below.
class myTest(object):
def __init__(self):
pass
def myfunc(self):
self._do_atomic_job()
...
...
def _do_atomic_job(self):
print "Hello"
That is a practical-looking way to solve the problem. But since I have too many parameters that is needed to be transferred to and revieced back from _do_atomic_job(), I do not want to pass and retrieve tons of parameters. Other option is setting these parameters as class variables with self.param_var etc but those parameters are used in a small part of the code and using self is not my preferred way of solving this.
Last option I thought is using inner functions. (I know I will have problems in variable scopes but as I said, this is a best practise and just ignore them and think scope and all things about the inner functions are working as expected)
class MyTest2(object):
mytext = ""
def myfunc(self):
def _do_atomic_job():
mytext = "Hello"
_do_atomic_job()
print mytext
Lets assume that works as expected. What I want to do is overriding the inner function _do_atomic_job()
class MyTest3(MyTest2):
def __init__(self):
super(MyTest3, self).__init__()
self.myfunc._do_atomic_job = self._alt_do_atomic_job # Of course this do not work!
def _alt_do_atomic_job(self):
mytext = "Hollla!"
Do what I want to achieve is overriding inherited class' method's inner function _do_atomic_job
Is it possible?
Either factoring _do_atomic_job() into a proper method, or maybe factoring it
into its own class seem like the best approach to take. Overriding an inner
function can't work, because you won't have access to the local variable of the
containing method.
You say that _do_atomic_job() takes a lot of parameters returns lots of values. Maybe you group some of these parameters into reasonable objects:
_do_atomic_job(start_x, start_y, end_x, end_y) # Separate coordinates
_do_atomic_job(start, end) # Better: start/end points
_do_atomic_job(rect) # Even better: rectangle
If you can't do that, and _do_atomic_job() is reasonably self-contained,
you could create helper classes AtomicJobParams and AtomicJobResult.
An example using namedtuples instead of classes:
AtomicJobParams = namedtuple('AtomicJobParams', ['a', 'b', 'c', 'd'])
jobparams = AtomicJobParams(a, b, c, d)
_do_atomic_job(jobparams) # Returns AtomicJobResult
Finally, if the atomic job is self-contained, you can even factor it into its
own class AtomicJob.
class AtomicJob:
def __init__(self, a, b, c, d):
self.a = a
self.b = b
self.c = c
self.d = d
self._do_atomic_job()
def _do_atomic_job(self):
...
self.result_1 = 42
self.result_2 = 23
self.result_3 = 443
Overall, this seems more like a code factorization problem. Aim for rather lean
classes that delegate work to helpers where appropriate. Follow the single responsibility principle. If values belong together, bundle them up in a value class.
As David Miller (a prominent Linux kernel developer) recently said:
If you write interfaces with more than 4 or 5 function arguments, it's
possible that you and I cannot be friends.
Inner variables are related to where they are defined and not where they are executed. This prints "hello".
class MyTest2(object):
def __init__(self):
localvariable = "hello"
def do_atomic_job():
print localvariable
self.do_atomic_job = do_atomic_job
def myfunc(self):
localvariable = "hollla!"
self.do_atomic_job()
MyTest2().myfunc()
So I can't see any way you could use the local variables without passing them, which is probably the best way to do it.
Note: Passing locals() will get you a dict of the variables, this is considered quite bad style though.

Class __init__ attributes, DRY vs IDE functinality

What's the proper way to follow the DRY rule in class __init__ method?
I know this two ways:
class Foo:
def __init__(self, x, y, z=None):
self.x = x
self.y = y
self.z = z
class Bar:
_fields = ['x', 'y', 'z']
def __init__(self, x, y, z=None):
for field in self.__class__._fields:
setattr(self, field, locals()[field])
The method in Foo is very repetitive, you have to type each attribute name three times, it gets quite exhausting doing this in classes with even small number of attributes and names not so lengthy.
On the other hand, the method used in Bar is way shorter, but has the draw back of constant warnings from the IDE's stating that there's 'unresolved references'. And also this method doesn't allow using the dot operator functionality in the IDE's to auto-complete the attributes.
I'm looking for what to do to create the classes not repeating attributes names all over and still be able to use some functionality from the IDE's.
I'm using PyCharm as my IDE, but I would happily change to any other if there's support for what I'm trying to do.
"On the other hand, the method used in Bar is way shorter"
Not really... In your example it is the same number of lines and WAY more characters. Of course, this might not be the case if you're passing LOTS of arguments to the constructor, but... once you start having too many arguments in the constructor then you're about due for a refactor to figure out how to cut down the number of arguments anyway...
Use the first version. Your future self/collaborators will thank you for it1.
1Actually, your future collaborators probably won't know to thank you... I suppose it might be more accurate to say that your future self/collaborators won't hunt you down to make your life miserable for writing hard to read code :-)

Python: renaming a superclass's methods and their function-scope references

Consider the following example:
class Company():
def hireEmployee():
def fireEmployee():
def promoteEmployee():
etc...
class EngineeringFirm(Company):
pass
class PaintingFirm(Company):
pass
Suppose the Company class has a lot more methods. What if I want to rename these methods from the superclass so I can get the following:
class EngineeringFirm(Company):
def hireEngineer():
...
class PaintingFirm(Company):
def hirePainter():
...
...and so on. While using 'Employee' in this scenario really wouldn't hurt a bit, this is really just to illustrate the idea. How would I go about it?
My idea was to use a classFactory function that would take the type of employee as argument and generate a Company class, while a metaclass would handle the renaming by iterating through the attribute dictionary and replacing 'Employee' with said type.
class EngineeringFirm(companyFactory('Engineer'))
...
The only problem is this: What if the methods inside of Company make calls to one another by the default 'Employee' names? This is where I'm stumped. I had the idea that the metaclass involved in renaming the methods could also get the source of each function (via the inspect module) and search if a known method attribute is found within and, if so, replace that part and create a new function via exec and assigning it back to the right attribute key.
...But that really seems kinda of hacky. I am open to alternatives and although I realize there may be design-related issues with the question (I am open to suggestions on that front as well) I would be interested in finding out if this problem has a more elegant solution.
Thanks!
Edit: another solution
For the sake of argument, I'll assume for a moment that the code above is really what I'm working with; I figured I could address some of the concerns in the comments with another solution I had in mind, one I'd already considered and put away for reasons I'll explain.
If the Firm classes inherited from Company and I wished to maintain a identical interface (as one usually would in a case like this to allow dynamic calls to hire() or promote(), etc) I could implement a __getattribute__ that accepts HirePainter() (by accessing the original Employee method) while still allowing any other interface to use the HireEmployee() if necessary.
I wonder, supposing it's alright to extend my question, if this is something that would be considered bad practice if, say, I planned to do this because I thought that the code inside PaintingFirm would benefit in readability? Again, I realize this example is horrid in that readability here really does not seem to benefit in any way whatsoever, but suppose it did?
(The only reason I didn't suggest this idea in the first place is that my __getattribute__ already handles quite a bit, and adding extra noise to it didn't feel that appealing. Still, I could work it in, but this is a question I had to ask in case there were more magical (but not hacky) solutions out there..)
For posterity's sake, I'm posting a solution of my own that I believe is a decent alternative. I don't suggest this as the answer because the truth is I did not mention in my question that I preferred not adding extra names, or to retain the ability to call these attributes as self.hireEngineer rather than ClassDict['HireEngineer']. Given that, I can't really say any of these answers don't answer the question.
Solution:
In hindsight, the problem was a lot simpler than I made it out to be. I guess I got hooked on the metaclassery just for the sake of it. If it's not already obvious, I'm really only just learning about metaclasses and for a moment it seemed like a good opportunity to try them out. Alas.
I believe the following solution respects the spirit of Liskov's principle (thank you, Ignacio) while giving the derived class the ability to reference the derived methods in its own way. The class namespace stays the same and other objects can call upon these methods with their real names if necessary.
# superclass...
def __getattribute__(self, attr):
# Early exit (AttributeError) if attribute not found.
obj = object.__getattribute__(self, attr)
# All the extra code...
def __getattr__(self, attr):
# Ex. self.type == 'Engineer'
# Replacing titled-cased and lower-cased
# versions just to be safe (ex. self.employeeNames)
attr = (attr
.replace(self.type, 'Employee')
.replace(self.type.lower(), 'employee')
)
if attr in self.attributes:
return self.__getattribute__(attr)
else:
raise AttributeError
I'll try to do a better job next time around when outlining the requirements. Thanks, guys.
You could try adding in a dictionary for each class.
class EngineeringFirm(Company):
ClassDict = {'HireEngineer':self.HireEmployee,
...
};
Whenever you want to call the function you would use
<EngineeringFirmInstanc>.ClassDict['HireEngineer'](<arguments>)
It's not particularly elegant, but it might get you close to what you are asking.
I tend to agree with the comments on the question: I suspect that what you're asking would add unnecessary complication to the code, making it harder to read & maintain just to implement a minor "cosmetic" feature of dubious benefit.
However, if you really want to do this, perhaps you could create methods that are synonyms of the existing methods, so you can call a method with its original name or with a "customized" name when it seems appropriate.
Here's one fairly straight-forward way to do that. I guess there's some sleek way to do it with class decorators, but I don't know how to use those. :)
#! /usr/bin/env python
''' Class synonym demo
From http://stackoverflow.com/q/27729681/4014959
Written by PM 2Ring 2015.01.01
'''
class Foo(object):
def __init__(self, data):
self.foo_set(data)
def foo_set(self, data):
self.data = data
def foo_add(self, n):
self.data += n
return self.data
def foo_mul(self, n):
self.data *= n
return self.data
def foo_mul_add(self, n, m):
self.foo_mul(n)
return self.foo_add(m)
def make_synonyms(cls, old, new):
class newclass(cls):
pass
d = cls.__dict__
for k in d:
if k.startswith(old):
newname = k.replace(old, new)
#print k, d[k], newname
setattr(newclass, newname, d[k])
return newclass
#--------------------------------------
Bar = make_synonyms(Foo, 'foo', 'bar')
a = Foo(5)
print a.data
print a.foo_add(10)
print a.foo_mul(4)
print a.foo_mul_add(2, 1)
print '-' * 20
a = Bar(6)
print a.data
print a.foo_add(10)
print a.foo_mul(4)
print a.foo_mul_add(2, 1)
print '-' * 20
a.bar_set(5)
print a.data
print a.bar_add(10)
print a.bar_mul(4)
print a.bar_mul_add(2, 1)
output
5
15
60
121
--------------------
6
16
64
129
--------------------
5
15
60
121

Please help me in understanding Class in Python

I am newbie and finding it very hard to grasp the syntax of Class in python. I have a background of C/C++, java and objective C. A very big difference which i am noticing in python is that you don't explicitly declare the "data members" in the class and you just randomly add them? And it leads to quite big confusion.
Let say i have a class
class MyClass:
def __int__(self, a, b):
self.a = a
self.b = b
And then when i initiate the object.
myobject = MyClass(10,10)
And just after some time for some reason i come to know that i need another parameter in this class but i dont wanted to initiate that using constructor because it will be initiated by another function depending on the some particular condition, so in whole mess of code that will be only point that variable actually get birth. is not the case when i will be checking the code while debugging or reviewing it for some other reason it will be confusing?
In short, Yes.
You're right. Python lets you add (and remove!) members from objects at will, at any time. There's nothing special about a constructor that allows it to do anything that other functions can't.
If you want to be sure that all instances of your class have the same members at all times, then by all means assign them all in the constructor, using a sentinel value like None for ones that don't have a meaningful value yet, and avoid adding new members outside the constructor.
It's up to you how you manipulate your objects, and if you want to do that in a static fashion then that's fine, or if you want to take advantage of the ability to add and remove members at arbitrary times, that's fine too. Python itself doesn't impose (m)any rules.
You should really use some . in your text :p
Could you mean:
class MyClass:
def __int__(self, a, b, c=None):
self.a = a
self.b = b
self.c = c
one = MyClass(1,2)
one.c # None
two = MyClass(1,2,3)
two.c # 3
class MyClass:
def __int__(self, a, b):
self.a = a
self.b = b
self.c = None #This line is optional
def set_c(self, c):
self.c = c
Some people prefer to list all the attributes in the __init__. You don't have to, but there are any number of reasons you might choose to.
Maybe it improves your editor's ability to understand your code for highlighting or completion.
Maybe it is just a style that you prefer.

Categories

Resources