2010-01-30 10 views
17

क्या क्लास विधि से शुरू होने पर कक्षा में __init__ को कॉल करने से बचने का कोई तरीका है?पायथन: प्रारंभकर्ता को कॉल किए बिना कक्षा उदाहरण बनाना

मैं पाइथन में एक केस और विराम चिह्न असंवेदनशील स्ट्रिंग क्लास बनाने की कोशिश कर रहा हूं जो कुशल तुलनात्मक उद्देश्यों के लिए उपयोग किया जाता है लेकिन __init__ पर कॉल किए बिना एक नया उदाहरण बनाने में परेशानी हो रही है।

>>> class String: 

    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:] 
Traceback (most recent call last): 
    File "<pyshell#2>", line 1, in <module> 
    String('Hello, world!')[1:] 
    File "<pyshell#1>", line 17, in __getitem__ 
    string = String() 
TypeError: __init__() takes exactly 2 positional arguments (1 given) 
>>> 

मैं स्लाइस के साथ नई वस्तु प्रारंभ करने के साथ string = String(); string.__string = self.__string[key]; string.__simple = self.__simple[key] क्या बदलना चाहिए?

संपादित करें:

के रूप में जवाब के नीचे लिखा से प्रेरित, प्रारंभकर्ता जल्दी से कोई तर्क के लिए जाँच करने के लिए संपादित किया गया है।

def __init__(self, string=None): 
    if string is None: 
     self.__string = self.__simple =() 
    else: 
     self.__string = tuple(string.split()) 
     self.__simple = tuple(self.__simple()) 
+0

संभावित डुप्लिकेट [क्या \ _ \ _ init \ _ \ _?] (Http: // stackoverflow) कॉल किए बिना कक्षा को तुरंत चालू करने का कोई तरीका है।कॉम/प्रश्न/6383914/एक-तरफा-से-तत्काल-ए-क्लास-बिना-कॉलिंग-इनिट) – kay

उत्तर

1

मेटाक्लास का उपयोग इस उदाहरण में एक अच्छा समाधान प्रदान करता है। मेटाक्लास के पास सीमित उपयोग है लेकिन ठीक काम करता है।

>>> 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',)) 
>>> 
0

निर्माता के लिए एक और तर्क पास है, इसलिए जैसे:

def __init__(self, string, simple = None): 
    if simple is None: 
     self.__string = tuple(string.split()) 
     self.__simple = tuple(self.__simple()) 
    else: 
     self.__string = string 
     self.__simple = simple 

फिर आप इसे इस तरह कॉल कर सकते हैं: इसके अलावा

def __getitem__(self, key): 
    assert isinstance(key, slice) 
    return String(self.__string[key], self.__simple[key]) 

, मुझे यकीन है कि यह नाम करने की अनुमति दी है नहीं कर रहा हूँ क्षेत्र और विधि __simple दोनों। अगर केवल पठनीयता के लिए, आपको इसे बदलना चाहिए।

+0

मुझे आपका पहला उत्तर बेहतर पसंद आया। 'Str() == '' 'को ध्यान में रखते हुए, मुझे लगता है कि मैं कोड को' def __init __ (self, string = '') में बदल दूंगा:'। आपकी मदद और विचारों के लिए धन्यवाद! मैं पूरी तरह से '__init__' से बचने की उम्मीद कर रहा था, लेकिन उल्लेख किए गए परिवर्तन के साथ 'स्ट्रिंग()' को बुलाकर बहुत महंगी ऑपरेशन नहीं होना चाहिए। ऐसा लगता है कि इस समय सबसे अच्छा समाधान है। –

+0

क्षमा करें, मैंने सोचा कि मेरा पहला जवाब वास्तव में प्रश्न को संबोधित नहीं करता है :) ऐसा लगता है कि मैं इसे वापस प्राप्त नहीं कर सकता ...? – Thomas

21

व्यवहार्य होने पर, __init__ को बुलाएं (और उपयुक्त तर्कों से निर्दोष कॉल करें) बेहतर है। हालांकि, क्या आपको बहुत अधिक गर्भपात की आवश्यकता होनी चाहिए, आपके पास एक विकल्प है, जब तक कि आप पुरानी शैली के वर्गों का उपयोग करने की विनाशकारी पसंद से बचें ( नए कोड में पुरानी शैली के वर्गों का उपयोग करने का अच्छा कारण है, और कई अच्छे कारणों नहीं करने के लिए) ...:

class String(object): 
     ... 

    bare_s = String.__new__(String) 

यह मुहावरा आम तौर पर, classmethod रों जो "वैकल्पिक कंस्ट्रक्टर्स" के रूप में काम करने के लिए होती हैं प्रयोग किया जाता है, ताकि आप आम तौर पर यह इस तरह के रूप तरीकों से किया देखेंगे ...:

@classmethod 
def makeit(cls): 
    self = cls.__new__(cls) 
    # etc etc, then 
    return self 

(इस तरह से classmethod आधार वर्ग के बजाए उप-वर्ग पर कॉल किए जाने पर ठीक से विरासत में प्राप्त किया जाएगा और सबक्लास उदाहरण उत्पन्न होंगे)।

+6

आप इसे पायथन 3.1 के लिए कैसे लिखेंगे? –

+0

यदि स्ट्रिंग एक सबक्लास था, तो आप सुपरक्लास 'कन्स्ट्रक्टर को कैसे कॉल करेंगे? – gozzilli

+0

ओह मुझे यह मिला, आप '' '' '' '' '' '' '' '' '' '' '' _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ – gozzilli

5

मानक अचार और प्रतिलिपि मॉड्यूल का उपयोग एक खाली वर्ग बनाने के लिए है, उस वस्तु का उपयोग करके तुरंत चालू करें, और उसके बाद उस उदाहरण के __class__ को "असली" कक्षा में असाइन करें। जैसे

>>> 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.init 
True 
>>> b = Empty() 
>>> b.__class__ = MyClass 
>>> b.hello() 
hello world! 
>>> print b.init 
False 

लेकिन ध्यान दें, यह दृष्टिकोण बहुत ही कम आवश्यक है। __init__ को छोड़कर कुछ अप्रत्याशित साइड इफेक्ट्स हो सकते हैं, खासकर यदि आप मूल कक्षा से परिचित नहीं हैं, तो सुनिश्चित करें कि आप जानते हैं कि आप क्या कर रहे हैं।

संबंधित मुद्दे