How to Make Type Cast for Python Custom Class

How to make type cast for python custom class

As noted by Anand in comments, what you're looking for is object serialization and deserialization. One way to achieve this is through the pickle (or cPickle) module:

>>> import pickle

>>> class Example():
... def __init__(self, x):
... self.x = x
...
>>> a = Example('foo')
>>> astr = pickle.dumps(a) # (i__main__\nExample\np0\n(dp1\nS'x'\np2\nS'foo'\np3\nsb.
>>> b = pickle.loads(astr)
>>> b
<__main__.Example instance at 0x101c89ea8>
>>> b.x
'foo'

Note, however, that one gotcha in using the pickle module is dealing with implementation versions. As suggested in the Python docs, if you want an unpickled instance to automatically handle implementation versioning, you may want to add a version instance attribute and add a custom __setstate__ implementation: https://docs.python.org/2/library/pickle.html#object.setstate. Otherwise, the version of the object at serialization time will be exactly what you get at deserialization time, regardless of code changes made to the object itself.

How to cast a variable to custom Class in python

You can store your class in a dictionary and then by your json input you can convert json to a dictionary from model to class:

import json

class User:
def __str__(self) -> str:
return "User Class"

class Admin:
def __str__(self) -> str:
return "Admin Class"

models= {"User": User, "Admin": Admin}

jsonStr = '{"model1":"User","model2":"Admin"}'
obj = json.loads(jsonStr)

convertedObj = {k:models[v] for k,v in obj.items()}

print(convertedObj["model1"]())
print(convertedObj["model2"]())

The output will be:

User Class
Admin Class

Casting a custom class to a dict in python

If you define __iter__, it'll Just Work(tm):

class A(object):
def __init__(self, a, b):
self.a = a
self.b = b
def __iter__(self):
return vars(self).iteritems()

gives

>>> A(2,3)
<__main__.A object at 0x101ea70d0>
>>> dict(A(2,3))
{'a': 2, 'b': 3}

and you can return or yield whatever you like. That said, I second the suggestion in the comments that you should really just implement a .to_dict() method instead, as often __iter__ is too useful for other purposes to waste on this one.

How do you cast an instance to a derived class?

Rather than "casting", I think you really want to create an UnapprovedUser rather than a User when invoking UnapprovedUser.get(). To do that:

Change User.get to actually use the cls argument that's passed-in:

@classmethod
def get(cls, uid):
ldap_data = LdapUtil.get(uid + ',' + self.base_dn)
return cls._from_ldap(ldap_data)

You'll need to do something similar in _from_ldap. You didn't list the code for _from_ldap, but I assume that at some point it does something like:

result = User(... blah ...)

You want to replace this with:

result = cls(... blah ...)

Remember: in Python a class object is a callable that constructs instances of that class. So you can use the cls parameter of a classmethod to construct instances of the class used to call the classmethod.

How to cast object in Python

There is no casting as the other answers already explained. You can make subclasses or make modified new types with the extra functionality using decorators.

Here's a complete example (credit to How to make a chain of function decorators?). You do not need to modify your original classes. In my example the original class is called Working.

# decorator for logging
def logging(func):
def wrapper(*args, **kwargs):
print func.__name__, args, kwargs
res = func(*args, **kwargs)
return res
return wrapper

# this is some example class you do not want to/can not modify
class Working:
def Do(c):
print("I am working")
def pr(c,printit): # other example method
print(printit)
def bla(c): # other example method
c.pr("saybla")

# this is how to make a new class with some methods logged:
class MutantWorking(Working):
pr=logging(Working.pr)
bla=logging(Working.bla)
Do=logging(Working.Do)

h=MutantWorking()
h.bla()
h.pr("Working")
h.Do()

this will print

h.bla()
bla (<__main__.MutantWorking instance at 0xb776b78c>,) {}
pr (<__main__.MutantWorking instance at 0xb776b78c>, 'saybla') {}
saybla

pr (<__main__.MutantWorking instance at 0xb776b78c>, 'Working') {}
Working

Do (<__main__.MutantWorking instance at 0xb776b78c>,) {}
I am working

In addition, I would like to understand why you can not modify a class. Did you try? Because, as an alternative to making a subclass, if you feel dynamic you can almost always modify an old class in place:

Working.Do=logging(Working.Do)
ReturnStatement.Act=logging(ReturnStatement.Act)

Update: Apply logging to all methods of a class

As you now specifically asked for this. You can loop over all members and apply logging to them all. But you need to define a rule for what kind of members to modify. The example below excludes any method with __ in its name .

import types
def hasmethod(obj, name):
return hasattr(obj, name) and type(getattr(obj, name)) == types.MethodType

def loggify(theclass):
for x in filter(lambda x:"__" not in x, dir(theclass)):
if hasmethod(theclass,x):
print(x)
setattr(theclass,x,logging(getattr(theclass,x)))
return theclass

With this all you have to do to make a new logged version of a class is:

@loggify
class loggedWorker(Working): pass

Or modify an existing class in place:

loggify(Working)

Object type casting in Python (design suggestion)

Perhaps something like this

class CommercialPack(object):
def __init__(self, pack):
self.__dict__.update(pack.__dict__)

You can even do this if you don't mind sharing state between the pack and the commercial pack

class CommercialPack(object):
def __init__(self, pack):
self.__dict__ = pack.__dict__

It should be ok in your example since you aren't keeping any other references to the pack object

eg.

PER_KM_PRICE = 100

class Pack(object):
def __init__(self, name, weight):
self.name = name
self.weight = weight


class CommercialPack(Pack):
def __init__(self, pack):
self.__dict__ = pack.__dict__

def get_delivery_price(self, distance):
return self.weight * PER_KM_PRICE * distance

def get_pack():
return Pack("pack", 20)

cp = CommercialPack(get_pack())
print cp.get_delivery_price(3)


Related Topics



Leave a reply



Submit