python pickle dump and load private variables - python

I need to protect a class variable. But what to do if the class supports save and load options?
import numpy as np
import pickle
class data(object):
def __init__(self):
self.__a = range(100)
#property
def a(self):
return self.__a
def save(self, path):
pickle.dump(self,open(path, 'wb'), protocol=2)
def load(self, path):
obj = pickle.load(open(path, 'wb'))
self.__a = obj.a
This is simple but __aattribute is no more protected because calling instance.a returns the exact instance.__a list and it can changed from the outside which is dangerous in my case.
is there any way around this?

To protect lists from being changed, you can return a copy of the list by your property:
#property
def a(self):
return list(self.__a)

Instead of non-standard save/load methods, stick with the standard pythonic way of pickling objects, i.e. using pickle.dump and pickle.load directly.
The data members will be as protected after loading as they were before dumping, i.e. your object behaves the same.
class data(object):
def __init__(self):
self.__a = range(100)
#property
def a(self):
return self.__a
obj = data()
# when you want to save, do:
x = pickle.dumps(obj)
# and for loading, do:
obj = pickle.loads(x)
obj.__dict__
=> {'_data__a': [0,
1,
2,
3,
...
]}
This approach has many advantages, e.g. you can safely pickle objects which reference instances of your class data.

Related

How to fetch class instance from class variable (from outside the class)?

Let's say I have this:
from PySide2 import QtWidgets
class MyClass(object):
def __init__(self, parent=None):
self.class_variable = QtWidgets.QWidget()
class_instance = MyClass()
variable = class_instance.class_variable
class_instance_returned = mystery_method(variable) # How to make this return class_instance?
How should I define mystery_method so that it would return the class_instance instance?
The real-world case I have is that I'm sending a QWidget which I'm using as a base instance for .ui file loading into a function. Inside this function I need to figure out which class instance it belongs to.
Python 2.7
class MyClass(object):
def foo():
return 'bar'
instance = MyClass()
def mystery_method(method):
return method.im_self.__class__
print mystery_method(instance.foo)
Python 3
class MyClass(object):
def foo():
return 'bar'
instance = MyClass()
def mystery_method(method):
return method.__self__.__class__
print mystery_method(instance.foo)
EDIT
After the OP was edited:
class ParentClass():
def foo():
return 'bar'
class MyClass(object):
def __init__(self, parent=None):
self.instance_attribute = ParentClass()
def mystery_method(method):
return method.__class__
class_instance = MyClass()
print mystery_method(class_instance.instance_attribute)
One way would we to define foo as a custom property that returns both its value and the related instance when its value is fetched:
from collections import namedtuple
class Prop(object):
def __init__(self, val):
self.val = val
def __get__(self, instance, type):
return namedtuple('Prop', ('value', 'instance'))(self.val, instance)
def __set__(self, instance, val):
self.val = val
class MyClass(object):
foo = Prop('bar')
Now in your program you can explicitly use its value and the related instance using foo's value and instance attributes respectively.
Demo:
>>> instance = MyClass()
>>> instance.foo
Prop(value='bar', instance=<__main__.MyClass object at 0x10effbcd0>)
>>> instance.foo.value
'bar'
>>> instance.foo.instance
<__main__.MyClass object at 0x10effbcd0>
In general you cannot (at least not without a lot of searching through all the objects in the system) but if all you want is to find which instances of a class match a particular value then it's fairly easy.
You can create a set of all instances and iterate over them to find what you need.
from weakref import WeakSet
class MyClass(object):
_instances = WeakSet()
def __init__(self, foo):
self._instances.add(self)
self.foo = foo
#classmethod
def findFoo(cls, foo):
return [instance for instance in cls._instances if instance.foo == foo]
>>> instance1 = MyClass('bar')
>>> instance2 = MyClass('baz')
>>> MyClass.findFoo('baz')
[<__main__.MyClass object at 0x7f6723308f50>]
>>> MyClass.findFoo('bar')
[<__main__.MyClass object at 0x7f6723308c50>]
Note that deleting the object won't remove it immediately, it may not go until garbage collected:
>>> del instance1
>>> MyClass.findFoo('bar')
[<__main__.MyClass object at 0x7f6723308c50>]
>>> import gc
>>> gc.collect()
16
>>> MyClass.findFoo('bar')
[]
However in general you would be better to keep the reference to the original object hanging around and just use that.
Also, note that you cannot reliably tell which instance holds 'bar' if it is stored in more than one object: they could be the same 'bar' or they could be different ones, and whether they are the same or different is an implementation detail.

Python : use a class methods as static , when its implemented as instance methods

I have a big class which has a lot of functions and attributes.
the instances are created from data in a remote database.
the process of creating each instance is very long and heavy.
In performance sake ive created a bunch class from this heavy class.
so accessing the attributed is easy and works great .
the problem is how to use the methods from that class.
ex :
class clsA():
def __init__(self,obj):
self.attrA=obj.attrA
def someFunc(self):
print self
class bunchClsA(bunch):
def __getattr__(self, attr):
# this is the problem:
try:
#try and return a func
func = clsA.attr
return func
except:
# return simple attribute
return self.attr
Clearly this dosent work , Is there a way i could access the instance function staticly and override the "self" var ?
Found out a nice solution to the problem :
from bunch import Bunch
import types
#Original class:
class A():
y=6
def __init__(self,num):
self.x=num
def funcA(self):
print self.x
#class that wraps A using Bunch(thats what i needed .. u can use another):
class B(Bunch):
def __init__(self, data, cls):
self._cls = cls # notice, not an instance just the class it self
super(B, self).__init__(data)
def __getattr__(self, attr):
# Handles normal Bunch, dict attributes
if attr in self.keys():
return self[attr]
else:
res = getattr(self._cls, attr)
if isinstance(res, types.MethodType):
# returns the class func with self overriden
return types.MethodType(res.im_func, self, type(self))
else:
# returns class attributes like y
return res
data = {'x': 3}
ins_b = B(data, A)
print ins_b.funcA() # returns 3
print ins_b.y # returns 6
And this solves my issue, its a hack and if you have the privileges, redesign the code.

Python2 introspection namespace

I try python introspection in some weird manner.
For example, I have Class LoggerManager which incapsulate pool of specific loggers classes for statistic. I know this is no standard way to do it, but I can't use mixins due to my object of class SpecificLogger is serializable to json in code and I really don't want to pass self.data throw params to init (in this case I need to rewrite many rows code and get problem with garbage in serialization again).
class LoggerManager(object):
def __init__(self):
self.data
self.b = SpecificLogger()
self.c = SpecificLogger2()
...
class SpecificLogger(LoggerGeneral):
def get_data(self):
global data #now I want get object from namespace object of LoggerManager, not really global
do_something_with_data(data)
I want behavior like this code with mixins:
import json
class A(object):
def __init__(self):
self.data = 'something'
def create_pool_of_specific_objects(self):
self.obj = B()
class B(A):
def __init__(self):
A.__init__(self)
def do_something_with_data(self):
print(self.data)
self.data = 'new_data'
print(self.data)
def save(self):
return json.dumps(self.__dict__, ensure_ascii=False)
def hack_save(self):
data_to_dumped = {x:y for x,y in self.__dict__.iteritems() if x != 'obj'}
return json.dumps(data_to_dumped, ensure_ascii=False)
b=B()
b.create_pool_of_specific_objects()
b.do_something_with_data()
b.save() #will raise exception due to we have all stuff from instance of class A there
b.hack_save() #will work but it is very ugly and unusable with runtime modify object of A class
Now I wrote code with GC, but using method get_objects I have some sort of overhead, is not it?
import json
import gc
class A(object):
def __init__(self):
self.data = 'something'
self.obj = B()
class B(object):
def __init__(self): pass
def do_something_with_data(self):
for obj in gc.get_objects(): #or even for obj in globals().values()
if isinstance(obj, A):
print(obj.data)
obj.data = 'new_data'
print(obj.data)
def save(self):
return json.dumps(self.__dict__, ensure_ascii=False)
a=A()
b=B()
b.do_something_with_data()
b.save() #will work
Any suggestion to do it with introspection and not inheritance and GC overhead? Maybe python save ref to namespace above and I can get A instance in friendly manner?
Ok, guyz. Correctly asked question includes right answer itself.
All I need is:
import inspect
def my_method(self):
parent_self = inspect.currentframe().f_back.f_locals['self']
do_something_with_parent_self(parent_self)

python: is this a good way to use the same function name for both classmethod and method?

class A(object):
#classmethod
def print(cls):
print 'A'
def __print(self):
print 'B'
def __init__(self):
self.print = self.__print
a = A()
a.print()
A.print()
I think it's too ugly, is there any other method to implement the same features? do not say combinemethod, because it creates an object every time.
The simplest solution is to create a descriptor decorator like classmethod but that also passes the instance to the method:
from functools import partial
class descriptormethod(object):
def __init__(self, fn):
self.fn = fn
def __get__(self, instance, owner):
return partial(self.fn, instance, owner)
class A(object):
#descriptormethod
def print_(self, cls):
print 'A' if self is None else 'B'
Don't worry about the overhead of the descriptor or partial objects; it's no different from what happens when you call an instance or class method normally.

How to create and store instances of a class at initialization?

Using Python 3.3, I want to bind a class Test to another class called TestManager so that the manager creates instances of Test and stores them to give an access to them afterwards.
In a nutshell (I mean, Python shell...), I want to be able to do this (assuming name is an attribute of Test):
> t = Test.objects.get(id=3)
> t.name
# Returns 'Name 3'
The trick is that my collection of objects is a "static" collection, in a sense that it is created at first (not by any user) and then never modified or deleted, nor its records removed or edited. It's fixed.
So here is the code I tried:
class TestManager:
def __init__(self, *args, **kwargs):
self._tests = [Test(name='Name {}'.format(i)) for i in range(100)]
def get(self, id):
return self._tests[id]
class Test:
objects = TestManager()
def __init__(self, name=''):
self.name = name
Aaaand, as expected, NameError: global name 'Test' is not defined due to the circular initialization. Ideally, I should have a create() method in the manager which would take care of adding elements in the list (instead of the __init__()), but that would mean that the creation is not done in the manager but elsewhere.
The "best" solution I came up with, so far, is to check first in the get() method if the list is empty, and thus call a fill_the_damn_list() method, but it seems very hackish to me. Another way to do that would be to use a dict instead of a list and to create the instances on the fly at first get(). The advantage of the latter one is that it does not create useless/never get()-ed instances, but with only an hundred of them in total, I am not sure it really matters, and the hackish-ness of this solution looks quite the same to me...
As I am quite new to Python (if it isn't clear enough...), I wonder if there is a better way to do that and to keep it simple. I am also OK to refactor if needed, but I didn't find any better solution yet...
Your design seems a little odd -- it's unclear why the Test class needs a reference to a TestManger instance. Regardless, I think the following will make that happen. It uses a metaclass to create the objects attribute of the Test class and adds the _tests attribute you want to the TestManger instance it created -- which all go into making this a rather peculiar answer...fitting, I suppose. ;-)
class TestManager:
def __init__(self, *args, **kwargs):
print('creating TestManager')
def get(self, id):
return self._tests[id]
class TestMetaClass(type):
def __new__(mcl, name, bases, classdict):
# add an "objects" attribute to the class being created
classdict['objects'] = tm = TestManager()
cls = type.__new__(mcl, name, bases, classdict)
# add a "_tests" attribute to the TestManager instance just created
# (can't use class's name, since it hasn't been returned yet)
tm._tests = [cls(name='Name {}'.format(i)) for i in range(100)]
return cls
class Test(metaclass=TestMetaClass):
def __init__(self, name=''):
self.name = name
t = Test.objects.get(3)
print(t.name)
I completely agree with sean's comment: your design is strange and, I think, quite useless, and this is causing problems even before starting using it. Anyway, if you want to do that you can use a lot of different methods.
The simple way:
class TestManager:
def __init__(self, *args, **kwargs):
self._tests = [Test(name='Name {}'.format(i)) for i in range(100)]
def get(self, id):
return self._tests[id]
class Test:
objects = None
def __init__(self, name=''):
self.name = name
Test.objects = TestManager()
An other approach can be using a decorator:
>>> class TestManager(object):
... def __init__(self, *args, **kwargs):
... self._tests = []
... def init_class(self, cls):
... self._tests = [cls(name='Name {}'.format(i)) for i in range(100)]
... cls.objects = self
... return cls
... def get(self, id):
... return self._tests[id]
...
>>> manager = TestManager()
>>> #manager.init_class
... class Test(object):
... def __init__(self, name=''):
... self.name = name
...
>>> manager.get(5)
<__main__.Test object at 0x7f4319db8110>
The above recipe works if TestManager is a Singleton, but if it is not a singleton you simply have to remember to call TestManager.init_class(TheClass) before accessing the class instances, and that can be done anywhere in your code.
You can also use getters for this:
>>> class TheGetter(object):
... def __init__(self, cls):
... self._cls = cls
... self._inst = None
... def __get__(self, inst, owner):
... if self._inst is None:
... self._inst = self._cls()
... return self._inst
...
>>> class Test(object):
... objects = TheGetter(TestManager)
... def __init__(self, name):
... self.name = name
...
>>> Test.objects.get(5)
<__main__.Test object at 0x7f431690c0d0>

Categories