I'm cleaning up a python object class, focusing mainly on how the object is created. The __init__ method creates a an empty dictionary that needs to be filled almost instantly. But this should NOT happen within the __init__, as the method used will vary widely. Here's an example:
class Storage:
def __init__(self):
self.data = {}
def fill_1(self):
self.data['solo'] = 'all alone'
def fill_2(self, buddy, bff):
self.data['buddy'] = buddy
self.data['bff'] = bff
def fill_3(self, that_guy, house):
self.data[that_guy] = house
Normally, I can just call one after the other like so:
box = Storage.Storage()
box.fill_1()
However, this can be overwhelming when I create many of these objects sequentially. My goal is to use the __init__ method with one of the fill methods on the same line. I've tried using the call below:
box = Storage.Storage().fill_1()
But this does not create the object and instead returns None. So I have two questions:
Is my code returning a None object because the line is calling an instance method?
And how can I create the Storage object and then call it's fill method within the same line?
This is not an idiom you tend to see that often in python (though it's quite prevalent in many other languages, especially javascript), but you could do this by returning self from the mutator functions. (It looks like you were missing the self argument to the instance methods as well). This means you could also chain mutator calls -- Storage().fill_1().fill_2()
class Storage(object):
def __init__(self):
super(Storage, self).__init__()
data = {}
def fill_1(self):
data['solo'] = 'all alone'
return self
def fill_2(self, buddy, bff):
data['buddy'] = buddy
data['bff'] = bff
return self
def fill_3(self, that_guy, house):
data[that_guy] = house
return self
box = Storage().fill_1()
Make alternate constructors:
class Storage(object):
def __init__(self):
self.data = {}
#staticmethod
def filled_1():
obj = Storage()
obj.data['solo'] = 'all alone'
return obj
#staticmethod
def filled_2(self, buddy, bff):
obj = Storage()
obj.data['buddy'] = buddy
obj.data['bff'] = bff
return obj
#staticmethod
def filled_3(self, that_guy, house):
obj = Storage()
obj.data[that_guy] = house
return obj
Then you don't need to worry about separate creation and initialization calls, or muddle command-query separation with call chaining:
obj1 = Storage.filled_1()
obj2 = Storage.filled_2('Jenny', 'Joe')
...
Related
I am rather new to using classes. I struggle with functions (i.e. methods) in classes and how to access the classes attributes via method parameter.
My aim is to have a method accessing an instance's list (and the instances contained therein, yadda yadda)
While:
class dictclasser:
def __init__(self, attribute):
self.attribute = attribute
def printattr(self):
self.printattr2()
def printattr2(self):
return self.attribute
classcollection = []
while True:
attribute = input()
classcollection.append(dictclasser(attribute))
for i in classcollection:
print(i.printattr())
Returns None
class dictclasser:
def __init__(self, attribute):
self.attribute = attribute
def printattr(self):
return self.attribute
classcollection = []
while True:
attribute = input()
classcollection.append(dictclasser(attribute))
for i in classcollection:
print(i.printattr())
Returns everything as intended. I cannot figure out why printattr can access the instances attribute and printattr2 cannot. I have checked "Similar Question" to no avail.
Thanks in advance!
Because you missed a return statement in the first printattr. In order to propagate the return value of printattr2 onwards from printattr you have to return the returned value:
def printattr(self):
return self.printattr2()
Your printattr function has no return statement. Change
self.printattr2()
to
return self.printattr2()
How do you access an instance in an object and pass it to another 'main' object? I'm working with a parser for a file that parses different tags, INDI(individual), BIRT(event), FAMS(spouse), FAMC(children)
Basically there are three classes: Person, Event, Family
class Person():
def __init__(self, ref):
self._id = ref
self._birth : None
def addBirth(self, event):
self._birth: event
class Event():
def __init__(self, ref):
self._id = ref
self._event = None
def addEvent(self, event):
self._event = event
#**event = ['12 Jul 1997', 'Seattle, WA'] (this is generated from a function outside a class)
I want to transfer self._event from the Event class into addBirth method to add it into my person class. I have little knowledge on how classes and class inhertiances work. Please help!
If I understand your question, you want to pass an (for example) Event object to an instance of Person?
Honestly, I don't understand the intent of your code, but you probably just need to pass self from one class instance to the other class instance.
self references the current instance.
class Person:
def __init__(self):
self._events = []
def add_event(self, event)
self._events.append(event)
class Event:
def add_to_person(self, person):
person.add_event(self)
The most proper way to handle situations like this is to use getter and setter methods; data encapsulation is important in OO programming. I don't always see this done in Python where I think it should, as compared to other languages. It simply means to add methods to your classes who sole purpose are to return args to a caller, or modify args from a caller. For example
Say you have class A and B, and class B (caller) wants to use a variable x from class A. Then class A should provide a getter interface to handle such situations. Setting you work the same:
class class_A():
def __init__(self, init_args):
x = 0
def someMethod():
doStuff()
def getX():
return x
def setX(val):
x = val
class class_B():
def init(self):
init_args = stuff
A = class_A(init_args)
x = class_A.getX()
def someOtherMethod():
doStuff()
So if class B wanted the x property of an instance object A of class class_A, B just needs to call the getter method.
As far as passing instances of objects themselves, say if you wanted A to pass an already-created instance object of itself to a method in class B, then indeed, you simply would pass self.
I have a dict of different types for which I want to add a simple getter based on the name of the actual parameter.
For example, for three storage parameters, let's say:
self.storage = {'total':100,'used':88,'free':1}
I am looking now for a way (if possible?) to generate a function on the fly with some meta-programming magic.
Instead of
class spaceObj(object):
def getSize(what='total'):
return storage[what]
or hard coding
#property
def getSizeTotal():
return storage['total']
but
class spaceObj(object):
# manipulting the object's index and magic
#property
def getSize:
return ???
so that calling mySpaceObj.getSizeFree would be derived - with getSize only defined once in the object and related functions derived from it by manipulating the objects function list.
Is something like that possible?
While certainly possible to get an unknown attribute from a class as a property, this is not a pythonic approach (__getattr__ magic methods are rather rubyist)
class spaceObj(object):
storage = None
def __init__(self): # this is for testing only
self.storage = {'total':100,'used':88,'free':1}
def __getattr__(self, item):
if item[:7] == 'getSize': # check if an undefined attribute starts with this
return self.getSize(item[7:])
def getSize(self, what='total'):
return self.storage[what.lower()]
print (spaceObj().getSizeTotal) # 100
You can put the values into the object as properties:
class SpaceObj(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
storage = {'total':100,'used':88,'free':1}
o = SpaceObj(**storage)
print o.total
or
o = SpaceObj(total=100, used=88, free=1)
print o.total
or using __getattr__:
class SpaceObj(object):
def __init__(self, **kwargs):
self.storage = kwargs
def __getattr__(self,name):
return self.storage[name]
o = SpaceObj(total=100, used=88, free=1)
print o.total
The latter approach takes a bit more code but it's more safe; if you have a method foo and someone create the instance with SpaceObj(foo=1), then the method will be overwritten with the first approach.
>>> import new
>>> funcstr = "def wat(): print \"wat\";return;"
>>> funcbin = compile(funcstr,'','exec')
>>> ns = {}
>>> exec funcbin in ns
>>> watfunction = new.function(ns["wat"].func_code,globals(),"wat")
>>> globals()["wat"]=watfunction
>>> wat()
wat
I find it very interesting the way how SQLAlchemy constructing query strings, eg:
(Session.query(model.User)
.filter(model.User.age > 18)
.order_by(model.User.age)
.all())
As far as I can see, there applied some kind of Proxy Pattern. In my small project I need to make similar string construction using OOP approach. So, I tried to reconstitute this behavior.
Firstly, some kind of object, one of plenty similar objects:
class SomeObject(object):
items = None
def __init__(self):
self.items = []
def __call__(self):
return ' '.join(self.items) if self.items is not None else ''
def a(self):
self.items.append('a')
return self
def b(self):
self.items.append('b')
return self
All methods of this object return self, so I can call them in any order and unlimited number of times.
Secondly, proxy object, that will call subject's methods if it's not a perform method, which calls object to see the resulting string.
import operator
class Proxy(object):
def __init__(self, some_object):
self.some_object = some_object
def __getattr__(self, name):
self.method = operator.methodcaller(name)
return self
def __call__(self, *args, **kw):
self.some_object = self.method(self.some_object, *args, **kw)
return self
def perform(self):
return self.some_object()
And finally:
>>> obj = SomeObject()
>>> p = Proxy(obj)
>>> print p.a().a().b().perform()
a a b
What can you say about this implementation? Is there better ways to make the desirable amount of classes that would make such a string cunstructing with the same syntax?
PS: Sorry for my english, it's not my primary language.
Actually what you are looking at is not a proxy pattern but the builder pattern, and yes your implementation is IMHO is the classic one (using the Fluent interface pattern).
I don't know what SQLAlchemy does, but I would implement the interface by having the Session.query() method return a Query object with methods like filter(), order_by(), all() etc. Each of these methods simply returns a new Query object taking into account the applied changes. This allows for method chaining as in your first example.
Your own code example has numerous problems. One example
obj = SomeObject()
p = Proxy(obj)
a = p.a
b = p.b
print a().perform() # prints b
I am programming a simulations for single neurons. Therefore I have to handle a lot of Parameters. Now the Idea is that I have two classes, one for a SingleParameter and a Collection of parameters. I use property() to access the parameter value easy and to make the code more readable. This works perfect for a sinlge parameter but I don't know how to implement it for the collection as I want to name the property in Collection after the SingleParameter. Here an example:
class SingleParameter(object):
def __init__(self, name, default_value=0, unit='not specified'):
self.name = name
self.default_value = default_value
self.unit = unit
self.set(default_value)
def get(self):
return self._v
def set(self, value):
self._v = value
v = property(fget=get, fset=set, doc='value of parameter')
par1 = SingleParameter(name='par1', default_value=10, unit='mV')
par2 = SingleParameter(name='par2', default_value=20, unit='mA')
# par1 and par2 I can access perfectly via 'p1.v = ...'
# or get its value with 'p1.v'
class Collection(object):
def __init__(self):
self.dict = {}
def __getitem__(self, name):
return self.dict[name] # get the whole object
# to get the value instead:
# return self.dict[name].v
def add(self, parameter):
self.dict[parameter.name] = parameter
# now comes the part that I don't know how to implement with property():
# It shoule be something like
# self.__dict__[parameter.name] = property(...) ?
col = Collection()
col.add(par1)
col.add(par2)
col['par1'] # gives the whole object
# Now here is what I would like to get:
# col.par1 -> should result like col['par1'].v
# col.par1 = 5 -> should result like col['par1'].v = 5
Other questions that I put to understand property():
Why do managed attributes just work for class attributes and not for instance attributes in python?
How can I assign a new class attribute via __dict__ in python?
Look at built-in functions getattr and setattr. You'll probably be a lot happier.
Using the same get/set functions for both classes forces you into an ugly hack with the argument list. Very sketchy, this is how I would do it:
In class SingleParameter, define get and set as usual:
def get(self):
return self._s
def set(self, value):
self._s = value
In class Collection, you cannot know the information until you create the property, so you define the metaset/metaget function and particularize them only later with a lambda function:
def metaget(self, par):
return par.s
def metaset(self, value, par):
par.s = value
def add(self, par):
self[par.name] = par
setattr(Collection, par.name,
property(
fget=lambda x : Collection.metaget(x, par),
fset=lambda x, y : Collection.metaset(x,y, par))
Properties are meant to dynamically evaluate attributes or to make them read-only. What you need is customizing attribute access. __getattr__ and __setattr__ do that really fine, and there's also __getattribute__ if __getattr__ is not enough.
See Python docs on customizing attribute access for details.
Have you looked at the traits package? It seems that you are reinventing the wheel here with your parameter classes. Traits also have additional features that might be useful for your type of application (incidently I know a person that happily uses traits in neural simulations).
Now I implemented a solution with set-/getattr:
class Collection(object):
...
def __setattr__(self, name, value):
if 'dict' in self.__dict__:
if name in self.dict:
self[name].v = value
else:
self.__dict__[name] = value
def __getattr__(self, name):
return self[name].v
There is one thing I quite don't like that much: The attributes are not in the __dict__. And if I have them there as well I would have a copy of the value - which can be dangerous...
Finally I succeded to implement the classes with property(). Thanks a lot for the advice. It took me quite a bit to work it out - but I can promise you that this exercise helps you to understand better pythons OOP.
I implemented it also with __getattr__ and __setattr__ but still don't know the advantages and disadvantages to the property-solution. But this seems to be worth another question. The property-solutions seems to be quit clean.
So here is the code:
class SingleParameter(object):
def __init__(self, name, default_value=0, unit='not specified'):
self.name = name
self.default_value = default_value
self.unit = unit
self.set(default_value)
def get(*args):
self = args[0]
print "get(): "
print args
return self._v
def set(*args):
print "set(): "
print args
self = args[0]
value = args[-1]
self._v = value
v = property(fget=get, fset=set, doc='value of parameter')
class Collection(dict):
# inheriting from dict saves the methods: __getitem__ and __init__
def add(self, par):
self[par.name] = par
# Now here comes the tricky part.
# (Note: this property call the get() and set() methods with one
# more argument than the property of SingleParameter)
setattr(Collection, par.name,
property(fget=par.get, fset=par.set))
# Applying the classes:
par1 = SingleParameter(name='par1', default_value=10, unit='mV')
par2 = SingleParameter(name='par2', default_value=20, unit='mA')
col = Collection()
col.add(par1)
col.add(par2)
# Setting parameter values:
par1.v = 13
col.par1 = 14
# Getting parameter values:
par1.v
col.par1
# checking identity:
par1.v is col.par1
# to access the whole object:
col['par1']
As I am new I am not sure how to move on:
how to treat follow up questions (like this itself):
get() is seems to be called twice - why?
oop-design: property vs. "__getattr__ & __setattr__" - when should I use what?
is it rude to check the own answer to the own question as accepted?
is it recommended to rename the title in order to put correlated questions or questions elaborated with the same example into the same context?
Other questions that I put to understand property():
Why do managed attributes just work for class attributes and not for instance attributes in python?
How can I assign a new class attribute via __dict__ in python?
I have a class that does something similar, but I did the following in the collection object:
setattr(self, par.name, par.v)