I am trying to improve my python code and have started using classes to group related methods and variables.
What is the best practice when using a function that is able to access the variables that are initialized in the class? Should I just access the variable in the function? Or explicitly pass the variable to make it clear that I am relying on it?
I've created two examples to show what I mean by this question. Which method is preferred?
# method 1
class UploadForm(object):
def __init__(self, form_data):
self.file_name = form_data.get('file_name')
def validate(self):
agency_name = self.extract_agency_name(self.file_name)
#staticmethod
def extract_agency_name(file_name):
pattern = re.search('^[CFS]Y\d{4} (.+?)[.](?:xls|csv)$', file_name, re.I)
if pattern:
agency_name = pattern.group(1)
return agency_name
# method 2
class UploadForm(object):
def __init__(self, form_data):
self.file_name = form_data.get('file_name')
def validate(self):
agency_name = self.extract_agency_name()
def extract_agency_name(self):
pattern = re.search('^[CFS]Y\d{4} (.+?)[.](?:xls|csv)$', self.file_name, re.I)
if pattern:
agency_name = pattern.group(1)
return agency_name
For reasons below method 2 is preferred.
A member variable should be accessed via self.
By using self, you are making clear that you are referencing file_name variable of the same object.
Decorators can become overheads.
Decorators are wrappers around a method or a variable.
Passing more argument is more memory consuming.
Each argument takes up memory.
I had a problem with overriding str inside my inherited class. Is there a way to do something similar?
class Sentence(str):
def input(self, msg):
"""Extend allow to hold one changing object for various strings."""
self = Sentence(input(msg))
def simplify(self):
self = self.lower()
self.strip()
I want to change mine string contained in that class, for various use. There's a way to do this? Because I tried many things from stack, and no one help me.
There is a explain what I want to do:
In init, I initialize Sentence class:
self.sentence = Sentence("")
Mainloop, where user can change Sentence:
self.sentence.input("Your input:")
After it I want to simplify string for alghoritm:
self.sentence.simplify()
And that's all, after it I want to use self.sentence like string.
But in both methods:
def input(self, msg):
"""Extend allow to hold one changing object for various strings."""
self = Sentence(input(msg))
def simplify(self):
self = self.lower()
self.strip()
String wasn't changed.
Due to the optimizations languages such as Python perform on strings (i.e. they are inmutable so the same string can be reused) I don't think it's a good practice to inherit from str, instead, you could write a class that wraps the string:
class Sentence:
def __init__(self, msg: str):
self.msg = msg
def simplify(self):
self.msg = self.msg.lower().strip()
This way you can improve your implementation if for example you are changing the string too often and you run into performance problems.
I have following structure for class.
class foo(object):
def __call__(self,param1):
pass
class bar(object):
def __call__(self,param1,param2):
pass
I have many classes of this type. And i am using this callable class as follows.
classes = [foo(), bar()]
for C in classes:
res = C(param1)
'''here i want to put condition if class takes 1 argumnet just pass 1
parameter otherwise pass two.'''
I have think of one pattern like this.
class abc():
def __init__(self):
self.param1 = 'xyz'
self.param2 = 'pqr'
def something(self, classes): # classes = [foo(), bar()]
for C in classes:
if C.__class__.__name__ in ['bar']:
res = C(self.param1, self.param2)
else:
res = C(self.param2)
but in above solution have to maintain list of class which takes two arguments and as i will add more class to file this will become messy.
I dont know whether this is correct(pythonic) way to do it.
On more idea i have in mind is to check how many argument that class is taking. If its 2 then pass an additional argument otherwise pass 1 argument.I have looked at this solution How can I find the number of arguments of a Python function? . But i am not confident enought that this is the best suited solution to my problem.
Few things about this:
There are only two type of classes in my usecase one with 1 argument and one with 2.
Both class takes first argument same so params1 in both case is same argument i am passing. in case of class with two required parameter i am passing additional argument(params2) containing some data.
Ps : Any help or new idea for this problem are appretiated.
UPD : Updated the code.
Basically, you want to use polymorphism on your object's __call__() method, but you have an issue with your callables signature not being the same.
The plain simple answer to this is: you can only use polymorphism on compatible types, which in this case means that your callables MUST have compatible signatures.
Hopefully, there's a quick and easy way to solve this: just modify your methods signatures so they accept varargs and kwargs:
class Foo(object):
def __call__(self,param1, *args, **kw):
pass
class Bar(object):
def __call__(self, param1, param2, *args, **kw):
pass
For the case where you can't change the callable's signature, there's still a workaround: use a lambda as proxy:
def func1(y, z):
pass
def func2(x):
pass
callables = [func1, lambda y, z: func2(y)]
for c in callables:
c(42, 1138)
Note that this last example is actually known as the adapter pattern
Unrelated: this:
if C.__class__.__name__ in ['bar']:
is a inefficient and convoluted way to write:
if C.__class__.__name__ == 'bar':
which is itself an inefficient, convoluted AND brittle way to write:
if type(C) is bar:
which, by itself, is a possible design smell (there are legit use cases for checking the exact type of an object, but most often this is really a design issue).
Is it good style to create a separate method, in which I preprocess data, before I pass it to the constructor (in case the preprocessing is cumbersome), like so:
class C():
def __init__(self, input, more_input):
self.value = self.prepare_value(input, more_input)
def prepare_value(self, input, more_input):
#here I actually do some nontrivial stuff, over many lines
#for brevity I'm illustrating just a short, one-line operation
value = (input + more_input)/2
return value
print(C(10, 33).value) # has value 21.5
If you wanted to do it like this, then I'd suggest two things.
Make the prepare_value() method a static method by decorating with the #staticmethod decorator. Since it's not making any changes to the instance of the class itself, just returning a value then you shouldn't be making it a method of the instance. Hence, #staticmethod.
Signify that the method should only be used internally by using the name _prepare_value(). This doesn't actually make it private, but it's a well recognized convention to say to other developers (i.e. future you) "this method isn't designed to be used externally".
Overall my suggestion would be:
class C():
def __init__(self, input, more_input):
self.value = self._prepare_value(input, more_input)
#staticmethod
def _prepare_value(input, more_input):
value = (input + more_input)/2
return value
I was wondering if there is anything wrong (from a OOP point of view) in doing something like this:
class Foobar:
foobars = {}
def __init__(self, name, something):
self.name = name
self.something = something
Foobar.foobars[name] = self
Foobar('first', 42)
Foobar('second', 77)
for name in Foobar.foobars:
print name, Foobar.foobars[name]
EDIT: this is the actual piece of code I'm using right now
from threading import Event
class Task:
ADDED, WAITING_FOR_DEPS, READY, IN_EXECUTION, DONE = range(5)
tasks = {}
def __init__(self, name, dep_names, job, ins, outs, uptodate, where):
self.name = name
self.dep_names = [dep_names] if isinstance(dep_names, str) else dep_names
self.job = job
self.where = where
self.done = Event()
self.status = Task.ADDED
self.jobs = []
# other stuff...
Task.tasks[name] = self
def set_done(self):
self.done.set()
self.status = Task.DONE
def wait_for_deps(self):
self.status = Task.WAITING_FOR_DEPS
for dep_name in self.dep_names:
Task.tasks[dep_name].done.wait()
self.status = Task.READY
def add_jobs_to_queues(self):
jobs = self.jobs
# a lot of stuff I trimmed here
for w in self.where: Queue.queues[w].put(jobs)
self.status = Task.IN_EXECUTION
def wait_for_jobs(self):
for j in self.jobs: j.wait()
#[...]
As you can see I need to access the dictionary with all the instances in
the wait_for_deps method. Would it make more sense to have a global variable
instead of a class field? I could be using a wrong approach here, maybe that
stuff shouldn't even be in a method, but it made sense to me (I'm new to OOP)
Yes. It's bad. It conflates the instance with the collection of instances.
Collections are one thing.
The instances which are collected are unrelated.
Also, class-level variables which get updated confuse some of us. Yes, we can eventually reason on what's going on, but the Standard Expectation™ is that state change applies to objects, not classes.
class Foobar_Collection( dict ):
def __init__( self, *arg, **kw ):
super( Foobar_Collection, self ).__init__( *arg, **kw ):
def foobar( self, *arg, **kw ):
fb= Foobar( *arg, **kw )
self[fb.name]= fb
return fb
class Foobar( object ):
def __init__( self, name, something )
self.name= name
self.something= something
fc= Foobar_Collection()
fc.foobar( 'first', 42 )
fc.foobar( 'second', 77 )
for name in fc:
print name, fc[name]
That's more typical.
In your example, the wait_for_deps is simply a method of the task collection, not the individual task. You don't need globals.
You need to refactor.
I don't suppose that there's anything wrong with this, but I don't really see how this would be sensible. Why would you need to keep a global variable (in the class, of all places) that holds references to all the instances? The client could just as easily implement this himself if he just kept a list of his instances. All in all, it seems a little hackish and unnecessary, so I'd recommend that you don't do it.
If you're more specific about what you're trying to do, perhaps we can find a better solution.
This is NOT cohesive, as well as not very functional, you want to strive to get your objects as far from the 'data-bucket' mindset as possible. The static object collection is not going to really gain you anything, you need to think WHY do you need all the objects in the collection and think about creating a second class whose responsibility is to manage and be queried for all the Foobars in the system.
Why would you want to do this?
There are several problems with this code. The first is that you have to take care of deleting instances -- there will always be a reference to each Foobar instance left in Foobar.foobars, so the garbage collector will never garbage collect them. The second problem is that it won't work with copy and pickle.
But apart from the technical problems, it feels like a wrong design. The purpose of object instances is hiding state, and you make them see each other.
From a OOP point of view there's nothing wrong with it. A class is an instance of a metaclass, and any instance can hold any kind of data in it.
However, from an efficiency point of view, if you don't eventualy clean up the foobars dict on a long running Python program, you are having potential memory leak.
No one has mentioned the potential problem this might have if you later derive a subclass from Foobar which could happen if the base class __init__() function is called from the derived class's __init__(). Specifically whether you want all the subclass instances to be sored in the same place as those of the base class -- which of course depend on why you're doing this.
It's a solvable problem but something to consider, and perhaps to code for, up front in the base class.
I needed multiple Jinja environments in an app engine application:
class JinjaEnv(object):
""" Jinja environment / loader instance per env_name """
_env_lock = threading.Lock()
with _env_lock:
_jinja_envs = dict() # instances of this class
def __init__(self, env_name):
self.jinja_loader = ..... # init jinja loader
self.client_cache = memcache.Client()
self.jinja_bcc = MemcachedBytecodeCache(self.client_cache, prefix='jinja2/bcc_%s/' % env_name, timeout=3600)
self.jinja_env = self.jinja_loader(self.jinja_bcc, env_name)
#classmethod
def get_env(cls, env_name):
with cls._env_lock:
if env_name not in cls._jinja_envs:
cls._jinja_envs[env_name] = JinjaEnv(env_name) # new env
return cls._jinja_envs[env_name].jinja_env
#classmethod
def flush_env(cls, env_name):
with cls._env_lock:
if env_name not in cls._jinja_envs:
self = cls._jinja_envs[env_name] = JinjaEnv(env_name) # new env
else:
self = cls._jinja_envs[env_name]
self.client_cache.flush_all()
self.jinja_env = self.jinja_loader(self.jinja_bcc, env_name)
return self.jinja_env
Used like:
template = JinjaEnv.get_env('example_env').get_template('example_template')