Multiple constructor with Python - python

I have a class A that can be generated from two different ways.
a = A(path_to_xml_file)
a = A(listA, listB)
The first method has file path as an input to parse from XML file to get listA, and listB. The second method is given two lists.
I can think of two ways to implement multiple constructor. What do you think? What method normally Python guys use for this case?
Check the type
class A():
def __init__(self, arg1, arg2 = None):
if isinstance(arg1, str):
...
elif isinstance(arg1, list):
...
a = A("abc")
b = A([1,2,3],[4,5,6])
Make different builders
class A2():
def __init__(self):
pass
def genFromPath(self, path):
...
def genFromList(self, list1, list2):
...
a = A2()
a.genFromPath("abc")
b = A2()
b.genFromList([1,2,3],[4,5,6])

Make the constructor take the two lists. Write a factory classmethod that parses the XML and returns the object.

Use classmethod for second one
class A(object):
#classmethod
def from_string(cls, string):
# ...
#classmethod
def from_lists(cls, list1, list2):
# ...
Use module's functions
def from_string(string):
# ...
def from_lists(list1, list2):
# ...
class A(object):
pass

Since the number of arguments passed to the initializer is different in each case, you can avoid type-checking by using the extended call syntax:
class A(object):
def __init__(self, *args):
if len(args) == 1:
path = args[0]
...
elif len(args) == 2:
list1 = args[0]
list2 = args[1]
...
else:
raise SomeException()

Looking at the problem more closely, I'd suggest having the class take two lists, and include a helper function in the module:
class A(object):
def __init__(self, list1, list2):
# Init from lists here
pass
def create_A_from_path(path):
list1, list2 = parse_xml_into_lists(path)
return A(list1, list2)

class A(object):
#staticmethod
def from_string(str):
obj =A()
obj.str = str
return obj
#staticmethod
def from_list(lis):
obj = A()
obj.lis = lis
return obj
>>>
(obj1, obj2) = A.from_string('hello'), A.from_list(['one', 'two'])

Related

Python #cls.decorator

I want to create a python decorator that adds a certain function to a list of functions of that class that will, sometimes, be processed. Example code:
class A:
# every subclass should define _list
#classmethod
def decorator(cls, f):
# cls = B
cls._flist.append(f)
return f
#classmethod
def processFunctions(cls):
for f in cls._flist:
...
class B(A):
_flist = []
#B.decorator # Obviously not possible because cls is not defined (yet)
def foo(self):
print("Inside foo")
Is it possible to replicate this behaviour? The class (cls) should be passed when decorating the function, so I can't use the usual approach of creating a wrapper function that "unpacks" cls and the other arguments.
Ok, I think I've worked something out.
You need an instance of A, but as a class variable inside B.
Then each method will need an instance:
class A:
def __init__(self):
self._flist = []
def decorator(self, f):
self._flist.append(f)
return f
def processFunctions(self, other):
for f in self._flist:
f(other)
class B:
a=A()
#a.decorator
def foo(self):
print("Inside foo")
def processFunctions(self):
B.a.processFunctions(self)
b = B()
b.processFunctions()
Output
Inside foo
The following way is based on the implementation behavior of locals() in CPython but there is PEP 558 to make it documented standard behavior:
class A:
# every subclass should define _list
#staticmethod
def decorator(loc):
def registrator(f):
loc['_flist'].append(f)
return f
return registrator
#classmethod
def processFunctions(cls):
for f in cls._flist:
...
class B(A):
_flist = []
#decorator(locals())
def foo(self):
print("Inside foo")
Another approach, like the one the package ABC uses is making the decorator add a flag to the function, and then go through the functions of this class that have that flag activated.
class A:
#staticmethod
def decorator(f):
def wraps(f)
f.__processable__ = True
return f
return wraps
def processFunctions(self):
for d in dir(self):
try:
f = getattr(self, d).__func__
if f.__processable__:
f() # Or whatever we want to do with the function
# Instead of try/except we could use a bunch of nested ifs
except AttributeError:
pass

How to use map for class method within another class method in Python

I want to define a class method which applies a different class method to a list - I thought the below would work but it doesn't seem to, am I missing something obvious?
class Foo():
def __init__(self):
pass
def method1(self, data):
do some stuff
def method2(self, iterable):
map(self.method1, iterable)
do some more stuff
As a concrete example, method2 is applying method1 to each element of a list but the actual content of method1 (printing) doesn't seem to be executing:
class Foo():
def __init__(self):
self.factor = 2
def method1(self, num):
print(num*self.factor)
def method2(self, ls):
map(self.method1, ls)
f = Foo()
f.method2([1,2,3])
I would expect this to print 2, 4, 6 but nothing is printed.
map returns a generator (in Python 3), so you still need to iterate over it:
def method2(self, iterable):
for val in map(self.method1, iterable):
do some stuff with val
If you don't care about the return values, you could always just wrap it in a list: list(map(self.method1, iterable)).

Overriding constructors for list in python

Let's say I want to implement some list class in python with extra structure, like a new constructor. I wrote:
import random
class Lis(list):
def __init__(self, n):
self = []
for i in range(n):
self.append(random.randint(0, 30))
Now doing Lis(3) gives me an empty list. I don't know where I did it wrong.
You are overriding the object with self = []
try the following
import random
class Lis(list):
def __init__(self, n):
for i in range(n):
self.append(random.randint(0, 30))
if you want to return a list from object call
class MyClass(object):
def __init__(self):
print "never called in this case"
def __new__(cls):
return [1,2,3]
obj = MyClass()
print(obj)
How to return a value from __init__ in Python?
or if you want an modified object try:
class MyClass:
def __getitem__(self, key):
not_self = []
for i in range(n):
not_self.append(random.randint(0, 30))
return not_self
myobj = MyClass()
myobj[3] #Output: 6
How to override the [] operator in Python?
I am not sure if using self like you did is healthy.

How to add a method into a dict using decorator?

What I want is something like flask routing register:
class ClassName(object):
def __init__(self):
self.handle_dict = {}
def handle(data):
h = self.handle_dict.get(data)
h()
#handle_route("open")
def open_handle()
"""do something"""
pass
#handle_route("close")
def close_handle()
"""do something"""
pass
def handle_route()
"""How to implement this warpper?"""
I know I could write the a dict in the __init__ function:
self.handle_dict = {"open":self.open_handle, "close":self.colse_handle}
But the decorator way looks more clear, right?
I have tried
def handle_router(self, path):
def warpper(f):
self.handle_map[path] = f
return f
return warpper
but self is not allow in decorator args, #handle_router(self, "path") is invalid.
Effectively, the handle dict should be some sort of class attribute, as it is filled at class definition time and all instances share the same route-handler mapping. However, the class does not exist yet when the decorator is called and evaluated. You could do something like the following:
from functools import partial
class A:
router = {}
def handle(self, data):
m = self.router.get(data)
return m(self)
#partial(router.setdefault, 'open')
def open_handle(self):
return 5
>>> a = A()
>>> a.handle('open')
5
Or be more explicit and extract the routing functionailty to a reuasable class:
from functools import partial
class Router(dict):
__call__ = lambda self, route: partial(self.setdefault, route)
class A:
router = Router()
def handle(self, data):
m = self.router.get(data)
return m(self)
#router('open')
def open_handle(self):
return 5
Instead of decorating the functions, you could just use a consistent naming convention:
class ClassName(object):
def handle(self, type):
getattr(self, '{}_handle'.format(type))()
def open_handle(self):
print('open_handle')
def close_handle(self):
print('close_handle')
ClassName().handle('open')
>>> open_handle

How to return a value from __init__ in Python?

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'

Categories

Resources