this is related to python, dynamically implement a class onthefly.
when i restarted my pc, couldnt get back to add comments to the post - below is an example to explain what meant by save the class_with_the_methods_used
class bank(object):
def __init__(self, bal=0):
self.bal = bal
def deposit(self, amount):
self.bal+=amount
print self.bal
def debit(self, amt):
self.bal-=amt
print self.bal
bank.debit = debit
myacct = bank()
myacct.deposit(1000) # prints 1000
myacct.debit(99) # print 901
dir(myacct) # print [ ....'bal', 'debit', 'deposit']
then i used pickle and saved the object myacct
after saving, restarted my python and tried the commands below
>>> import pickle
>>> obj = pickle.load(open('bank.pkl'))
>>> dir(obj) # prints [....'bal', 'deposit']
note that 'debit' is not among the attributes . So my problem is how to make methods like 'debit' persistent?
Check out the new module (http://docs.python.org/library/new.html)
It has a lot of tools for doing things dynamically. The problem you are having is debit is not a instance method, it is just a normal function. Methods defined in classes are different than functions defined outside.
This is due to the way pickle dumps custom classes.
>>> class Bank(object):
... pass
...
>>> def debit(self, amt):
... print amt
...
>>> Bank.debit = debit
>>>
>>> acct = Bank()
>>> acct.debit
<bound method Bank.debit of <__main__.Bank object at 0x023B57D0>>
>>> import pickle
Look at the following:
>>> print pickle.dumps(acct)
ccopy_reg
_reconstructor
p0
(c__main__
Bank
p1
c__builtin__
object
p2
Ntp3
Rp4
.
You'll see that in fact the entire instance isn't pickled; instead, pickle simply records that it is an instance of Bank and recreates it by re-instantiating Bank. You will have to define a custom pickle protocol if you want to do this properly, which is complicated.
Related
I have a function below which I want to output lines of values relating to 'O', instead it prints the location of these values, how do I amend this? allReactions is an empty array initially. I've tried a number of ways to get around this but keep getting errors. Also I think my methods are less efficient than can be.
allReactions = []
reactionFile = "/Databases/reactionsDatabase.txt"
with open(reactionFile) as sourceFile:
for line in sourceFile:
if line[0] == "!" or len(line.strip()) == 0: continue
allReactions.append(Reaction(line, sourceType="Unified Data"))
def find_allReactions(allReactions, reactant_set):
reactant_set = set(reactant_set)
relevant_reactions = []
previous_reactant_count = None
while len(reactant_set) != previous_reactant_count:
previous_reactant_count = len(reactant_set)
for reaction in allReactions:
if set(reaction.reactants).issubset(reactant_set):
relevant_reactions.append(reaction)
reactant_set = reactant_set.union(set(reaction.products))
return relevant_reactions
print find_allReactions(allReactions, ["O"])
You are trying to print a list of Reaction objects. By default, python prints a class object's ID because it really doesn't have much to say about it. If you have control over the class definition, you can change that by adding __str__ and __repr__ method to the class.
>>> class C(object):
... pass
...
>>> print C()
<__main__.C object at 0x7fbe3af3f9d0>
>>> class C(object):
... def __str__(self):
... return "A C Object"
...
>>> print C()
A C Object
>>>
If you don't have control of the class... well, the author didn't implement a pretty view of the class. You could create subclasses with the methods or write a function to pull out the stuff you want.
I am trying to extend arrow and fail to understand how I can replicate the functionality of the base classes. This is probably due to a lack of clear understanding on how to extend classes in modules (emphasized by my arrow case - this is to say that the question is probably more general than limited to arrow only).
arrow basic usage:
>>> import arrow
>>> arrow.now()
<Arrow [2016-11-19T15:13:23.897484+01:00]>
>>> arrow.get("2016-11-20")
<Arrow [2016-11-20T00:00:00+00:00]>
I would like to add a when method which will return 'today', 'tomorrow' or 'later'. I first tried this:
import arrow
class MyArrow(arrow.Arrow):
def __init__(self, *args):
arrow.Arrow.__init__(self, *args)
def when(self):
now = arrow.now()
end_today = now.ceil('day')
end_tomorrow = now.replace(days=+1).ceil('day')
start_tomorrow = now.replace(days=+1).floor('day')
if self < end_today:
return 'today'
elif self < end_tomorrow:
return 'tomorrow'
else:
return 'later'
if __name__ == "__main__":
tom = MyArrow.now().replace(days=+1)
print(tom.when())
someday = MyArrow.get("2016-11-19")
The result is
tomorrow
Traceback (most recent call last):
File "D:/Dropbox/dev/domotique/testing/myarrow.py", line 23, in <module>
someday = MyArrow.get("2016-11-19")
AttributeError: type object 'MyArrow' has no attribute 'get'
So the first part worked, but get() failed. I had a look at the sources and get is in ArrowFactory. If I extend ArrowFactory instead of Arrow I will be able to use get but not now() anymore.
This is the point I am at loss: the "basic usage" above shows that I can call arrow.whatever_is_available no matter if it is defined in the class Arrow or ArrowFactory.
How does this work?
How can I add my when method to keep the rest of arrow as it is (and all its methods)?
Extensible for your own Arrow-derived types
is one of the highlighted features in Arrow's documentation, which actually demonstrates exactly how to create and use a custom Arrow subclass:
Factories
Use factories to harness Arrow’s module API for a custom Arrow-derived
type. First, derive your type:
>>> class CustomArrow(arrow.Arrow):
...
... def days_till_xmas(self):
...
... xmas = arrow.Arrow(self.year, 12, 25)
...
... if self > xmas:
... xmas = xmas.replace(years=1)
...
... return (xmas - self).days
Then get and use a factory for it:
>>> factory = arrow.Factory(CustomArrow)
>>> custom = factory.utcnow()
>>> custom
>>> <CustomArrow [2013-05-27T23:35:35.533160+00:00]>
>>> custom.days_till_xmas()
>>> 211
You can then call the .get, .now and .utcnow methods on the factory and get your custom subclass, with its .when method.
This is specific to dealing with Arrow and its module-level API; with simpler modules, you could just subclass their classes directly.
So Python isn't my strong suit and I've encountered what I view to be a strange issue. I've narrowed the problem down to a few lines of code, simplifying it to make asking this question easier. I have a list of objects, this object:
class FinalRecord():
ruid = 0
drugs = {}
I create them in the shell like this:
finalRecords = []
fr = FinalRecord()
fr.ruid = 7
finalRecords.append(fr)
fr2 = FinalRecord()
fr2.ruid = 10
finalRecords.append(fr2)
As soon as I want to change the drugs dict on one object, it changes it for the other one too
finalRecords[0].drugs["Avonex"] = "Found"
I print out this:
finalRecords[1].drugs
and it shows:
{'Avonex':'Found'}
When I'm expecting it to actually be empty. I know I'm not completely understand how Python is working with the objects, can anyone help me out here?
The reason for this is because drugs is a class attribute. So if you change it for one object it will in fact change in others.
If you are looking to not have this behaviour, then you are looking for instance attributes. Set drugs in your __init__ like this:
class FinalRecord():
def __init__(self):
self.ruid = 0
self.drugs = {}
Take note of the use of self, which is a reference to your object.
Here is some info on class vs instance attributes
So, full demo illustrating this behaviour:
>>> class FinalRecord():
... def __init__(self):
... self.ruid = 0
... self.drugs = {}
...
>>> obj1 = FinalRecord()
>>> obj2 = FinalRecord()
>>> obj1.drugs['stuff'] = 2
>>> print(obj1.drugs)
{'stuff': 2}
>>> print(obj2.drugs)
{}
You define drugs as a class attribute, not an instance attribute. Because of that, you are always modifying the same object. You should instead define drugs in the __init__ method. I would also suggest using ruid as an argument:
class FinalRecord():
def __init__(self, ruid):
self.ruid = ruid
self.drugs = {}
It could then be used as this:
fr = FinalRecord(7)
finalRecords.append(fr)
fr2 = FinalRecord(10)
finalRecords.append(fr2)
Or more simply:
finalRecords.append(FinalRecord(7))
finalRecords.append(FinalRecord(10))
I have this:
class Klasse1:
variable1 = "haha"
print Klasse1.variable1
and this:
class Klasse1:
variable1 = "haha"
Object1 = Klasse1()
print Object1.variable1
Why would I use the second (too much code) instead of the first (obviously easier)? In many sites and tutorials I've seen people create objects for something they could easily get without creating them.
You create objects to hold state. If you had something like:
class Wallet(object):
balance = 0
It wouldn't make sense to share the same balance between multiple instances of the class. You'd want to create a new instance of Wallet for each bit of money you're trying to track.
Because you'd use it by doing something like:
fred.wallet = Wallet
jim.wallet = Wallet # same object!
So now when Fred spends money
fred.wallet.balance -= 3.50
Jim spends that money too.
>>> print(jim.wallet.balance)
3.50
Instead you'd want to create INSTANCES of the class Wallet and give each one its own state
class Wallet(object):
def __init__(self, balance=0):
# __init__ is called when you instantiate the class
self.balance = balance
fred.wallet = Wallet()
jim.wallet = Wallet()
Now when Fred spends money:
fred.wallet.balance -= 3.50
Jim won't be affected because his Wallet object is a different instance
>>> print(jim.wallet.balance)
0
This is a tough question to answer succinctly but it comes down to when you want to have more than one instance of Klasse1. If you know you'll only ever need the class and never instantiate it, you'll be fine. If you do instantiate it, (ie calling the class and using the returned object), you can change the variable1 member without modifying the class' variable:
class Klasse1:
variable1 = "haha"
foo = Klasse1()
print foo.variable1
>>>'haha'
foo.variable1 = 123
print Klasse1.variable1
>>>'haha'
If you made another instance of Klasse1, it's variable1 would still be 'haha' even after altering foo's variable1.
bar = Klasse1()
print bar.variable1
>>>'haha'
What's sort of tricky is that if you change Klasse1.variable1, only bar.variable1 would change, foo.variable1 would remain 123.
Klasse1.variable1 = "this isn't funny"
print foo.variable1
>>>123
print bar.variable1
>>>"this isn't funny"
print Klasse1.variable1
>>>"this isn't funny"
I have a function below which I want to output lines of values relating to 'O', instead it prints the location of these values, how do I amend this? allReactions is an empty array initially. I've tried a number of ways to get around this but keep getting errors. Also I think my methods are less efficient than can be.
allReactions = []
reactionFile = "/Databases/reactionsDatabase.txt"
with open(reactionFile) as sourceFile:
for line in sourceFile:
if line[0] == "!" or len(line.strip()) == 0: continue
allReactions.append(Reaction(line, sourceType="Unified Data"))
def find_allReactions(allReactions, reactant_set):
reactant_set = set(reactant_set)
relevant_reactions = []
previous_reactant_count = None
while len(reactant_set) != previous_reactant_count:
previous_reactant_count = len(reactant_set)
for reaction in allReactions:
if set(reaction.reactants).issubset(reactant_set):
relevant_reactions.append(reaction)
reactant_set = reactant_set.union(set(reaction.products))
return relevant_reactions
print find_allReactions(allReactions, ["O"])
You are trying to print a list of Reaction objects. By default, python prints a class object's ID because it really doesn't have much to say about it. If you have control over the class definition, you can change that by adding __str__ and __repr__ method to the class.
>>> class C(object):
... pass
...
>>> print C()
<__main__.C object at 0x7fbe3af3f9d0>
>>> class C(object):
... def __str__(self):
... return "A C Object"
...
>>> print C()
A C Object
>>>
If you don't have control of the class... well, the author didn't implement a pretty view of the class. You could create subclasses with the methods or write a function to pull out the stuff you want.