ক্লাসে পাইথন সাজসজ্জা


140

কেউ কি এমন কিছু লিখতে পারেন:

class Test(object):
    def _decorator(self, foo):
        foo()

    @self._decorator
    def bar(self):
        pass

এটি ব্যর্থ: নিজের মধ্যে থাকা অজানা

আমি চেষ্টাও করেছি:

@Test._decorator(self)

যা ব্যর্থ হয়: পরীক্ষা অজানা

আমি অস্থায়ীভাবে সাজসজ্জারে কিছু উদাহরণ ভেরিয়েবলগুলি পরিবর্তন করতে এবং তারপরে পরিবর্তন করার আগে সজ্জিত পদ্ধতিটি চালাতে চাই।

উত্তর:


268

এর মতো কিছু আপনার প্রয়োজন অনুসারে করবে?

class Test(object):
    def _decorator(foo):
        def magic( self ) :
            print "start magic"
            foo( self )
            print "end magic"
        return magic

    @_decorator
    def bar( self ) :
        print "normal call"

test = Test()

test.bar()

এটি সাজসজ্জারকে অ্যাক্সেস করতে স্ব-কলকে এড়িয়ে চলে এবং এটিকে নিয়মিত পদ্ধতি হিসাবে শ্রেণীর নেমস্পেসে লুকিয়ে রাখে।

>>> import stackoverflow
>>> test = stackoverflow.Test()
>>> test.bar()
start magic
normal call
end magic
>>> 

মন্তব্যে প্রশ্নের উত্তর দিতে সম্পাদিত:

কিভাবে অন্য ক্লাসে লুকানো সাজসজ্জা ব্যবহার করবেন

class Test(object):
    def _decorator(foo):
        def magic( self ) :
            print "start magic"
            foo( self )
            print "end magic"
        return magic

    @_decorator
    def bar( self ) :
        print "normal call"

    _decorator = staticmethod( _decorator )

class TestB( Test ):
    @Test._decorator
    def bar( self ):
        print "override bar in"
        super( TestB, self ).bar()
        print "override bar out"

print "Normal:"
test = Test()
test.bar()
print

print "Inherited:"
b = TestB()
b.bar()
print

আউটপুট:

Normal:
start magic
normal call
end magic

Inherited:
start magic
override bar in
start magic
normal call
end magic
override bar out
end magic

7
সাজসজ্জার বা সাজানো কাজ? প্রত্যাবর্তিত "যাদু" ফাংশনটি নোট করে যে বারটি যখন একটি দৃষ্টান্তের জন্য "বার" ডাকা হয় তখন উপরের একটি স্ব ভেরিয়েবল গ্রহণ করে এবং এর আগে এবং পরে যে উদাহরণটি ভেরিয়েবলগুলি চেয়েছিল তার কিছু করতে পারে (বা এমনকি এটি "বার" বলা হয়) । শ্রেণি ঘোষণার সময় উদাহরণ ভেরিয়েবলের মতো জিনিস নেই। আপনি কি সাজসজ্জার মধ্য থেকে ক্লাসে কিছু করতে চান? আমি মনে করি না যে এটি একটি মূ .় ব্যবহার।
মাইকেল স্পিকার 14 ই

1
ধন্যবাদ মাইকেল, কেবল এখন দেখলাম যে এটিই আমি চেয়েছিলাম।
hcvst

2
আমি এই সমাধানটি গৃহীত উত্তরের চেয়ে অনেক সুন্দর দেখতে পেয়েছি কারণ এটি সংজ্ঞায়নের স্থানে @ সজ্জা সিনট্যাক্স ব্যবহারের অনুমতি দেয়। যদি আমাকে ক্লাস শেষে ডেকরেটার কল দিতে হয়, তবে এটি পরিষ্কার নয় যে ফাংশনগুলি সজ্জিত হচ্ছে। এটি কিছুটা অদ্ভুত যে আপনি ডেকরেটার নিজেই @ স্ট্যাটিকমেডথ ব্যবহার করতে পারবেন না, তবে কমপক্ষে এটি কার্যকর।
mgiuca

1
আমি মনে করি না যে আমি যদি টেস্টের উত্তরাধিকারসূত্রে ক্লাস তৈরি করি তবে এটি কাজ করে example উদাহরণস্বরূপ: ক্লাস টেস্টবি (টেস্ট): @_decorator Def foobar (স্ব): মুদ্রণ "adf" আছে কি কোনও কার্যকারিতা আছে?
অতিরিক্তি

1
@ এক্সট্রাই: আমি যে সম্পাদনা করেছি তা পরীক্ষা করে দেখুন। আপনাকে প্রদত্ত ডিকোরিটারকে স্ট্যাটিকমেডোথ হিসাবে যোগ্যতা অর্জন করতে হবে তবে আপনি এটি ব্যবহারের পরে (বা স্ট্যাটিকমেডোথ ভার্সনটি অন্য কোনও নামে অর্পণ করার পরে)
মাইকেল স্পিকার

58

আপনি যা করতে চাইছেন তা সম্ভব নয়। উদাহরণস্বরূপ, নীচের কোডটি বৈধ বলে মনে হচ্ছে কিনা তা নিন:

class Test(object):

    def _decorator(self, foo):
        foo()

    def bar(self):
        pass
    bar = self._decorator(bar)

এটি অবশ্যই বৈধ নয় যেহেতু selfসেই সময়ে সংজ্ঞায়িত হয়নি। Testক্লাস নিজেই সংজ্ঞায়িত না হওয়া পর্যন্ত এটি সংজ্ঞায়িত হবে না (যা এটি প্রক্রিয়াধীন) for আমি আপনাকে এই কোড স্নিপেট দেখাচ্ছে কারণ এটিই আপনার ডেকোরেটর স্নিপেট রূপান্তরিত করে।

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

আপনার যদি শ্রেণি-স্তরের অ্যাক্সেসের প্রয়োজন হয় তবে এটি ব্যবহার করে দেখুন:

class Test(object):

    @classmethod
    def _decorator(cls, foo):
        foo()

    def bar(self):
        pass
Test.bar = Test._decorator(Test.bar)

5
নীচের আরও সঠিক উত্তরের জন্য সম্ভবত সম্ভবত আপডেট করা উচিত
নাথান বুয়েজেনস

1
খুশী হলাম। আপনার গদ্যটি অসম্ভব বলেছে, তবে কীভাবে এটি করা যায় তা আপনার কোডটি দেখায়।
ম্যাড পদার্থবিদ

22
import functools


class Example:

    def wrapper(func):
        @functools.wraps(func)
        def wrap(self, *args, **kwargs):
            print("inside wrap")
            return func(self, *args, **kwargs)
        return wrap

    @wrapper
    def method(self):
        print("METHOD")

    wrapper = staticmethod(wrapper)


e = Example()
e.method()

1
প্রকারের ত্রুটি: 'স্ট্যাটিকমথডো' অবজেক্টটি কলযোগ্য নয়
wyx

@ উইক্স শোভাকরকে কল করবেন না। উদাহরণস্বরূপ, এটি হওয়া উচিত @foo, না@foo()
ডকোয়দা

প্রথম যুক্তি হওয়া wrapperউচিত নয় self?
1:25

7

আমি কিছু ডিবাগিং পরিস্থিতিতে এই ধরণের ডেকরেটার ব্যবহার করি, এটি কলিং ফাংশনটি সন্ধান না করে সজ্জিত করে শ্রেণীর বৈশিষ্ট্যগুলিকে ওভাররাইড করার অনুমতি দেয়।

class myclass(object):
    def __init__(self):
        self.property = "HELLO"

    @adecorator(property="GOODBYE")
    def method(self):
        print self.property

এখানে সাজসজ্জারের কোড

class adecorator (object):
    def __init__ (self, *args, **kwargs):
        # store arguments passed to the decorator
        self.args = args
        self.kwargs = kwargs

    def __call__(self, func):
        def newf(*args, **kwargs):

            #the 'self' for a method function is passed as args[0]
            slf = args[0]

            # replace and store the attributes
            saved = {}
            for k,v in self.kwargs.items():
                if hasattr(slf, k):
                    saved[k] = getattr(slf,k)
                    setattr(slf, k, v)

            # call the method
            ret = func(*args, **kwargs)

            #put things back
            for k,v in saved.items():
                setattr(slf, k, v)

            return ret
        newf.__doc__ = func.__doc__
        return newf 

দ্রষ্টব্য: যেহেতু আমি একটি শ্রেনী সাজসজ্জা ব্যবহার করেছি আপনার ফাংশনগুলি সাজাতে ব্র্যাকের সাথে @ অ্যাডিকোরেটর () ব্যবহার করতে হবে , এমনকি যদি আপনি সাজসজ্জা বর্গ নির্মাণকারীকে কোনও যুক্তি না দিয়ে থাকেন don't


7

এটি একই শ্রেণীর অভ্যন্তরে সংজ্ঞায়িত হওয়া selfথেকে অ্যাক্সেসের এক উপায় (এবং ব্যবহৃত হয়েছে) decorator:

class Thing(object):
    def __init__(self, name):
        self.name = name

    def debug_name(function):
        def debug_wrapper(*args):
            self = args[0]
            print 'self.name = ' + self.name
            print 'running function {}()'.format(function.__name__)
            function(*args)
            print 'self.name = ' + self.name
        return debug_wrapper

    @debug_name
    def set_name(self, new_name):
        self.name = new_name

আউটপুট (পরীক্ষিত Python 2.7.10):

>>> a = Thing('A')
>>> a.name
'A'
>>> a.set_name('B')
self.name = A
running function set_name()
self.name = B
>>> a.name
'B'

উপরের উদাহরণটি নির্বোধ, তবে এটি কার্যকর।


4

খুব অনুরূপ সমস্যা নিয়ে গবেষণা করার সময় আমি এই প্রশ্নটি পেয়েছি। আমার সমাধানটি সমস্যাটিকে দুটি ভাগে ভাগ করা। প্রথমত, আপনার ক্লাস পদ্ধতিগুলির সাথে সংযুক্ত করতে চান এমন ডেটা ক্যাপচার করতে হবে। এই ক্ষেত্রে, handler_for সেই কমান্ডের আউটপুটটির জন্য হ্যান্ডলারের সাথে একটি ইউনিক্স কমান্ড সংযুক্ত করবে।

class OutputAnalysis(object):
    "analyze the output of diagnostic commands"
    def handler_for(name):
        "decorator to associate a function with a command"
        def wrapper(func):
            func.handler_for = name
            return func
        return wrapper
    # associate mount_p with 'mount_-p.txt'
    @handler_for('mount -p')
    def mount_p(self, slurped):
        pass

এখন যেহেতু আমরা প্রতিটি শ্রেণি পদ্ধতির সাথে কিছু ডেটা যুক্ত করেছি, আমাদের সেই ডেটা সংগ্রহ করতে হবে এবং এটি একটি শ্রেণির বৈশিষ্ট্যে সংরক্ষণ করতে হবে।

OutputAnalysis.cmd_handler = {}
for value in OutputAnalysis.__dict__.itervalues():
    try:
        OutputAnalysis.cmd_handler[value.handler_for] = value
    except AttributeError:
        pass

4

মাইকেল স্পিকারের উত্তরটি আরও কয়েক ধাপ এগিয়ে নিয়ে যাওয়ার জন্য এখানে একটি সম্প্রসারণ রয়েছে:

একটি উদাহরণ পদ্ধতি সাজসজ্জা যা তর্ক করে এবং আর্গুমেন্ট এবং একটি রিটার্ন মান সহ একটি ফাংশনে কাজ করে।

class Test(object):
    "Prints if x == y. Throws an error otherwise."
    def __init__(self, x):
        self.x = x

    def _outer_decorator(y):
        def _decorator(foo):
            def magic(self, *args, **kwargs) :
                print("start magic")
                if self.x == y:
                    return foo(self, *args, **kwargs)
                else:
                    raise ValueError("x ({}) != y ({})".format(self.x, y))
                print("end magic")
            return magic

        return _decorator

    @_outer_decorator(y=3)
    def bar(self, *args, **kwargs) :
        print("normal call")
        print("args: {}".format(args))
        print("kwargs: {}".format(kwargs))

        return 27

এবং তারপর

In [2]:

    test = Test(3)
    test.bar(
        13,
        'Test',
        q=9,
        lollipop=[1,2,3]
    )
    
    start magic
    normal call
    args: (13, 'Test')
    kwargs: {'q': 9, 'lollipop': [1, 2, 3]}
Out[2]:
    27
In [3]:

    test = Test(4)
    test.bar(
        13,
        'Test',
        q=9,
        lollipop=[1,2,3]
    )
    
    start magic
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-3-576146b3d37e> in <module>()
          4     'Test',
          5     q=9,
    ----> 6     lollipop=[1,2,3]
          7 )

    <ipython-input-1-428f22ac6c9b> in magic(self, *args, **kwargs)
         11                     return foo(self, *args, **kwargs)
         12                 else:
    ---> 13                     raise ValueError("x ({}) != y ({})".format(self.x, y))
         14                 print("end magic")
         15             return magic

    ValueError: x (4) != y (3)

3

সাজসজ্জাবিদরা কোনও সামগ্রীর কার্যকারিতা বনাম কোনও সামগ্রীর (ফাংশন অবজেক্ট সহ) কার্যকারিতা সংশোধন করতে আরও উপযুক্ত বলে মনে করেন যা সাধারণভাবে উদাহরণ বৈশিষ্ট্যের উপর নির্ভর করবে। উদাহরণ স্বরূপ:

def mod_bar(cls):
    # returns modified class

    def decorate(fcn):
        # returns decorated function

        def new_fcn(self):
            print self.start_str
            print fcn(self)
            print self.end_str

        return new_fcn

    cls.bar = decorate(cls.bar)
    return cls

@mod_bar
class Test(object):
    def __init__(self):
        self.start_str = "starting dec"
        self.end_str = "ending dec" 

    def bar(self):
        return "bar"

আউটপুটটি হ'ল:

>>> import Test
>>> a = Test()
>>> a.bar()
starting dec
bar
ending dec

1

আপনি সাজসজ্জা সাজাইয়া করতে পারেন:

import decorator

class Test(object):
    @decorator.decorator
    def _decorator(foo, self):
        foo(self)

    @_decorator
    def bar(self):
        pass

1

আমার ডেকোরেটরগুলির একটি বাস্তবায়ন রয়েছে যা সাহায্য করতে পারে

    import functools
    import datetime


    class Decorator(object):

        def __init__(self):
            pass


        def execution_time(func):

            @functools.wraps(func)
            def wrap(self, *args, **kwargs):

                """ Wrapper Function """

                start = datetime.datetime.now()
                Tem = func(self, *args, **kwargs)
                end = datetime.datetime.now()
                print("Exection Time:{}".format(end-start))
                return Tem

            return wrap


    class Test(Decorator):

        def __init__(self):
            self._MethodName = Test.funca.__name__

        @Decorator.execution_time
        def funca(self):
            print("Running Function : {}".format(self._MethodName))
            return True


    if __name__ == "__main__":
        obj = Test()
        data = obj.funca()
        print(data)

1

ইনার ক্লাসে ঘোষণা করুন। এই সমাধানটি বেশ শক্ত এবং প্রস্তাবিত।

class Test(object):
    class Decorators(object):
    @staticmethod
    def decorator(foo):
        def magic(self, *args, **kwargs) :
            print("start magic")
            foo(self, *args, **kwargs)
            print("end magic")
        return magic

    @Decorators.decorator
    def bar( self ) :
        print("normal call")

test = Test()

test.bar()

ফলাফল:

>>> test = Test()
>>> test.bar()
start magic
normal call
end magic
>>> 
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.