Inheritance from Str or Int

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 object myInstance. __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 Enums -- 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



Leave a reply



Submit