पायथन डेकोरेटर कैसे बनाएं जिसका उपयोग या तो मापदंडों के साथ या बिना किया जा सकता है?


90

मैं एक पायथन डेकोरेटर बनाना चाहूंगा जिसका उपयोग या तो मापदंडों के साथ किया जा सकता है:

@redirect_output("somewhere.log")
def foo():
    ....

या उनके बिना (उदाहरण के लिए डिफ़ॉल्ट रूप से उत्पादन को स्ट्रीडर पर पुनर्निर्देशित करने के लिए):

@redirect_output
def foo():
    ....

क्या यह सब संभव है?

ध्यान दें कि मैं आउटपुट के पुनर्निर्देशन की समस्या के अलग समाधान की तलाश में नहीं हूं, यह सिंटैक्स का एक उदाहरण है जिसे मैं प्राप्त करना चाहता हूं।


डिफ़ॉल्ट-दिखने @redirect_outputउल्लेखनीय रूप से एकरूप है। मेरा सुझाव है कि यह एक बुरा विचार है। पहले रूप का उपयोग करें और अपने जीवन को सरल बनाएं।
— एस.लॉट

हालांकि दिलचस्प सवाल - जब तक मैंने इसे देखा और दस्तावेज के माध्यम से देखा, मैंने मान लिया था कि @f @ @ () के रूप में ही था, और मुझे अभी भी लगता है कि यह ईमानदार होना चाहिए (किसी भी प्रदान किए गए तर्कों से निपटा जाएगा) समारोह तर्क करने के बारे में)
— rog

जवाबों:


68

मुझे पता है कि यह सवाल पुराना है, लेकिन कुछ टिप्पणियां नई हैं, और जबकि सभी व्यवहार्य समाधान अनिवार्य रूप से समान हैं, उनमें से अधिकांश बहुत साफ या पढ़ने में आसान नहीं हैं।

जैसा कि थोबे का जवाब कहता है, दोनों मामलों को संभालने का एकमात्र तरीका दोनों परिदृश्यों की जांच करना है। सबसे आसान तरीका यह है कि यह देखने के लिए कि क्या कोई एकल तर्क है और यह कॉलबेब है (नोट: अतिरिक्त चेक आवश्यक होगा यदि आपका डेकोरेटर केवल 1 तर्क लेता है और यह कॉल करने योग्य ऑब्जेक्ट होता है):

def decorator(*args, **kwargs):
    if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
        # called as @decorator
    else:
        # called as @decorator(*args, **kwargs)

पहले मामले में, आप वही करते हैं जो कोई भी सामान्य डेकोरेटर करता है, फ़ंक्शन में पारित का एक संशोधित या लिपटे संस्करण लौटाता है।

दूसरे मामले में, आप एक 'नए' डेकोरेटर को लौटाते हैं, जो किसी तरह से पास की गई जानकारी को * आर्ग, ** क्वार्ग्स के साथ प्रयोग करता है।

यह ठीक है और सभी है, लेकिन आपके द्वारा किए गए हर डेकोरेटर के लिए इसे लिखना बहुत कष्टप्रद हो सकता है और उतना साफ नहीं। इसके बजाय, यह अच्छा होगा कि हम अपने डेकोरेटर्स को आटोमैटिकली मॉडिफाई कर सकें, उन्हें दोबारा लिखे बिना ... लेकिन यही डेकोरेटर्स किस लिए हैं!

निम्नलिखित डेकोरेटर डेकोरेटर का उपयोग करके, हम अपने डेकोरेटर्स को हटा सकते हैं ताकि उनका उपयोग तर्कों के साथ या बिना किया जा सके:

def doublewrap(f):
    '''
    a decorator decorator, allowing the decorator to be used as:
    @decorator(with, arguments, and=kwargs)
    or
    @decorator
    '''
    @wraps(f)
    def new_dec(*args, **kwargs):
        if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
            # actual decorated function
            return f(args[0])
        else:
            # decorator arguments
            return lambda realf: f(realf, *args, **kwargs)

    return new_dec

अब, हम @ सज्जाकार के साथ अपने डेकोरेटर को सजा सकते हैं, और वे बिना किसी तर्क के साथ और बिना तर्क के काम करेंगे:

मैंने ऊपर उल्लेख किया है, लेकिन यहां दोहराना चाहिए, इस डेकोरेटर में चेक उन तर्कों के बारे में एक धारणा बनाता है जो एक डेकोरेटर प्राप्त कर सकता है (अर्थात यह एक एकल, कॉल करने योग्य तर्क प्राप्त नहीं कर सकता है)। चूंकि अब हम इसे किसी भी जनरेटर के लिए लागू कर रहे हैं, इसलिए इसे विरोधाभास होने पर इसे ध्यान में रखा जाना चाहिए या संशोधित किया जाना चाहिए।

निम्नलिखित इसके उपयोग को प्रदर्शित करता है:

def test_doublewrap():
    from util import doublewrap
    from functools import wraps    

    @doublewrap
    def mult(f, factor=2):
        '''multiply a function's return value'''
        @wraps(f)
        def wrap(*args, **kwargs):
            return factor*f(*args,**kwargs)
        return wrap

    # try normal
    @mult
    def f(x, y):
        return x + y

    # try args
    @mult(3)
    def f2(x, y):
        return x*y

    # try kwargs
    @mult(factor=5)
    def f3(x, y):
        return x - y

    assert f(2,3) == 10
    assert f2(2,5) == 30
    assert f3(8,1) == 5*7

31

डिफ़ॉल्ट मानों के साथ कीवर्ड तर्क का उपयोग करना (जैसा कि kquinn द्वारा सुझाया गया है) एक अच्छा विचार है, लेकिन आपको कोष्ठक को शामिल करने की आवश्यकता होगी:

@redirect_output()
def foo():
    ...

यदि आप एक ऐसा संस्करण चाहते हैं जो डेकोरेटर पर कोष्ठक के बिना काम करता है तो आपको अपने डेकोरेटर कोड में दोनों परिदृश्यों को ध्यान में रखना होगा।

यदि आप Python 3.0 का उपयोग कर रहे हैं, तो आप इसके लिए केवल तर्क का उपयोग कर सकते हैं:

def redirect_output(fn=None,*,destination=None):
  destination = sys.stderr if destination is None else destination
  def wrapper(*args, **kwargs):
    ... # your code here
  if fn is None:
    def decorator(fn):
      return functools.update_wrapper(wrapper, fn)
    return decorator
  else:
    return functools.update_wrapper(wrapper, fn)

पाइथन 2.x में इसे वैरगस ट्रिक के साथ अनुकरण किया जा सकता है:

def redirected_output(*fn,**options):
  destination = options.pop('destination', sys.stderr)
  if options:
    raise TypeError("unsupported keyword arguments: %s" % 
                    ",".join(options.keys()))
  def wrapper(*args, **kwargs):
    ... # your code here
  if fn:
    return functools.update_wrapper(wrapper, fn[0])
  else:
    def decorator(fn):
      return functools.update_wrapper(wrapper, fn)
    return decorator

इनमें से कोई भी संस्करण आपको इस तरह कोड लिखने की अनुमति देगा:

@redirected_output
def foo():
    ...

@redirected_output(destination="somewhere.log")
def bar():
    ...

1
आप क्या डालते हैं your code here? आप उस फ़ंक्शन को कैसे कहते हैं जो सजाया गया है? fn(*args, **kwargs)काम नहीं करता है।
— लुम

मुझे लगता है कि एक बहुत सरल उत्तर है, एक वर्ग बनाएं जो डेकोरेटर को वैकल्पिक तर्क देगा। चूक के साथ एक ही तर्क के साथ एक और फ़ंक्शन बनाएं और डेकोरेटर वर्गों का एक नया उदाहरण लौटाएं। कुछ इस तरह दिखना चाहिए: def f(a = 5): return MyDecorator( a = a) और class MyDecorator( object ): def __init__( self, a = 5 ): .... खेद है कि यह एक टिप्पणी में लिख रहा है, लेकिन मुझे आशा है कि यह समझने के लिए पर्याप्त सरल है
— ओमर बेन हैम

17

मुझे पता है कि यह एक पुराना प्रश्न है, लेकिन मुझे वास्तव में प्रस्तावित किसी भी तकनीक को पसंद नहीं है इसलिए मैं एक और तरीका जोड़ना चाहता था। मैंने देखा कि django अपने login_requiredडेकोरेटर मेंdjango.contrib.auth.decorators एक बहुत साफ तरीके का उपयोग करता है । जैसा कि आप डेकोरेटर के डॉक्स में देख सकते हैं , इसका उपयोग अकेले @login_requiredया तर्कों के साथ किया जा सकता है @login_required(redirect_field_name='my_redirect_field')।

जिस तरह से वे करते हैं वह काफी सरल है। वे अपने डेकोरेटर तर्कों से पहले एक kwarg( function=None) जोड़ते हैं । यदि डेकोरेटर का उपयोग अकेले किया जाता है, functionतो यह वास्तविक कार्य होगा जो इसे सजा रहा है, जबकि यदि इसे तर्कों के साथ कहा जाता है, तो यह functionहोगा None।

उदाहरण:

from functools import wraps

def custom_decorator(function=None, some_arg=None, some_other_arg=None):
    def actual_decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            # Do stuff with args here...
            if some_arg:
                print(some_arg)
            if some_other_arg:
                print(some_other_arg)
            return f(*args, **kwargs)
        return wrapper
    if function:
        return actual_decorator(function)
    return actual_decorator

@custom_decorator
def test1():
    print('test1')

>>> test1()
test1

@custom_decorator(some_arg='hello')
def test2():
    print('test2')

>>> test2()
hello
test2

@custom_decorator(some_arg='hello', some_other_arg='world')
def test3():
    print('test3')

>>> test3()
hello
world
test3

मुझे यह दृष्टिकोण मिला है कि यहाँ प्रस्तावित अन्य तकनीकों की तुलना में django अधिक सुरुचिपूर्ण और समझने में आसान है।


हाँ, मुझे यह तरीका पसंद है। टिप्पणी क्या आप कि है जब डेकोरेटर अन्यथा पहले स्थितीय आर्ग को सौंपा गया है बुला kwargs उपयोग करने के लिए functionऔर फिर उन बातों को तोड़ने क्योंकि डेकोरेटर की कोशिश करता है कि पहली स्थितीय आर्ग कॉल करने के लिए के रूप में अगर यह आपके सजाया समारोह थे।
— डस्टिन व्याट

12

आपको दोनों मामलों का पता लगाने की आवश्यकता है, उदाहरण के लिए पहले तर्क के प्रकार का उपयोग करना, और तदनुसार रैपर (जब पैरामीटर के बिना उपयोग किया जाता है) या एक डेकोरेटर (जब तर्कों के साथ उपयोग किया जाता है)।

from functools import wraps
import inspect

def redirect_output(fn_or_output):
    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **args):
            # Redirect output
            try:
                return fn(*args, **args)
            finally:
                # Restore output
        return wrapper

    if inspect.isfunction(fn_or_output):
        # Called with no parameter
        return decorator(fn_or_output)
    else:
        # Called with a parameter
        return decorator

@redirect_output("output.log")सिंटैक्स का उपयोग करते समय , redirect_outputएक तर्क के साथ कहा जाता है "output.log", और इसे एक डेकोरेटर को फ़ंक्शन को एक तर्क के रूप में सजाया जाना स्वीकार करना चाहिए। जब इसका उपयोग किया जाता है @redirect_output, तो इसे सीधे फ़ंक्शन के साथ एक तर्क के रूप में सजाया जाता है।

या दूसरे शब्दों में: @वाक्यविन्यास का एक अभिव्यक्ति द्वारा पालन किया जाना चाहिए जिसका परिणाम एक फ़ंक्शन को अपने एकमात्र तर्क के रूप में सजाया जाने वाला फ़ंक्शन स्वीकार करना और सजाया गया फ़ंक्शन वापस करना है। अभिव्यक्ति स्वयं एक फ़ंक्शन कॉल हो सकती है, जो कि मामला है @redirect_output("output.log")। सही, लेकिन सच :-)


9

यहाँ कई उत्तर पहले से ही आपकी समस्या को अच्छी तरह से संबोधित करते हैं। शैली के संबंध में, हालाँकि, मैं इस डेकोरेटर का उपयोग करना पसंद कर रहा हूँ functools.partial, जैसा कि डेविड बेज़ले के पाइथनबुक 3 में सुझाया गया है :

from functools import partial, wraps

def decorator(func=None, foo='spam'):
    if func is None:
         return partial(decorator, foo=foo)

    @wraps(func)
    def wrapper(*args, **kwargs):
        # do something with `func` and `foo`, if you're so inclined
        pass

    return wrapper

जबकि हाँ, आप बस कर सकते हैं

@decorator()
def f(*args, **kwargs):
    pass

कायरतापूर्ण वर्कअराउंड के बिना, मुझे यह अजीब लग रहा है, और मुझे बस इसके साथ सजाने का विकल्प पसंद है @decorator।

द्वितीयक मिशन उद्देश्य के लिए, इस स्टैक ओवरफ्लो पोस्ट में एक फ़ंक्शन के आउटपुट को रीडायरेक्ट किया जाता है ।


यदि आप गहरा गोता लगाना चाहते हैं, तो पायथन कुकबुक 3 में अध्याय 9 (मेटाप्रोग्रामिंग) देखें , जो ऑनलाइन पढ़ने के लिए स्वतंत्र रूप से उपलब्ध है ।

उस सामग्री में से कुछ बेज़ले के भयानक YouTube वीडियो पायथन 3 मेटाप्रोग्रामिंग में लाइव (प्लस अधिक!) प्रदर्शित की गई है ।

मुबारक कोडिंग :)


8

एक अजगर डेकोरेटर को मौलिक रूप से अलग तरीके से बुलाया जाता है, जो इस बात पर निर्भर करता है कि आप इसे तर्क देते हैं या नहीं। सजावट वास्तव में सिर्फ (सिंटैक्टिकली प्रतिबंधित) अभिव्यक्ति है।

अपने पहले उदाहरण में:

@redirect_output("somewhere.log")
def foo():
    ....

फ़ंक्शन redirect_outputको दिए गए तर्क के साथ कहा जाता है, जो कि एक डेकोरेटर फ़ंक्शन को वापस करने की उम्मीद है, जिसे स्वयं fooएक तर्क के रूप में कहा जाता है, जो (अंत में!) अंतिम सजाए गए फ़ंक्शन को वापस करने की उम्मीद है।

समतुल्य कोड इस तरह दिखता है:

def foo():
    ....
d = redirect_output("somewhere.log")
foo = d(foo)

आपके दूसरे उदाहरण के लिए समान कोड दिखता है:

def foo():
    ....
d = redirect_output
foo = d(foo)

तो आप वह कर सकते हैं जो आप चाहते हैं लेकिन पूरी तरह से सहज तरीके से नहीं:

import types
def redirect_output(arg):
    def decorator(file, f):
        def df(*args, **kwargs):
            print 'redirecting to ', file
            return f(*args, **kwargs)
        return df
    if type(arg) is types.FunctionType:
        return decorator(sys.stderr, arg)
    return lambda f: decorator(arg, f)

यह तब तक ठीक होना चाहिए जब तक आप अपने डेकोरेटर के लिए एक फ़ंक्शन के रूप में फ़ंक्शन का उपयोग करना चाहते हैं, जिस स्थिति में डेकोरेटर गलत तरीके से यह मान लेगा कि उसके पास कोई तर्क नहीं है। यह भी विफल हो जाएगा यदि यह सजावट किसी अन्य सजावट पर लागू होती है जो फ़ंक्शन प्रकार वापस नहीं करती है।

एक वैकल्पिक विधि केवल यह आवश्यक है कि डेकोरेटर फ़ंक्शन को हमेशा कहा जाता है, भले ही वह बिना किसी तर्क के हो। इस मामले में, आपका दूसरा उदाहरण इस तरह दिखेगा:

@redirect_output()
def foo():
    ....

डेकोरेटर फ़ंक्शन कोड इस तरह दिखेगा:

def redirect_output(file = sys.stderr):
    def decorator(file, f):
        def df(*args, **kwargs):
            print 'redirecting to ', file
            return f(*args, **kwargs)
        return df
    return lambda f: decorator(file, f)

2

वास्तव में, @ bj0 के समाधान में कैविएट केस को आसानी से जांचा जा सकता है:

def meta_wrap(decor):
    @functools.wraps(decor)
    def new_decor(*args, **kwargs):
        if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
            # this is the double-decorated f. 
            # Its first argument should not be a callable
            doubled_f = decor(args[0])
            @functools.wraps(doubled_f)
            def checked_doubled_f(*f_args, **f_kwargs):
                if callable(f_args[0]):
                    raise ValueError('meta_wrap failure: '
                                'first positional argument cannot be callable.')
                return doubled_f(*f_args, **f_kwargs)
            return checked_doubled_f 
        else:
            # decorator arguments
            return lambda real_f: decor(real_f, *args, **kwargs)

    return new_decor

इस असफल-सुरक्षित संस्करण के लिए यहां कुछ परीक्षण मामले दिए गए हैं meta_wrap।

    @meta_wrap
    def baddecor(f, caller=lambda x: -1*x):
        @functools.wraps(f)
        def _f(*args, **kwargs):
            return caller(f(args[0]))
        return _f

    @baddecor  # used without arg: no problem
    def f_call1(x):
        return x + 1
    assert f_call1(5) == -6

    @baddecor(lambda x : 2*x) # bad case
    def f_call2(x):
        return x + 1
    f_call2(5)  # raises ValueError

    # explicit keyword: no problem
    @baddecor(caller=lambda x : 100*x)
    def f_call3(x):
        return x + 1
    assert f_call3(5) == 600

1
धन्यवाद। यह मददगार है!
— प्रगति अग्रवाल

1

चूंकि किसी ने इसका उल्लेख नहीं किया है, इसलिए कॉल करने योग्य वर्ग का उपयोग करने वाला एक समाधान भी है जो मुझे अधिक सुरुचिपूर्ण लगता है, खासकर ऐसे मामलों में जहां सज्जाकार जटिल है और कोई इसे कई तरीकों (कार्यों) में विभाजित करना चाह सकता है। यह समाधान __new__अनिवार्य रूप से दूसरों को इंगित करने के लिए जादू की विधि का उपयोग करता है। पहले पता लगाएं कि डेकोरेटर का उपयोग उचित तरीके से समायोजन से कैसे किया गया।

class decorator_with_arguments(object):

    def __new__(cls, decorated_function=None, **kwargs):

        self = super().__new__(cls)
        self._init(**kwargs)

        if not decorated_function:
            return self
        else:
            return self.__call__(decorated_function)

    def _init(self, arg1="default", arg2="default", arg3="default"):
        self.arg1 = arg1
        self.arg2 = arg2
        self.arg3 = arg3

    def __call__(self, decorated_function):

        def wrapped_f(*args):
            print("Decorator arguments:", self.arg1, self.arg2, self.arg3)
            print("decorated_function arguments:", *args)
            decorated_function(*args)

        return wrapped_f

@decorator_with_arguments(arg1=5)
def sayHello(a1, a2, a3, a4):
    print('sayHello arguments:', a1, a2, a3, a4)

@decorator_with_arguments()
def sayHello(a1, a2, a3, a4):
    print('sayHello arguments:', a1, a2, a3, a4)

@decorator_with_arguments
def sayHello(a1, a2, a3, a4):
    print('sayHello arguments:', a1, a2, a3, a4)

यदि डेकोरेटर का उपयोग तर्कों के साथ किया जाता है, तो यह बराबर होता है:

result = decorator_with_arguments(arg1=5)(sayHello)(a1, a2, a3, a4)

कोई यह देख सकता है कि तर्क arg1सही ढंग से कंस्ट्रक्टर को दिए गए हैं और सजाए गए फ़ंक्शन को पास किया गया है__call__

लेकिन अगर डेकोरेटर का उपयोग तर्कों के बिना किया जाता है, तो यह बराबर होता है:

result = decorator_with_arguments(sayHello)(a1, a2, a3, a4)

आप देखते हैं कि इस मामले में सजाया गया कार्य सीधे कंस्ट्रक्टर को पास किया जाता है और कॉल को __call__पूरी तरह से छोड़ दिया जाता है। इसलिए हमें __new__जादू की विधि में इस मामले की देखभाल के लिए तर्क को नियोजित करने की आवश्यकता है ।

हम __init__इसके बजाय उपयोग क्यों नहीं कर सकते __new__? कारण सरल है: अजगर किसी से भी किसी भी अन्य मूल्यों को वापस करने पर प्रतिबंध लगाता है__init__

चेतावनी

इस दृष्टिकोण का एक पक्ष प्रभाव है। यह फ़ंक्शन हस्ताक्षर को संरक्षित नहीं करेगा!


0

उपरोक्त से अधिक पूर्ण उत्तर देने के लिए:

"क्या एक डेकोरेटर बनाने का एक तरीका है जिसका उपयोग तर्क के साथ और बिना दोनों के लिए किया जा सकता है?"

नहीं , कोई सामान्य तरीका नहीं है क्योंकि दो अलग-अलग उपयोग मामलों का पता लगाने के लिए वर्तमान में अजगर भाषा में कुछ गायब है।

हालाँकि , जैसा कि पहले से ही अन्य उत्तरों जैसे कि bj0एस द्वारा बताया गया है , एक क्लूनी वर्कअराउंड है जो प्राप्त किए गए पहले स्थितीय तर्क के प्रकार और मूल्य की जांच करना है (और यह जांचने के लिए कि क्या कोई अन्य तर्क गैर-डिफ़ॉल्ट मान नहीं है)। यदि आप इस बात की गारंटी देते हैं कि उपयोगकर्ता आपके डेकोरेटर के पहले तर्क के रूप में कॉल करने योग्य नहीं होंगे , तो आप इस समाधान का उपयोग कर सकते हैं। ध्यान दें कि यह क्लास डेकोरेटर के लिए समान है (पिछले वाक्य में क्लास द्वारा कॉल करने योग्य बदलें)।

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

लेकिन स्पष्ट रूप से सबसे अच्छा यह होगा कि यहां किसी भी पुस्तकालय की आवश्यकता न हो और उस सुविधा को सीधे अजगर भाषा से प्राप्त किया जा सके। यदि, आप की तरह, आपको लगता है कि यह अफ़सोस की बात है कि अजगर भाषा आज की नहीं है , तो इस सवाल का एक साफ जवाब देने में सक्षम है, अजगर बगट्रैकर में इस विचार का समर्थन करने में संकोच न करें : https: //bug.python .org / issue36553 !

अजगर को बेहतर भाषा बनाने में आपकी मदद के लिए बहुत बहुत धन्यवाद :)


0

यह बिना किसी उपद्रव के काम करता है:

from functools import wraps

def memoize(fn=None, hours=48.0):
  def deco(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
      return fn(*args, **kwargs)
    return wrapper

  if callable(fn): return deco(fn)
  return deco

-1

क्या आपने डिफ़ॉल्ट मानों के साथ खोजशब्द तर्क की कोशिश की है? कुछ इस तरह

def decorate_something(foo=bar, baz=quux):
    pass

-2

आम तौर पर आप पायथन में डिफ़ॉल्ट तर्क दे सकते हैं ...

def redirect_output(fn, output = stderr):
    # whatever

यकीन नहीं है कि अगर सज्जाकारों के साथ भी काम करता है, हालांकि। मैं किसी भी कारण से नहीं जानता कि यह क्यों नहीं होगा।


2
यदि आप कहते हैं कि @dec (abc) फ़ंक्शन को सीधे डिक्रिप्ट करने के लिए पारित नहीं किया गया है। dec (abc) कुछ देता है, और यह वापसी मान सज्जाकार के रूप में उपयोग किया जाता है। तो dec (abc) को एक फ़ंक्शन वापस करना पड़ता है, जो तब एक पैरामीटर के रूप में सजाए गए फ़ंक्शन को पास करता है। (इसके अलावा thobes कोड देखें)
— sth

-2

वर्सेट के उत्तर पर निर्माण:

imports sys

def redirect_output(func, output=None):
    if output is None:
        output = sys.stderr
    if isinstance(output, basestring):
        output = open(output, 'w') # etc...
    # everything else...

यह @redirect_output("somewhere.log") def foo()प्रश्न में उदाहरण में एक डेकोरेटर की तरह इस्तेमाल नहीं किया जा सकता है ।
— एहबाकॉस्ट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.