How to create a class instance without calling initializer?
When feasible, letting __init__
get called (and make the call innocuous by suitable arguments) is preferable. However, should that require too much of a contortion, you do have an alternative, as long as you avoid the disastrous choice of using old-style classes (there is no good reason to use old-style classes in new code, and several good reasons not to)...:
class String(object): ... bare_s = String.__new__(String)
This idiom is generally used in classmethod
s which are meant to work as "alternative constructors", so you'll usually see it used in ways such as...:
@classmethod def makeit(cls): self = cls.__new__(cls) # etc etc, then return self
(this way the classmethod will properly be inherited and generate subclass instances when called on a subclass rather than on the base class).
A trick the standard pickle and copy modules use is to create an empty class, instantiate the object using that, and then assign that instance's __class__
to the "real" class. e.g.
>>> class MyClass(object):... init = False... def __init__(self):... print 'init called!'... self.init = True... def hello(self):... print 'hello world!'... >>> class Empty(object):... pass... >>> a = MyClass()init called!>>> a.hello()hello world!>>> print a.initTrue>>> b = Empty()>>> b.__class__ = MyClass>>> b.hello()hello world!>>> print b.initFalse
But note, this approach is very rarely necessary. Bypassing the __init__
can have some unexpected side effects, especially if you're not familiar with the original class, so make sure you know what you're doing.
Using a metaclass provides a nice solution in this example. The metaclass has limited use but works fine.
>>> class MetaInit(type): def __call__(cls, *args, **kwargs): if args or kwargs: return super().__call__(*args, **kwargs) return cls.__new__(cls)>>> class String(metaclass=MetaInit): def __init__(self, string): self.__string = tuple(string.split()) self.__simple = tuple(self.__simple()) def __simple(self): letter = lambda s: ''.join(filter(lambda s: 'a' <= s <= 'z', s)) return filter(bool, map(letter, map(str.lower, self.__string))) def __eq__(self, other): assert isinstance(other, String) return self.__simple == other.__simple def __getitem__(self, key): assert isinstance(key, slice) string = String() string.__string = self.__string[key] string.__simple = self.__simple[key] return string def __iter__(self): return iter(self.__string)>>> String('Hello, world!')[1:]<__main__.String object at 0x02E78830>>>> _._String__string, _._String__simple(('world!',), ('world',))>>>
Addendum:
After six years, my opinion favors Alex Martelli's answer more than my own approach. With meta-classes still on the mind, the following answer shows how the problem can be solved both with and without them:
#! /usr/bin/env python3METHOD = 'metaclass'class NoInitMeta(type): def new(cls): return cls.__new__(cls)class String(metaclass=NoInitMeta if METHOD == 'metaclass' else type): def __init__(self, value): self.__value = tuple(value.split()) self.__alpha = tuple(filter(None, ( ''.join(c for c in word.casefold() if 'a' <= c <= 'z') for word in self.__value))) def __str__(self): return ' '.join(self.__value) def __eq__(self, other): if not isinstance(other, type(self)): return NotImplemented return self.__alpha == other.__alpha if METHOD == 'metaclass': def __getitem__(self, key): if not isinstance(key, slice): raise NotImplementedError instance = type(self).new() instance.__value = self.__value[key] instance.__alpha = self.__alpha[key] return instance elif METHOD == 'classmethod': def __getitem__(self, key): if not isinstance(key, slice): raise NotImplementedError instance = self.new() instance.__value = self.__value[key] instance.__alpha = self.__alpha[key] return instance @classmethod def new(cls): return cls.__new__(cls) elif METHOD == 'inline': def __getitem__(self, key): if not isinstance(key, slice): raise NotImplementedError cls = type(self) instance = cls.__new__(cls) instance.__value = self.__value[key] instance.__alpha = self.__alpha[key] return instance else: raise ValueError('METHOD did not have an appropriate value') def __iter__(self): return iter(self.__value)def main(): x = String('Hello, world!') y = x[1:] print(y)if __name__ == '__main__': main()