I have 2 different ways to set up a python class. One that automaticly runs the class function, and one that you need to run manually.
Manually running function:
class testclass:
def __init__(self, value):
self.value = value
def validator(self):
data = self.value[0] + self.value[1]
data = int(data)
return data
theClass = testclass('123456')
print(theClass.validator())
This prints "12"
Automaticly running the function:
class testclass:
def __init__(self, value):
self.value = value
self.validator()
def validator(self):
data = self.value[0] + self.value[1]
data = int(data)
return data
theClass = testclass('123456')
print(theClass)
this prints "<main.testclass object at 0x011C72B0>"
How can i run the class function automaticly, and still get 12 as print output?
In the second version you are calling the validator function in __init__, but not returning the value that validator is returning. The problem is that __init__ is not able to return anything but None. What you can do is to assign the value to an instance variable:
class testclass:
value = 0
def __init__(self, value):
self.value = value
self.value = self.validator()
def validator(self):
data = self.value[0] + self.value[1]
data = int(data)
return data
theClass = testclass('123456')
print(theClass.value)
Ouptut:
12
In your automatic example, you are not calling 'theClass'. Any function calls need ().
You can rename your automatic validator the __call__ and call it as theClass().
See more at https://www.journaldev.com/22761/python-callable-call
If you simply want to print the output value, and not use it as a variable, you can define __str__ as part of your class.
class testclass(object):
def __init__(self, value):
self.value = value
def __str__(self):
return self.validator()
def validator(self):
data = self.value[0] + self.value[1]
data = int(data)
return data
>>> theClass = testclass('123456')
>>> print(theClass)
12
If you want to use it as a variable, such as theClass + 5, then using a custom class is not the way to go in this case.
Print inside the validator function:
class TestClass: # sticking to more Pythonic naming conventions
def __init__(self, value):
self.value = value
self.validator()
def validator(self):
print(int(self.value[0] + self.value[1]))
This will automatically print validation output whenever an instance is created:
>>> the_class = TestClass('123456')
12
Related
I have two classes with similar methods but there is a bit of difference in variables, here are the two classes:-
First class
class SerializerOne(object):
def validate(self, data):
instance = self.instance or self.Meta.model(**data)
instance.full_clean()
if data.get('certificate') and data.get('private_key'):
data = get_import_data(instance)
return data
def validate_validity_start(self, value):
if value is None:
value = default_validity_start()
return value
def validate_validity_end(self, value):
if value is None:
value = default_ca_validity_end()
return value
Second class
class SerializerTwo(object):
def validate(self, data):
instance = self.instance or self.Meta.model(**data)
instance.full_clean()
if data.get('certificate') and data.get('private_key'):
data = get_import_data(instance)
data.update({'ca': instance.ca})
return data
def validate_validity_start(self, value):
if value is None:
value = default_validity_start()
return value
def validate_validity_end(self, value):
if value is None:
value = default_cert_validity_end()
return value
Now this is what I have tried to keep the similar methods in a base class:-
Base class
class BaseSerializer(object):
def validate(self, data):
instance = self.instance or self.Meta.model(**data)
instance.full_clean()
if data.get('certificate') and data.get('private_key'):
data = get_import_data(instance)
return data
def validate_validity_start(self, value):
if value is None:
value = default_validity_start()
return value
def validate_validity_end(self, value):
if value is None:
value = default_ca_validity_end()
return value
When I inherit the above BaseSerializer
class SerializerOne(BaseSerializer):
pass
class SerializerTwo(BaseSerializer):
# Now in this class how can I add `data.update({'ca': instance.ca})` in the
# `validate` method, and also there is a bit of change in the
# method `validate_validity_end`,
I found that it can be done with super(), but I couldn't achieve it.
I'd redefine how you factor out the common methods a bit:
class BaseSerializer:
def get_import_data_hook(self, instance):
return get_import_data(instance)
def validate(self, data):
instance = self.instance or self.Meta.model(**data)
instance.full_clean()
if data.get('certificate') and data.get('private_key'):
data = self.get_import_data_hook(instance)
return data
def default_validity_start_hook(self):
return default_validity_start()
def validate_validity_start(self, value):
if value is None:
value = default_validity_start_hook()
return value
def default_validity_end_hook(self):
return default_ca_validity_end()
def validate_validity_end(self, value):
if value is None:
value = self.default_validity_end_hook()
return value
Any time you find yourself reusing all the code except a small tweak, put the tweak in its own hook. You don't have to put "hook" in the name, I just did that for emphasis. Instead, document it clearly.
Now you can do something like
class SerializerOne(BaseSerializer):
pass
and
class SerializerTwo(BaseSerializer):
def get_import_data_hook(self, instance):
data = super().get_import_data_hook(instance)
data.update({'ca': instance.ca})
return data
def default_validity_end_hook(self):
return default_cert_validity_end()
Right now, making a separate hook for default_validity_start_hook seems superfluous, but I added it for consistency. You may also want to look into the functions get_import_data, default_validity_start, and default_c*_validity_end to see if they belong directly in your class structure. It would certainly make the part of the code you show a lot simpler.
I have a class which has its own methods, for example:
class Original():
def __init__(self, dummy=False):
self.dummy = dummy
def funcA(self):
print('funcA')
And I want that, in case the variable dummy is true, all the custom made functions from class Original (e.g., funcA) become dummy (i.e., don't do nothing and return nothing).
I have managed to do a dummy class like this:
class Dummy(object):
def dummy(*args, **kwargs):
pass
def __getattr__(self, _):
return self.dummy
a = Dummy()
a.asd() # returns nothing
However, I can't manage to make a class in which the writen functions work in case the variable dummy is False, and they don't if the variable is True.
Any help please?
Managed to figure it out based on Alex Hall's comment. Hope this helps anyone out there:
class Dummy(object):
def __init__(self, isDummy):
self.isDummy = isDummy
def dummy(*args, **kwargs):
pass
def __getattribute__(self, item):
if item in ['isDummy', 'dummy'] or self.isDummy is False:
attr = object.__getattribute__(self, item)
return attr
else:
return self.dummy
def funcA(self):
print('funcA')
print('Dummy:')
dummy = Dummy(isDummy=True)
dummy.funcA() # returns nothing
print('---')
print('nonDummy:')
nonDummy = Dummy(isDummy=False)
nonDummy.funcA() # prints 'funcA'
I have created a decorator memoization class that I am actively using for cache my calls. There are already many excellent suggestions on how to implement python memoization.
The class that I have created currently uses get and set method calls to set the cacheTimeOut. They are called getCacheTimeOut() and setCacheTimeOut(). While this is an adequate solution. I was hoping to use the #property and #cacheTimeOut.setter decorators to enable the functions to be called directly as for example cacheTimeOut=120
The problem is in the details. I do not know how to make these properties accessible in the __get__ method. The __get__ method assigns the different function calls defined within the class to functions.partial.
Here is my script example designed for Python 2.7
import time
from functools import partial
import cPickle
class memoize(object):
def __init__(self, func):
self.func = func
self._cache = {}
self._timestamps = {}
self._cacheTimeOut = 120
self.objtype = None
def __new__(cls, *args, **kwargs):
return object.__new__(cls,*args, **kwargs)
def __get__(self, obj, objtype=None):
"""Used for object methods where decorator has been placed before methods."""
self.objtype = objtype
fn = partial(self, obj)
fn.resetCache = self.resetCache
fn.getTimeStamps = self.getTimeStamps
fn.getCache = self.getCache
fn._timestamps = self._timestamps
fn.setCacheTimeOut = self.setCacheTimeOut
fn.getCacheTimeOut = self.getCacheTimeOut
return fn
def __argsToKey(self, *args, **kwargs):
args = list(args)
for x, arg in enumerate(args): # remove instance from
if self.objtype:
if isinstance(arg, self.objtype):
args.remove(arg)
str = cPickle.dumps(args, 1)+cPickle.dumps(kwargs, 1)
return str
def __call__(self, *args, **kwargs):
"""Main calling function of decorator."""
key = self.__argsToKey(*args, **kwargs)
now = time.time() # get current time to query for key
if self._timestamps.get(key, now) > now:
return self._cache[key]
else:
value = self.func(*args, **kwargs)
self._cache[key] = value
self._timestamps[key] = now + self._cacheTimeOut
return value
def __repr__(self):
'''Return the function's docstring.'''
return self.func.__doc__
def resetCache(self):
"""Resets the cache. Currently called manually upon request."""
self._cache = {}
self._timestamps = {}
def getCacheTimeOut(self):
"""Get the cache time out used to track stale data."""
return self._cacheTimeOut
def setCacheTimeOut(self, timeOut):
"""Set the cache timeout to some other value besides 120. Requires an integer value. If you set timeOut to zero you are ignoring the cache"""
self._cacheTimeOut = timeOut
def getCache(self):
"""Returns the cache dictionary."""
return self._cache
def getTimeStamps(self):
"""Returns the encapsulated timestamp dictionary."""
return self._timestamps
#property
def cacheTimeOut(self):
"""Get cacheTimeOut."""
return self._cacheTimeOut
#cacheTimeOut.setter
def cacheTimeOut(self, timeOut):
"""Set cacheTimeOut."""
self._cacheTimeOut = timeOut
memoize
def increment(x):
increment.count+=1
print("increment.count:%d, x:%d"%(increment.count, x))
x+=1
return x
increment.count = 0 # Define the count to track whether calls to increment vs cache
class basic(object):
def __init__(self):
self.count = 0
#memoize
def increment(self, x):
self.count+=1
print("increment.count:%d, x:%d"%(increment.count, x))
x+=1
return x
def main():
print increment(3)
print increment(3)
# What I am actually doing
print increment.getCacheTimeOut() # print out default of 120
increment.setCacheTimeOut(20) # set to 20
print increment.getCacheTimeOut() # verify that is has been set to 120
# What I would like to do and currently does not work
print increment.cacheTimeOut
# Assign to property
increment.cacheTimeOut = 20
myObject = basic()
print myObject.increment(3)
print myObject.count
print myObject.increment(3)
print myObject.count
print myObject.increment(4)
print myObject.count
####### Unittest code.
import sys
import time
import unittest
from memoize import memoize
class testSampleUsages(unittest.TestCase):
# """This series of unit tests is to show the user how to apply memoize calls."""
def testSimpleUsageMemoize(self):
#memoize
def increment(var=0):
var += 1
return var
increment(3)
increment(3)
def testMethodBasedUsage(self):
"""Add the #memoize before method call."""
class myClass(object):
#memoize
def increment(self,var=0):
var += 1
return var
#memoize
def decrement(self, var=0):
var -=1
return var
myObj = myClass()
myObj.increment(3)
myObj.increment(3)
myObj.decrement(6)
myObj.decrement(6)
def testMultipleInstances(self):
#memoize
class myClass(object):
def __init__(self):
self.incrementCountCalls = 0
self.decrementCountCalls = 0
self.powCountCall = 0
# #memoize
def increment(self,var=0):
var += 1
self.incrementCountCalls+=1
return var
# #memoize
def decrement(self, var=0):
self.decrementCountCalls+=1
var -=1
return var
def pow(self, var=0):
self.powCountCall+=1
return var*var
obj1 = myClass() # Memoizing class above does not seem to work.
obj2 = myClass()
obj3 = myClass()
obj1.increment(3)
obj1.increment(3)
#obj2.increment(3)
#obj2.increment(3)
#obj3.increment(3)
#obj3.increment(3)
obj1.pow(4)
obj2.pow(4)
obj3.pow(4)
There's no way to attach a property to a single instance. Being descriptors, propertys must be part of a class definition in order to function. That means you can't easily add them to the partial object you create in __get__.
Now, you could create a class of your own to reimplement the behavior of partial with your added property. However, I suspect the limitation is actually to your benefit. If memo is applied to a method, its state is shared by all instances of the class (and perhaps even instances of subclasses). If you allow the caching details to be adjusted through instances, you might confuse users with cases like:
obj1 = basic()
print obj1.increment.getCacheTimeout() # prints the initial value, e.g. 120
obj2 = basic()
obj2.increment.setCacheTimeOut(20) # change the timeout value via another instance
print obj1.increment.getCacheTimeout() # the value via the first instance now prints 20
I suggest that you make the memoization-related interfaces of decorated methods accessible only through the class, not through instances. To make that work, you need to update your __get__ method to work if obj is None. It can simply return self:
def __get__(self, obj, objtype=None):
if obj is None:
return self
self.objtype = objtype
return partial(self, obj) # no need to attach our methods to the partial anymore
With this change, using a property on the memo via the class works:
basic.increment.cacheTimeOut = 20 # set property of the "unbound" method basic.increment
There is actually a way to accomplish this - by rebinding the decorator as instance-object with a call-method
class Helper(object):
def __init__(self, d, obj):
self.d = d
self.obj = obj
self.timeout = 0
def __call__(self, *args, **kwargs):
print self, self.timeout
return self.d.func(self.obj, *args, **kwargs)
class decorator(object):
def __init__(self, func):
self.func = func
self.name = func.__name__
def __get__(self, obj, clazz):
if object is not None:
obj.__dict__[self.name] = Helper(self, obj)
return obj.__dict__[self.name]
class Foo(object):
#decorator
def bar(self, args):
return args * 2
f = Foo()
g = Foo()
f.bar.timeout = 10
g.bar.timeout = 20
print f.bar(10)
print g.bar(20)
HTH
i'm tasked with the job to create a class of strings and integers between 1 and 10.
I basically did the following...
class hello():
__slots__ = ('name', 'number')
def __init__(self):
self.name = myName
self.number = myNumber
The only problem is that I don't know how to make myNumber = an integer between 1 and 10. Similarly, how would I compare myNumber if it's assigned to a name to other objects? Thanks
You the constructor and enforce a check at assignment. Try doing this with the property decorator:
class MyClass():
def __init__(self, value):
self.something = value
#property
def something(self):
return self.item
#something.setter
def set_something(self, value):
if value is not None:
self.time = value
else:
raise Error
This is one way to put in logic which prevents setting a None value on a property of a class. You could also doing something with this to change it to check the values you want it to be.
I have a class with an __init__ function.
How can I return an integer value from this function when an object is created?
I wrote a program, where __init__ does command line parsing and I need to have some value set. Is it OK set it in global variable and use it in other member functions? If so how to do that? So far, I declared a variable outside class. and setting it one function doesn't reflect in other function ??
If you want to return some other object when a class is called, then use the __new__() method:
class MyClass:
def __init__(self):
print("never called in this case")
def __new__(cls):
return 42
obj = MyClass()
print(obj)
# Output: 42
__init__ is required to return None. You cannot (or at least shouldn't) return something else.
Try making whatever you want to return an instance variable (or function).
>>> class Foo:
... def __init__(self):
... return 42
...
>>> foo = Foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __init__() should return None
From the documentation of __init__:
As a special constraint on constructors, no value may be returned; doing so will cause a TypeError to be raised at runtime.
As a proof, this code:
class Foo(object):
def __init__(self):
return 2
f = Foo()
Gives this error:
Traceback (most recent call last):
File "test_init.py", line 5, in <module>
f = Foo()
TypeError: __init__() should return None, not 'int'
Sample Usage of the matter in question can be like:
class SampleObject(object):
def __new__(cls, item):
if cls.IsValid(item):
return super(SampleObject, cls).__new__(cls)
else:
return None
def __init__(self, item):
self.InitData(item) #large amount of data and very complex calculations
...
ValidObjects = []
for i in data:
item = SampleObject(i)
if item: # in case the i data is valid for the sample object
ValidObjects.append(item)
The __init__ method, like other methods and functions returns None by default in the absence of a return statement, so you can write it like either of these:
class Foo:
def __init__(self):
self.value=42
class Bar:
def __init__(self):
self.value=42
return None
But, of course, adding the return None doesn't buy you anything.
I'm not sure what you are after, but you might be interested in one of these:
class Foo:
def __init__(self):
self.value=42
def __str__(self):
return str(self.value)
f=Foo()
print f.value
print f
prints:
42
42
__init__ doesn't return anything and should always return None.
You can just set it to a class variable and read it from the main program:
class Foo:
def __init__(self):
#Do your stuff here
self.returncode = 42
bar = Foo()
baz = bar.returncode
We can not return value from init. But we can return value using new.
class Car:
def __new__(cls, speed, unit):
return (f"{speed} with unit {unit}")
car = Car(42, "km")
print(car)
init() return none value solved perfectly
class Solve:
def __init__(self,w,d):
self.value=w
self.unit=d
def __str__(self):
return str("my speed is "+str(self.value)+" "+str(self.unit))
ob=Solve(21,'kmh')
print (ob)
output:
my speed is 21 kmh
Just wanted to add, you can return classes in __init__
#property
def failureException(self):
class MyCustomException(AssertionError):
def __init__(self_, *args, **kwargs):
*** Your code here ***
return super().__init__(*args, **kwargs)
MyCustomException.__name__ = AssertionError.__name__
return MyCustomException
The above method helps you implement a specific action upon an Exception in your test
Met this case when tried to parse some string data into a recursive data structure, and had a counter to be passed through.
Python does not allow to return anything from __init__, but you may write a factory function, or a class method, or a Parser class, depending on the code structure and complexity of parsing, which will parse your data into data objects.
Global variable is not a good solution, as it may be changed somewhere else, breaking the parsing logic.
Function example:
class MyClass():
def __init__(self, a, b, c):
# only assignments here
self.a = a
self.b = b
self.c = c
# return None
def parse(data):
# parsing here
a = ...
b = ...
c = ...
# status, counter, etc.
i = ...
# create an object
my_obj = MyClass(a, b, c)
# return both
return my_obj, i
# get data and parse
data = ...
my_obj, i = parse(data)
Class method example:
class MyClass():
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
#classmethod
def parse(cls, data):
a = ...
b = ...
c = ...
i = ...
obj = cls(a, b, c)
return obj, i
data = ...
my_obj, i = MyClass.parse(data)
solution here
Yes,
trying to return from the init method in python returns errors as it is a constructor of the class you can only assign values for the scope of the class but not return a specific value.
if you want to return a value but do not wish to create a method, you can use
str method
def __init__(self,a):
self.value=a
def __str__(self):
return str("all my return values are possible here")`
Well, if you don't care about the object instance anymore ... you can just replace it!
class MuaHaHa():
def __init__(self, ret):
self=ret
print MuaHaHa('foo')=='foo'