Reputation: 335
Here I have defined immutable class str.
In __new__
method I am changing the values of instances such as "hello" to uppercase. Why should we do it using __new__
when we can define upper in __init__
?
class Upperstr(str):
def __new__(cls, value=""):
print(cls)
print(value)
return str.__new__(cls, value.upper())
# def __init__(self, m1):
# self.m1 = m1.upper()
u = Upperstr("hello")
print(u)
New is used to create class instances.
What are the other uses of __new__
method?
Upvotes: 8
Views: 9737
Reputation: 4644
Your question was something like,
Under what conditions is
__new__
better to use than__init__
in Python?
Suppose that we have a very simple class named Point
class Point():
def __init__(self, x:float, y:float):
self._x = x
self._y = y
We instantiate the Point
class as follows:
# construct and initialize paula the point
paula = Point(10.2, 7.4)
In order to help explain what __new__
does, I will write a classmethod named make_point
which has almost the same behavior as paula = = Point(10.2, 7.4)
.
class Point():
def __new__(cls, *args, **kwargs):
print("__new__(" + ", ".join(str(x) for x in [cls, *args]) + ")")
obj = super().__new__(cls)
return obj
def __init__(self, y:float, y:float):
args = (y, y)
print("__init__(" + ", ".join(str(x) for x in [self, *args]) + ")")
self._y = y
self._y = y
@classmethod
def make_point(cls, *args):
new_instance = cls.__new__(cls, *args)
if isinstance(new_instance, cls):
cls.__init__(new_instance, *args)
return new_instance
Now we can instantiate the Point
class as follows:
peter = Point.make_point(59.87, 5.91)
The __init__
method is unable to replace the self
parameter with something new and different.
For example, people sometimes want want to put a wrapper around the self
parameter. You might want something like this:
import functools
import sys
class decorator:
def __new__(cls, kallable):
instance = super().__new__(cls)
instance = functools.update_wrapper(instance, kallable)
return instance
def __init__(self, kallable):
self._kallable = kallable
self._file = sys.stdout
def __call__(self, *args, **kwargs):
print("__init__(" + ", ".join(str(x) for x in [self, *args]) + ")", file=self._file)
return self._kallable(*args, **kwargs)
@decorator
def pow(base:float, exp:int):
"""
+------------------------------------------+
| EXAMPLES |
+------------------------------------------+
| BASE | EXPONENT | OUTPUT |
+------+----------+------------------------+
| 2 | 5 | 2^5 | 32 |
| 2.5 | 7 | 2.5^7 | 610.3515625 |
| 10 | 3 | 10^3 | 1000 |
| 0.1 | 5 | 0.1^5 | 0.00001 |
| 7 | 0 | 7^0 | 1 |
+------+----------+----------+-------------+
"""
base = float(base)
# convert `exp` to string to avoid flooring, or truncating, floats
exp = int(str(exp))
if exp > 0:
return base * pow(base, exp-1)
else: # exp == 2
return 1
result1 = pow(2, 5)
result2 = pow(8.1, 0)
print("pow(2, 5) == " , result1)
print("pow(8.1, 0) == ", result2)
print("What is the documentation string? The doc-string is... ", pow.__doc__)
It will not help to use functools.update_wrapper
inside of __init__
. If you try to write the following...
class f:
def __init__(self, inner):
# Here, the wrapper callable (function o functor) is named `self`
self = functools.update_wrapper(self, inner)
... then self = foo(self)
will be ignored.
In python, you are not allowed to replace the parameter named self
with a different self
The __new__
method is nice because it allows us to replace self
with a wrapper around self
import functools
class decorator:
def __new__(cls, wrapped):
assert(callable(wrapped))
wrapper = super().__new__(cls)
wrapper = functools.update_wrapper(wrapper, wrapped)
wrapper._kallable = kallable
return wrapper
def __call__(self, *args, **kwargs):
return self._kallable(*args, **kwargs)
Without using functools.update_wrapper
inside of __new__
the doc-string inside of the original callable will be wiped-out, ignored, not inherited, and/or shadowed.
Upvotes: 1
Reputation: 36570
New is used to create class instances. What are the other uses of new method?
You can use __new__
to implement singleton pattern (where pattern must be understand as thing described in Design Patterns: Elements of Reusable Object-Oriented Software), take look at example provided by geeksforgeeks.org of Classic Singleton
class SingletonClass(object):
def __new__(cls):
if not hasattr(cls, 'instance'):
cls.instance = super(SingletonClass, cls).__new__(cls)
return cls.instance
singleton = SingletonClass()
new_singleton = SingletonClass()
print(singleton is new_singleton)
singleton.singl_variable = "Singleton Variable"
print(new_singleton.singl_variable)
Upvotes: 11
Reputation: 438
new is basically a standard Python method that is invoked before init when a class instance is created. For further information, see the python new manual: https://docs.python.org/3/reference/datamodel.html#object.__new__
There is not other direct usage of it.
Regarding the difference between Init/New: The constructor function in python is called new and init is the initializer function. According to the Python documentation, new is used to control the creation of a new instance, whereas init is used to handle its initialization.
Upvotes: -3