আমি কীভাবে পাইথন ডেকরেটারের কাছে অতিরিক্ত যুক্তিগুলি পাস করব?


99

আমি নীচের মত একটি সজ্জা আছে।

def myDecorator(test_func):
    return callSomeWrapper(test_func)
def callSomeWrapper(test_func):
    return test_func
@myDecorator
def someFunc():
    print 'hello'

নীচের মতো অন্য একটি যুক্তি গ্রহণ করার জন্য আমি এই সাজসজ্জারকে বাড়িয়ে তুলতে চাই

def myDecorator(test_func,logIt):
    if logIt:
        print "Calling Function: " + test_func.__name__
    return callSomeWrapper(test_func)
@myDecorator(False)
def someFunc():
    print 'Hello'

তবে এই কোডটি ত্রুটি দেয়,

প্রকারের ত্রুটি: মাই ডেকোরেটর () সঠিকভাবে 2 টি আর্গুমেন্ট নেয় (1 প্রদত্ত)

ফাংশনটি স্বয়ংক্রিয়ভাবে কেন পাস হয় না? আমি কীভাবে স্পষ্টভাবে সাজসজ্জার ফাংশনটিতে ফাংশনটি পাস করব?


4
বাল্কি: দয়া করে আপনার যুক্তি হিসাবে বুলিয়ান ব্যবহার এড়িয়ে চলুন, এটি কোনও জিডি পদ্ধতি নয় এবং কোডের পাঠযোগ্যতা হ্রাস করুন
কিট হো

8
@ কিটহো - এটি একটি বুলিয়ান পতাকা, সুতরাং বুলিয়ান মান ব্যবহার করা সঠিক পন্থা।
একেএক্স

4
@ কিটহো - "জিডি" কী? এটা কি ভালো"?
রব বেদনার্ক

উত্তর:


172

যেহেতু আপনি সাজসজ্জারকে একটি ফাংশনের মতো ডাকছেন, তাই এটির অন্য ফাংশনটি ফিরিয়ে নেওয়া দরকার যা আসল সাজসজ্জারক:

def my_decorator(param):
    def actual_decorator(func):
        print("Decorating function {}, with parameter {}".format(func.__name__, param))
        return function_wrapper(func)  # assume we defined a wrapper somewhere
    return actual_decorator

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

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

def log_decorator(log_enabled):
    def actual_decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            if log_enabled:
                print("Calling Function: " + func.__name__)
            return func(*args, **kwargs)
        return wrapper
    return actual_decorator

functools.wrapsনাম এবং মোড়কের ফাংশন docstring মত কল কপি জিনিস, এটি আরো মূল ফাংশন অনুরূপ করা।

ব্যবহারের উদাহরণ:

>>> @log_decorator(True)
... def f(x):
...     return x+1
...
>>> f(4)
Calling Function: f
5

11
এবং ব্যবহার functools.wrapsকরা বাঞ্ছনীয় - এটি মোড়ানো ফাংশনটির আসল নাম, ডকস্ট্রিং, ইত্যাদি ধরে রাখে।
একেএক্স

@ ক্যাক্স: ধন্যবাদ, আমি এটি দ্বিতীয় উদাহরণে যুক্ত করেছি।
ইন্টারজয়

4
সুতরাং মূলত সাজসজ্জার সর্বদা একটি যুক্তি লাগে যা ফাংশন। তবে সাজসজ্জাটি কোনও ফাংশনের রিটার্ন মান হতে পারে যা তর্ক করতে পারে। এটা কি সঠিক?
বালকি

4
@ বালকি: হ্যাঁ, এটা ঠিক। কী জিনিসগুলিকে বিভ্রান্ত করে তা হ'ল বহু লোক বাইরের ফাংশনটিকে ( myDecoratorএখানে) ডেকরেটারও বলে। এটি সাজসজ্জার ব্যবহারকারীর পক্ষে সুবিধাজনক, তবে আপনি যখন কোনও লেখার চেষ্টা করছেন তখন বিভ্রান্তিকর হতে পারে।
ইন্টারজয়

4
ছোট বিবরণ যা আমাকে বিভ্রান্ত করেছে: যদি আপনি log_decoratorকোনও ডিফল্ট যুক্তি @log_decorator@log_decorator()
নেন

46

কেবল একটি ভিন্ন দৃষ্টিভঙ্গি সরবরাহ করতে: সিনট্যাক্স

@expr
def func(...): #stuff

সমতুল্য

def func(...): #stuff
func = expr(func)

বিশেষত, exprআপনার পছন্দের যে কোনও কিছু হতে পারে, যতক্ষণ না এটি কলযোগ্য হিসাবে মূল্যায়ন করে। ইন বিশেষ বিশেষ করে, exprএকটি প্রসাধক কারখানা হতে পারে: আপনি এটা কিছু প্যারামিটার দিতে এবং এর জন্য আপনাকে প্রসাধক দেয়। সুতরাং আপনার পরিস্থিতি বোঝার আরও ভাল উপায় হ'ল

dec = decorator_factory(*args)
@dec
def func(...):

যা তখন সংক্ষিপ্ত করা যেতে পারে

@decorator_factory(*args)
def func(...):

অবশ্যই, যেহেতু এটি দেখতেdecorator_factory একটি সাজসজ্জা হিসাবে মনে হচ্ছে , লোকেরা এটি প্রতিফলিত করার জন্য এটির নাম রাখে। আপনি যখন ইন্ডিরিয়ারেশন স্তরগুলি অনুসরণ করার চেষ্টা করেন তখন বিভ্রান্তিকর হতে পারে।


ধন্যবাদ, এটি আমাকে যা ঘটছে তার পিছনে যুক্তি বুঝতে সত্যিই সহায়তা করেছে।
আদিত্য শ্রীরাম

25

কেবল কিছু ব্যবহারযোগ্য কৌশল যুক্ত করতে চান যা ডেকোরেটর আর্গুমেন্টগুলি .চ্ছিক করতে দেয়। এটি সাজসজ্জার পুনরায় ব্যবহার এবং বাসা বাঁধতে হ্রাস করার অনুমতি দেয়

import functools

def myDecorator(test_func=None,logIt=None):
    if not test_func:
        return functools.partial(myDecorator, logIt=logIt)
    @functools.wraps(test_func)
    def f(*args, **kwargs):
        if logIt==1:
            print 'Logging level 1 for {}'.format(test_func.__name__)
        if logIt==2:
            print 'Logging level 2 for {}'.format(test_func.__name__)
        return test_func(*args, **kwargs)
    return f

#new decorator 
myDecorator_2 = myDecorator(logIt=2)

@myDecorator(logIt=2)
def pow2(i):
    return i**2

@myDecorator
def pow3(i):
    return i**3

@myDecorator_2
def pow4(i):
    return i**4

print pow2(2)
print pow3(2)
print pow4(2)

16

সাজসজ্জার করার আরও একটি উপায়। আমি এইভাবে আমার মাথাটি চারপাশে মোড়ানো সবচেয়ে সহজ খুঁজে পাই।

class NiceDecorator:
    def __init__(self, param_foo='a', param_bar='b'):
        self.param_foo = param_foo
        self.param_bar = param_bar

    def __call__(self, func):
        def my_logic(*args, **kwargs):
            # whatever logic your decorator is supposed to implement goes in here
            print('pre action baz')
            print(self.param_bar)
            # including the call to the decorated function (if you want to do that)
            result = func(*args, **kwargs)
            print('post action beep')
            return result

        return my_logic

# usage example from here on
@NiceDecorator(param_bar='baaar')
def example():
    print('example yay')


example()

ধন্যবাদ! প্রায় 30 মিনিটের জন্য কিছু মন-নমনকারী "সমাধানগুলি" দেখছেন এবং এটিই প্রথম যা বাস্তবে তা বোঝায়।
ক্যানহ্যাজেটস

0

এখন আপনি যদি function1কোনও সাজসজ্জারের সাথে একটি ফাংশন কল করতে চান decorator_with_argএবং এই ক্ষেত্রে ফাংশন এবং সজ্জা উভয়ই যুক্তি গ্রহণ করে,

def function1(a, b):
    print (a, b)

decorator_with_arg(10)(function1)(1, 2)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.