পরামিতি সহ সজ্জা?


401

সজ্জাকারীর দ্বারা ভেরিয়েবল 'বীমা_মোড' স্থানান্তর করতে আমার একটি সমস্যা আছে। আমি নিম্নলিখিত সজ্জনকারী বিবৃতি দ্বারা এটি করব:

 @execute_complete_reservation(True)
 def test_booking_gta_object(self):
     self.test_select_gta_object()

কিন্তু দুর্ভাগ্যক্রমে, এই বক্তব্যটি কার্যকর হয় না। সম্ভবত এই সমস্যা সমাধানের আরও ভাল উপায় আছে।

def execute_complete_reservation(test_case,insurance_mode):
    def inner_function(self,*args,**kwargs):
        self.test_create_qsf_query()
        test_case(self,*args,**kwargs)
        self.test_select_room_option()
        if insurance_mode:
            self.test_accept_insurance_crosseling()
        else:
            self.test_decline_insurance_crosseling()
        self.test_configure_pax_details()
        self.test_configure_payer_details

    return inner_function

3
আপনার উদাহরণ বাক্যবৈজ্ঞানিকভাবে বৈধ নয়। execute_complete_reservationদুটি প্যারামিটার লাগে তবে আপনি এটি পাস করছেন। সাজসজ্জারগুলি অন্যান্য ফাংশনের অভ্যন্তরে ফাংশন মোড়ানোর জন্য কেবল সিনট্যাকটিক চিনি। সম্পূর্ণ ডকুমেন্টেশনের জন্য docs.python.org/references/compound_stmts.html# ফাংশন দেখুন ।
ব্রায়ান ক্লেপার

উত্তর:


687

আর্গুমেন্ট সহ সাজসজ্জার জন্য সিনট্যাক্সটি কিছুটা আলাদা - যুক্তিযুক্ত সজ্জাকারীর একটি ফাংশন ফিরিয়ে নেওয়া উচিত যা কোনও ফাংশন নেবে এবং অন্য ফাংশনটি ফিরিয়ে দেবে। সুতরাং এটি সত্যই একটি সাধারণ সাজসজ্জা ফিরে আসা উচিত। কিছুটা বিভ্রান্তিকর, তাই না? আমি কি মানে হয়:

def decorator_factory(argument):
    def decorator(function):
        def wrapper(*args, **kwargs):
            funny_stuff()
            something_with_argument(argument)
            result = function(*args, **kwargs)
            more_funny_stuff()
            return result
        return wrapper
    return decorator

এখানে আপনি এই বিষয়ে আরও পড়তে পারেন - কলযোগ্য বস্তুগুলি ব্যবহার করে এটি প্রয়োগ করাও সম্ভব এবং এটি এখানেও ব্যাখ্যা করা হয়েছে।


56
আমি আশ্চর্য হয়েছি কেন 'ফাংশন' এর পরে পরবর্তী সজ্জা যুক্তি হিসাবে প্যারামিটারগুলিতে পাস করে জিভিআর এটি বাস্তবায়ন করেনি? 'ইও ডাগ আমি শুনেছি তোমাকে বন্ধের মতো ...' ইত্যাদি।
মিশেল মোলার 16

3
> প্রথম যুক্তি বা শেষ হতে পারে? স্পষ্টতই প্রথমে, যেহেতু প্যারামিটারগুলি পরিবর্তনশীল দৈর্ঘ্যের একটি পরামিতি তালিকা। > এটিও অদ্ভুত যে আপনি সংজ্ঞায়নের চেয়ে পৃথক স্বাক্ষরের সাথে ফাংশনটি "কল" করবেন। আপনি যেমন উল্লেখ করেছেন, এটি আসলে বেশ ভাল ফিট করবে - এটি কোনও শ্রেণিবদ্ধ পদ্ধতিকে কীভাবে বলা হয় তার সাথে অনেকটা উপমা। এটিকে আরও স্পষ্ট করার জন্য, আপনার কাছে ডেকরেটারের মতো কিছু থাকতে পারে (স্ব-ফাঙ্ক, প্যারাম 1, ...) কনভেনশন। তবে দ্রষ্টব্য: আমি এখানে কোনও পরিবর্তনের পক্ষে ন্যূনতম, পাইথন তার জন্য খুব দূরে রাস্তা এবং আমরা দেখতে পাচ্ছি যে ব্রেকিং পরিবর্তনগুলি কীভাবে কার্যকর হয়েছে ..
মিশেল মোলার

21
আপনি সাজানোর মোড়কের জন্য খুব কার্যকর ফান্টাকুলস.আর্যাপগুলি ভুলে গেছেন :)
সকেটপেইর

10
ফাংশন কল করার সময় আপনি ফিরতি সম্পর্কে ভুলে গিয়েছিলেন, যেমন return function(*args, **kwargs)
ফর্মিয়াকিজিক

36
হয়তো সুস্পষ্ট, কিন্তু ধরো যদি: আপনি এই প্রসাধক ব্যবহার করতে হবে @decorator()এবং শুধু @decorator, এমনকি যদি আপনি শুধুমাত্র ঐচ্ছিক আর্গুমেন্ট আছে।
প্যাট্রিক মেভিজেক

324

সম্পাদনা করুন : সাজসজ্জারীদের মানসিক মডেলটির গভীরতা বোঝার জন্য, এই দুর্দান্ত পাইকন টকটি দেখুন । ভাল 30 মিনিটের মূল্য।

যুক্তিযুক্ত সজ্জা সম্পর্কে চিন্তা করার এক উপায়

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

অনুবাদ

foo = decorator(foo)

সুতরাং যদি সাজসজ্জার পক্ষে যুক্তি থাকে,

@decorator_with_args(arg)
def foo(*args, **kwargs):
    pass

অনুবাদ

foo = decorator_with_args(arg)(foo)

decorator_with_args এটি একটি ফাংশন যা একটি কাস্টম যুক্তি গ্রহণ করে এবং যা প্রকৃত সাজসজ্জা দেয় (এটি সজ্জিত ফাংশনটিতে প্রয়োগ করা হবে)।

আমি আমার সাজসজ্জারকে সহজ করতে পার্টিয়ালগুলির সাথে একটি সাধারণ কৌশল ব্যবহার করি

from functools import partial

def _pseudo_decor(fun, argument):
    def ret_fun(*args, **kwargs):
        #do stuff here, for eg.
        print ("decorator arg is %s" % str(argument))
        return fun(*args, **kwargs)
    return ret_fun

real_decorator = partial(_pseudo_decor, argument=arg)

@real_decorator
def foo(*args, **kwargs):
    pass

হালনাগাদ:

উপরে, fooহয়ে যায়real_decorator(foo)

কোনও ফাংশন সজ্জিত করার একটি প্রভাব হ'ল নামটি fooসাজসজ্জার ঘোষণার উপরে ওভাররাইড করা হয়। fooযা কিছু ফিরে আসে তার দ্বারা "ওভাররাইড" হয় real_decorator। এই ক্ষেত্রে, একটি নতুন ফাংশন অবজেক্ট।

এর সমস্ত fooমেটাডেটা ওভাররাইড করা হয়েছে, উল্লেখযোগ্যভাবে ডকাস্ট্রিং এবং ফাংশন নাম।

>>> print(foo)
<function _pseudo_decor.<locals>.ret_fun at 0x10666a2f0>

functools.wraps ফেরত ফাংশনে ডকস্ট্রিং এবং নাম "লিফট" করার জন্য একটি সুবিধাজনক পদ্ধতি দেয়।

from functools import partial, wraps

def _pseudo_decor(fun, argument):
    # magic sauce to lift the name and doc of the function
    @wraps(fun)
    def ret_fun(*args, **kwargs):
        #do stuff here, for eg.
        print ("decorator arg is %s" % str(argument))
        return fun(*args, **kwargs)
    return ret_fun

real_decorator = partial(_pseudo_decor, argument=arg)

@real_decorator
def bar(*args, **kwargs):
    pass

>>> print(bar)
<function __main__.bar(*args, **kwargs)>

4
আপনার উত্তরটি সাজসজ্জার অন্তর্নিহিত
অরথোগোনিটি

আপনি যোগ করতে পারেন @functools.wraps?
মিঃ_আর_আমস_ডি

1
@ মিঃ_আর_আমস_ডি, আমি পোস্টটির সাথে একটি উদাহরণ সহ আপডেট করেছি functool.wraps। এটি উদাহরণে যুক্ত করা পাঠকদের আরও বিভ্রান্ত করতে পারে।
srj

7
argএখানে কি !?
displayname

1
আপনি কিভাবে প্রেরণ যুক্তি পাস হবে barতাদের যুক্তির real_decorator?
চ্যাং ঝাও

85

আমি একটি ধারণা দেখাতে চাই যা আইএমএইচও বেশ মার্জিত। টি ডুব্রাউনিক দ্বারা প্রস্তাবিত সমাধানটি এমন একটি প্যাটার্ন দেখায় যা সর্বদা একই থাকে: ডেকোরেটার যা করুক না কেন আপনার তিন স্তরযুক্ত মোড়কের প্রয়োজন।

সুতরাং আমি ভেবেছিলাম এটি একটি মেটা-ডেকরেটারের জন্য কাজ, অর্থাত্, সজ্জকারদের জন্য সজ্জিত। যেহেতু ডেকোরেটার একটি ফাংশন, এটি আসলে নিয়মিত সাজসজ্জার হিসাবে যুক্তি সহ কাজ করে:

def parametrized(dec):
    def layer(*args, **kwargs):
        def repl(f):
            return dec(f, *args, **kwargs)
        return repl
    return layer

পরামিতি যুক্ত করার জন্য এটি নিয়মিত ডেকরেটারে প্রয়োগ করা যেতে পারে। সুতরাং উদাহরণস্বরূপ, বলুন যে আমাদের সজ্জা আছে যা একটি ফাংশনের ফলাফল দ্বিগুণ করে:

def double(f):
    def aux(*xs, **kws):
        return 2 * f(*xs, **kws)
    return aux

@double
def function(a):
    return 10 + a

print function(3)    # Prints 26, namely 2 * (10 + 3)

সঙ্গে @parametrizedআমরা একটি জেনেরিক নির্মাণ করতে পারেন @multiplyপ্রসাধক একটি প্যারামিটার থাকার

@parametrized
def multiply(f, n):
    def aux(*xs, **kws):
        return n * f(*xs, **kws)
    return aux

@multiply(2)
def function(a):
    return 10 + a

print function(3)    # Prints 26

@multiply(3)
def function_again(a):
    return 10 + a

print function(3)          # Keeps printing 26
print function_again(3)    # Prints 39, namely 3 * (10 + 3)

প্রচলিতভাবে প্যারামিট্রাইজড ডেকোরেটারের প্রথম প্যারামিটারটি হ'ল ফাংশন, বাকী যুক্তিগুলি প্যারামিট্রাইজড ডিকোয়টারের প্যারামিটারের সাথে মিল রাখে।

একটি আকর্ষণীয় ব্যবহারের উদাহরণটি টাইপ-নিরাপদ দৃ dec়সজ্জাকারী হতে পারে:

import itertools as it

@parametrized
def types(f, *types):
    def rep(*args):
        for a, t, n in zip(args, types, it.count()):
            if type(a) is not t:
                raise TypeError('Value %d has not type %s. %s instead' %
                    (n, t, type(a))
                )
        return f(*args)
    return rep

@types(str, int)  # arg1 is str, arg2 is int
def string_multiply(text, times):
    return text * times

print(string_multiply('hello', 3))    # Prints hellohellohello
print(string_multiply(3, 3))          # Fails miserably with TypeError

একটি চূড়ান্ত নোট: এখানে আমি functools.wrapsমোড়ক ফাংশনগুলির জন্য ব্যবহার করছি না , তবে আমি এটি সর্বদা ব্যবহারের পরামর্শ দেব।


3
এটি হুবহু ব্যবহার করে নি, তবে ধারণাটি ঘিরে আমার মাথা পেতে সাহায্য করেছে :) ধন্যবাদ!
mouckatron

আমি এটি চেষ্টা করেছিলাম এবং কিছু সমস্যা ছিল ।
জেফ

@ জেফ আপনি কি ধরনের সমস্যা নিয়ে এসেছেন তা আমাদের সাথে ভাগ করে নিতে পারেন?
ডাকাভ

আমি আমার প্রশ্নের সাথে এটি যুক্ত করেছিলাম, এবং আমি এটি বের করেছিলাম ... @wrapsআমার বিশেষ মামলার জন্য আমাকে আমার কাছে ফোন করা দরকার ।
জেফ

4
ওহ ছেলে, আমি এই পুরো দিন হারিয়েছি। ধন্যবাদ, আমি এই উত্তরটি ঘিরে এসেছি (যা ঘটনাক্রমে পুরো ইন্টারনেটে তৈরি করা সেরা উত্তর হতে পারে)। তারাও আপনার @parametrizedকৌশলটি ব্যবহার করে। আমার যে সমস্যাটি ছিল তা ছিল আমি @বাক্যবিন্যাসটি ভুলে গিয়েছিলাম আসল কলগুলির সমান (কোনওভাবে আমি এটি জানতাম এবং জানতাম না যে আপনি আমার প্রশ্ন থেকে সংগ্রহ করতে পারেন একই সাথে)। তাই আপনি যদি অনুবাদ করতে চান @মধ্যে সিনট্যাক্স জাগতিক কল কিভাবে এটি কাজ করে চেক করতে, আপনি ভাল এটি মন্তব্য সাময়িকভাবে প্রথম অথবা আপনি এটা দুইবার কলিং এবং mumbojumbo ফলাফল পেয়ে শেষ পর্যন্ত চাই
z33k

79

এখানে t.dubrownik এর উত্তরের একটি সামান্য পরিবর্তিত সংস্করণ । কেন?

  1. সাধারণ টেম্পলেট হিসাবে, আপনার মূল ফাংশন থেকে রিটার্ন মানটি ফিরিয়ে দেওয়া উচিত।
  2. এটি ফাংশনের নাম পরিবর্তন করে, যা অন্যান্য সজ্জক / কোডকে প্রভাবিত করতে পারে।

সুতরাং ব্যবহার করুন @functools.wraps():

from functools import wraps

def decorator(argument):
    def real_decorator(function):
        @wraps(function)
        def wrapper(*args, **kwargs):
            funny_stuff()
            something_with_argument(argument)
            retval = function(*args, **kwargs)
            more_funny_stuff()
            return retval
        return wrapper
    return real_decorator

37

আমি অনুমান করি যে আপনার সমস্যাটি আপনার ডেকোরেটরের কাছে তর্ক বিতর্ক করছে। এটি কিছুটা জটিল এবং সোজা নয়।

এটি কীভাবে করা যায় তার একটি উদাহরণ এখানে:

class MyDec(object):
    def __init__(self,flag):
        self.flag = flag
    def __call__(self, original_func):
        decorator_self = self
        def wrappee( *args, **kwargs):
            print 'in decorator before wrapee with flag ',decorator_self.flag
            original_func(*args,**kwargs)
            print 'in decorator after wrapee with flag ',decorator_self.flag
        return wrappee

@MyDec('foo de fa fa')
def bar(a,b,c):
    print 'in bar',a,b,c

bar('x','y','z')

ছাপে:

in decorator before wrapee with flag  foo de fa fa
in bar x y z
in decorator after wrapee with flag  foo de fa fa

আরও বিশদ জানতে ব্রুস একেলের নিবন্ধটি দেখুন।


20
সাজসজ্জার ক্লাস থেকে সাবধান। উদাহরণস্বরূপ বর্ণনাকারীদের যুক্তিটিকে ম্যানুয়ালি পুনরায় উদ্ভাবন না করা পর্যন্ত তারা পদ্ধতিতে কাজ করে না।

9
দেলানান, বিস্তৃত যত্ন? আমাকে কেবল একবার এই প্যাটার্নটি ব্যবহার করতে হয়েছিল, তাই আমি এখনও কোনও সমস্যায় পড়িনি।
রস রজার্স

2
@ রোসরোজার্স আমার অনুমান যে @ ডেলান এমন জিনিসগুলির উল্লেখ করছেন __name__যা সাজসজ্জার শ্রেণীর উদাহরণ নেই?
jamesc

9
@ জামেস্ক এটিও সমাধান করার পক্ষে তুলনামূলক সহজ। আমি যে নির্দিষ্ট ক্ষেত্রে উল্লেখ করছি সেটি হ'ল class Foo: @MyDec(...) def method(self, ...): blahযা কার্যকর হয় না কারণ Foo().methodএকটি আবদ্ধ পদ্ধতি হবে না এবং selfস্বয়ংক্রিয়ভাবে পাস হবে না । এটিও MyDecএকটি বর্ণনাকারী তৈরি করে এবং এতে আবদ্ধ পদ্ধতি তৈরি করে ঠিক করা যেতে পারে __get__তবে এটি আরও জড়িত এবং আরও কম স্পষ্ট। শেষ পর্যন্ত, সাজসজ্জার ক্লাসগুলি যেমন মনে হয় তত সুবিধাজনক নয়।

2
@ ডেলান আমি এই ক্যাভিয়েটটি আরও বিশদভাবে বৈশিষ্ট্যযুক্ত দেখতে চাই। আমি এটিকে হিট করছি এবং কাজটি করে এমন কোনও সমাধান দেখতে আগ্রহী (এটি আরও কম জড়িত হলেও তা জড়িত)।
এইএপসন্তরান

12
def decorator(argument):
    def real_decorator(function):
        def wrapper(*args):
            for arg in args:
                assert type(arg)==int,f'{arg} is not an interger'
            result = function(*args)
            result = result*argument
            return result
        return wrapper
    return real_decorator

সাজসজ্জার ব্যবহার

@decorator(2)
def adder(*args):
    sum=0
    for i in args:
        sum+=i
    return sum

এরপর

adder(2,3)

উত্পাদন করে

10

কিন্তু

adder('hi',3)

উত্পাদন করে

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-143-242a8feb1cc4> in <module>
----> 1 adder('hi',3)

<ipython-input-140-d3420c248ebd> in wrapper(*args)
      3         def wrapper(*args):
      4             for arg in args:
----> 5                 assert type(arg)==int,f'{arg} is not an interger'
      6             result = function(*args)
      7             result = result*argument

AssertionError: hi is not an interger

8

এটি কোনও ফাংশন ডেকরেটারের জন্য একটি টেম্পলেট যা ()কোনও প্যারামিটার দেওয়ার প্রয়োজন নেই:

import functools


def decorator(x_or_func=None, *decorator_args, **decorator_kws):
    def _decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kws):
            if 'x_or_func' not in locals() \
                    or callable(x_or_func) \
                    or x_or_func is None:
                x = ...  # <-- default `x` value
            else:
                x = x_or_func
            return func(*args, **kws)

        return wrapper

    return _decorator(x_or_func) if callable(x_or_func) else _decorator

এর উদাহরণ নীচে দেওয়া হল:

def multiplying(factor_or_func=None):
    def _decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            if 'factor_or_func' not in locals() \
                    or callable(factor_or_func) \
                    or factor_or_func is None:
                factor = 1
            else:
                factor = factor_or_func
            return factor * func(*args, **kwargs)
        return wrapper
    return _decorator(factor_or_func) if callable(factor_or_func) else _decorator


@multiplying
def summing(x): return sum(x)

print(summing(range(10)))
# 45


@multiplying()
def summing(x): return sum(x)

print(summing(range(10)))
# 45


@multiplying(10)
def summing(x): return sum(x)

print(summing(range(10)))
# 450

এটিও নোট করুন যে factor_or_func(বা অন্য কোনও প্যারামিটার) কখনই আবার সাইন ইন করা উচিত নয়wrapper()
norok2

আপনার চেক ইন করা দরকার কেন locals()?
শীতল শাহ

@ শীতলশাহ এমন কেসটি জুড়ে যেখানে সজ্জা ছাড়াই ব্যবহৃত হয় ()
নরোক 2

4

আমার উদাহরণস্বরূপ, আমি একটি নতুন সজ্জা ফাংশন তৈরি করতে এক লাইনের ল্যাম্বডার মাধ্যমে এটি সমাধান করার সিদ্ধান্ত নিয়েছি:

def finished_message(function, message="Finished!"):

    def wrapper(*args, **kwargs):
        output = function(*args,**kwargs)
        print(message)
        return output

    return wrapper

@finished_message
def func():
    pass

my_finished_message = lambda f: finished_message(f, "All Done!")

@my_finished_message
def my_func():
    pass

if __name__ == '__main__':
    func()
    my_func()

মৃত্যুদন্ড কার্যকর করা হলে, এই মুদ্রণ:

Finished!
All Done!

অন্যান্য সমাধানের মতো সম্ভবত বর্ধমান নয়, তবে আমার পক্ষে কাজ করেছেন worked


এইটা কাজ করে. যদিও হ্যাঁ, এটি সাজসজ্জারকে মান সেট করা শক্ত করে তোলে।
অরিন্দম রায়চৌধুরী

3

প্যারামিটারের সাথে এবং ছাড়াই কাজ করে এমন একটি সজ্জা রচনা লিখানো একটি চ্যালেঞ্জ কারণ পাইথন এই দুটি ক্ষেত্রে সম্পূর্ণ ভিন্ন আচরণ প্রত্যাশা করে! অনেক উত্তর এটিকে ঘিরে কাজ করার চেষ্টা করেছে এবং নীচে @ নরোক 2 দ্বারা উত্তরের উত্তর দেওয়া হয়েছে। বিশেষত, এই প্রকরণটি এর ব্যবহারকে সরিয়ে দেয় locals()

@ নরোক 2 দ্বারা প্রদত্ত একই উদাহরণ অনুসরণ করা:

import functools

def multiplying(f_py=None, factor=1):
    assert callable(f_py) or f_py is None
    def _decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            return factor * func(*args, **kwargs)
        return wrapper
    return _decorator(f_py) if callable(f_py) else _decorator


@multiplying
def summing(x): return sum(x)

print(summing(range(10)))
# 45


@multiplying()
def summing(x): return sum(x)

print(summing(range(10)))
# 45


@multiplying(factor=10)
def summing(x): return sum(x)

print(summing(range(10)))
# 450

এই কোড দিয়ে খেলুন

ক্যাচটি হ'ল ব্যবহারকারীর অবস্থানগত পরামিতিগুলির পরিবর্তে কী, পরামিতিগুলির মান জোড়া এবং প্রথম প্যারামিটার সংরক্ষণ করা উচিত।


2

এটি সুপরিচিত যে নিম্নলিখিত দুটি টুকরো কোড প্রায় সমতুল্য:

@dec
def foo():
    pass    foo = dec(foo)

############################################
foo = dec(foo)

একটি সাধারণ ভুল হ'ল ভাবনা যা @কেবল বামতম যুক্তিটি গোপন করে।

@dec(1, 2, 3)
def foo():
    pass    
###########################################
foo = dec(foo, 1, 2, 3)

উপরেরটি যদি @কাজ করে তবে এটি সজ্জা লেখার কাজটি অনেক সহজ হবে । দুর্ভাগ্যক্রমে, জিনিসগুলি এভাবে করা হয় না।


কোনও সজ্জাকারীর কথা বিবেচনা করুন Waitযা কয়েক সেকেন্ডের জন্য প্রোগ্রামের প্রয়োগ কার্যকর করে। আপনি যদি অপেক্ষা অপেক্ষা না করে থাকেন তবে ডিফল্ট মানটি 1 সেকেন্ড। ব্যবহারের কেসগুলি নীচে দেখানো হয়েছে।

##################################################
@Wait
def print_something(something):
    print(something)

##################################################
@Wait(3)
def print_something_else(something_else):
    print(something_else)

##################################################
@Wait(delay=3)
def print_something_else(something_else):
    print(something_else)

যখন Waitকোনও যুক্তি থাকে যেমন যেমন @Wait(3), তখন অন্য কিছু হওয়ার আগেই কলটি Wait(3) কার্যকর করা হয়।

তা হল, নিম্নলিখিত দুটি টুকরো কোড সমান

@Wait(3)
def print_something_else(something_else):
    print(something_else)

###############################################
return_value = Wait(3)
@return_value
def print_something_else(something_else):
    print(something_else)

এটা একটা সমস্যা.

if `Wait` has no arguments:
    `Wait` is the decorator.
else: # `Wait` receives arguments
    `Wait` is not the decorator itself.
    Instead, `Wait` ***returns*** the decorator

একটি সমাধান নীচে দেখানো হয়েছে:

আসুন নীচের ক্লাসটি তৈরি করে শুরু করুন DelayedDecorator:

class DelayedDecorator:
    def __init__(i, cls, *args, **kwargs):
        print("Delayed Decorator __init__", cls, args, kwargs)
        i._cls = cls
        i._args = args
        i._kwargs = kwargs
    def __call__(i, func):
        print("Delayed Decorator __call__", func)
        if not (callable(func)):
            import io
            with io.StringIO() as ss:
                print(
                    "If only one input, input must be callable",
                    "Instead, received:",
                    repr(func),
                    sep="\n",
                    file=ss
                )
                msg = ss.getvalue()
            raise TypeError(msg)
        return i._cls(func, *i._args, **i._kwargs)

এখন আমরা এই জাতীয় জিনিস লিখতে পারি:

 dec = DelayedDecorator(Wait, delay=4)
 @dec
 def delayed_print(something):
    print(something)

মনে রাখবেন যে:

  • dec একাধিক যুক্তি গ্রহণ করে না।
  • dec কেবল মোড়ানোর জন্য ফাংশনটি গ্রহণ করে।

    PolyArgDecoratorMeta (প্রকার) শ্রেণি আমদানি করুন: ডিএফ কল (অপেক্ষা করুন, * আরগস, ** কোয়ার্গস): চেষ্টা করুন: আরগ_কাউন্ট = লেন (আরগস) যদি (আরগ_কাউন্ট == 1): কলযোগ্য (আরগস [0]): সুপারক্লাস = পরিদর্শন করুন। getmro (PolyArgDecoratorMeta) [1] r = সুপারক্লাস। কল করুন (অপেক্ষা করুন, আরগস [0]) অন্য: r = বিলম্বিত ডেকোরেটর (অপেক্ষা করুন, * আরগস, ** কোয়ার্গস) অন্য: আর = বিলম্বিত ডেকোরেটর (অপেক্ষা করুন, * আরগস, ** কাওয়ার্গস) অবশেষে: পাস রিটার্ন

    আমদানির সময় শ্রেণি অপেক্ষা (metaclass = PolyArgDecoratorMeta): Def init (i, func, বিলম্ব = 2): i._func = func i._delay = বিলম্ব

    def __call__(i, *args, **kwargs):
        time.sleep(i._delay)
        r = i._func(*args, **kwargs)
        return r 

নিম্নলিখিত দুটি টুকরো কোড সমান:

@Wait
def print_something(something):
     print (something)

##################################################

def print_something(something):
    print(something)
print_something = Wait(print_something)

আমরা "something"কনসোলে খুব ধীরে ধীরে মুদ্রণ করতে পারি , নীচে:

print_something("something")

#################################################
@Wait(delay=1)
def print_something_else(something_else):
    print(something_else)

##################################################
def print_something_else(something_else):
    print(something_else)

dd = DelayedDecorator(Wait, delay=1)
print_something_else = dd(print_something_else)

##################################################

print_something_else("something")

চূড়ান্ত নোটস

এটি অনেকটা কোডের মতো দেখতে পারে তবে আপনাকে ক্লাস DelayedDecoratorএবং PolyArgDecoratorMetaপ্রতিবার লিখতে হবে না । আপনাকে ব্যক্তিগতভাবে নিম্নরূপ কিছু লিখতে হবে এমন কোডটি যা মোটামুটি সংক্ষিপ্ত:

from PolyArgDecoratorMeta import PolyArgDecoratorMeta
import time
class Wait(metaclass=PolyArgDecoratorMeta):
 def __init__(i, func, delay = 2):
     i._func = func
     i._delay = delay

 def __call__(i, *args, **kwargs):
     time.sleep(i._delay)
     r = i._func(*args, **kwargs)
     return r

1

কাস্টমাইজড ডেকোরেটর ফাংশন উত্পন্ন করতে এই "ডেকোরেটরিজ ফাংশন" সংজ্ঞা দিন

def decoratorize(FUN, **kw):
    def foo(*args, **kws):
        return FUN(*args, **kws, **kw)
    return foo

এটি এইভাবে ব্যবহার করুন:

    @decoratorize(FUN, arg1 = , arg2 = , ...)
    def bar(...):
        ...

1

উপরে দুর্দান্ত উত্তর। এটি একটিও চিত্রিত করে @wraps, যা মূল ফাংশন থেকে ডক স্ট্রিং এবং ফাংশনের নাম নেয় এবং এটি নতুন মোড়ানো সংস্করণে প্রয়োগ করে:

from functools import wraps

def decorator_func_with_args(arg1, arg2):
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            print("Before orginal function with decorator args:", arg1, arg2)
            result = f(*args, **kwargs)
            print("Ran after the orginal function")
            return result
        return wrapper
    return decorator

@decorator_func_with_args("foo", "bar")
def hello(name):
    """A function which prints a greeting to the name provided.
    """
    print('hello ', name)
    return 42

print("Starting script..")
x = hello('Bob')
print("The value of x is:", x)
print("The wrapped functions docstring is:", hello.__doc__)
print("The wrapped functions name is:", hello.__name__)

ছাপে:

Starting script..
Before orginal function with decorator args: foo bar
hello  Bob
Ran after the orginal function
The value of x is: 42
The wrapped functions docstring is: A function which prints a greeting to the name provided.
The wrapped functions name is: hello

0

যদি ফাংশন এবং সাজসজ্জার উভয় পক্ষকে তর্ক করতে হয় তবে আপনি নীচের পদ্ধতিটি অনুসরণ করতে পারেন।

উদাহরণস্বরূপ এখানে একটি সাজসজ্জা রয়েছে decorator1যা একটি যুক্তি নেয়

@decorator1(5)
def func1(arg1, arg2):
    print (arg1, arg2)

func1(1, 2)

এখন যদি decorator1যুক্তিটি গতিশীল হতে হয়, বা ফাংশনটি কল করার সময় পাস করা হয়,

def func1(arg1, arg2):
    print (arg1, arg2)


a = 1
b = 2
seconds = 10

decorator1(seconds)(func1)(a, b)

উপরের কোডে

  • seconds জন্য যুক্তি decorator1
  • a, b এর যুক্তি func1
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.