inheritance from str or int
>>> class C(str):
... def __new__(cls, *args, **kw):
... return str.__new__(cls, *args, **kw)
...
>>> c = C("hello world")
>>> type(c)
<class '__main__.C'>
>>> c.__class__.__mro__
(<class '__main__.C'>, <type 'str'>, <type 'basestring'>, <type 'object'>)
Since __init__
is called after the object is constructed, it is too late to modify the value for immutable types. Note that __new__
is a classmethod, so I have called the first parameter cls
See here for more information
>>> class C(str):
... def __new__(cls, value, meta):
... obj = str.__new__(cls, value)
... obj.meta = meta
... return obj
...
>>> c = C("hello world", "meta")
>>> c
'hello world'
>>> c.meta
'meta'
Set the value of an argument in a class who inherits from int or float or str
What you wrote is essentially right, there are a few mistakes here and there.
class A(str):
def __new__(cls, *args, **kwargs):
return str.__new__(cls)
def __init__(self, arg01):
print(arg01)
This is not completely correct: if you don't pass any argument to str.__new__
, your new instance will be the equivalent of an empty string.
class A(str):
def __new__(cls, arg):
return str.__new__(cls, arg)
def __init__(self, arg):
print(arg)
In general, __new__
and __init__
should have the same signature. It is not a requirement, but in this case you need to pass arg
to str.__new__
so you must intercept arg
.
The method
myClass.__new__
is executed. This method will create the objectmyInstance
.__new__
is the real constructor (__init__
isn't a constructor !). In pseudocode,__new__
look something like this :
It is not the responsibility of __new__
to call __init__
, as demonstrated by this simple example:
class C:
def __new__(cls):
print('entering __new__')
self = super().__new__(cls)
print('exiting __new__')
return self
def __init__(self):
print('entering __init__')
super().__init__()
print('exiting __init__')
C()
# Output:
# entering __new__
# exiting __new__
# entering __init__
# exiting __init__
As you can see, in my __new__
I didn't call __init__
explicitly, and object.__new__
is not calling __init__
either.
__init__
is automatically called by the Python interpreter itself whenever __new__
returns an instance of the type.
The situation is a little different when we are using immutable types (str, int, float, tuple).
This is not entirely true. The situation is different when we are inheriting from a type that is not using the default __new__
implementation.
The default __new__
implementation (i.e. object.__new__
) is very permissive and ignores every positional argument and keyword argument. If you replace it with a less permissive implementation, then problems like the one you are observing happen.
What is important to understand is that the problem is not brought by the non-default __new__
itself, but by the fact that our __init__
is not compatible with __new__
.
foo.__new__(foo, arg = 1)
# That works because the method __new__ look like this : def __new__(*args, **kargs).
str.__new__(str, arg = 1)
# That fails because we are trying to pass the attribute 'arg' to a method which look like this : def __new__(anUniqueValue).
You got it. Just one bit is wrong: the correct signature for str.__new__
is:
def __new__(cls[, object[, encoding[, errors]]])
All arguments except cls
are both positional and keyword argument. In fact you can do:
>>> class C(str):
... def __init__(self, object):
... pass
...
>>> C('abc')
'abc'
>>> C(object='abc')
'abc'
You see? We used a signature for __init__
that is compatible with str.__new__
and now we can avoid overriding __new__
!
What are the caveats of inheriting from both str and Enum
When inheriting from str
, or any other type, the resulting enum members are also that type. This means:
- they have all the methods of that type
- they can be used as that type
- and, most importantly, they will compare with other instances of that type
That last point is the most important: because LogLevel.DEBUG
is a str
it will compare with other strings -- which is good -- but will also compare with other str
-based Enum
s -- which could be bad.
Info regarding subclassing enum from the documentation
Inherit builtin `str` class in python
Do not use a keyword argument for the string's value. Just use a single positional argument. The function signature will be MyStr(s, idx=0) where s is the value of the string.
(1) In your implementation of __new__
do not pass the keyword argument. str.__new__
will not know what to do with it. Both arguments will get passed to __init__
.
(2) In your implementation of __init__
just ignore the first argument. It has already been used to initialize the string by the str.__new__
function. All you need to do here is to store the idx
argument in a new variable.
(3) Just get rid of the .word
property. You already have a string, so the .word
property doesn't add anything.
The new instance will behave like a string and will have all the methods of a string. It will also have the property idx.
class MyStr(str):
def __new__(cls, s, idx=0):
return super().__new__(cls, s)
# less good style is: str.__new__(cls, s)
def __init__(self, s, idx: int=0):
super().__init__()
self._idx = idx
@property
def idx(self):
return self._idx
if __name__ == '__main__':
ms = MyStr('snake', idx=10)
print(ms, ms.idx)
print(ms.upper())
# Output:
# snake 10
# SNAKE
I basically agree with those commenters who advised against doing this on general principles (it's tricky and your code will not be easy to understand for someone else). But it does work.
Java inheritance and string interpolation
This is a situation where you could consider applying the Template Method design pattern. In this pattern, you define the reusable part of your method in the abstract class, and implement only the variable parts in the subclasses. For example:
abstract class Pet {
// ...
protected abstract String extra(); // Or, return the empty String
public final String toString() {
return String.format("Name: %s, Breed: %s, %s, Owner: %s",
name, breed, extra(), owner);
}
}
In your subclasses:
class Dog extends Pet {
int age;
public String extra() {
return String.format("Age: %d");
}
}
What is the way to inherit std::string right?
In C++ any declaration that can be parsed as a function declaration, such as …
spstring byteaddstr(std::string(argv[4])); //convertchar* to spstring
is parsed as a function declaration.
I.e. not a variable.
One solution in this particular case, is to add extra parentheses:
spstring byteaddstr(( std::string(argv[4]) )); //convertchar* to spstring
This is known as the most vexing parse in C++, although some people disagree about whether Scott Meyers' original use of that term applies as generally as it's used now.
And by the way, one should generally have a pretty good reason to derive from std::string
, because it adds complexity and confusion (you can safely disregard concerns about dynamic allocation, because code that dynamically allocates std::string
deserves whatever it gets). So, I suggest that you don't do that.
Subclassing int in Python
int
is immutable so you can't modify it after it is created, use __new__
instead
class TestClass(int):
def __new__(cls, *args, **kwargs):
return super(TestClass, cls).__new__(cls, 5)
print TestClass()
Related Topics
Get a List of All the Encodings Python Can Encode To
Pandas Out of Bounds Nanosecond Timestamp After Offset Rollforward Plus Adding a Month Offset
How to Run an Ipython Magic from a Script (Or Timing a Python Script)
Find the Closest Date to a Given Date
Use Python's String.Replace VS Re.Sub
Python Random Sample with a Generator/Iterable/Iterator
Return String with First Match for a Regex, Handling Case Where There Is No Match
Pipelinedrdd' Object Has No Attribute 'Todf' in Pyspark
How to Overwrite/Print Over the Current Line in Windows Command Line
How to Understand Numpy Strides for Layman
How to Tell If Numpy Creates a View or a Copy
Running Interactive Commands in Paramiko
How to Close a Thread When Multithreading
On Localhost, How to Pick a Free Port Number