পাইথন: একটি আনবাউন্ড পদ্ধতি বাঁধবেন?


117

পাইথনে, আনবাউন্ড পদ্ধতিটি না বলে বাঁধা দেওয়ার কোনও উপায় আছে কি?

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

class MyWidget(wx.Window):
    buttons = [("OK", OnOK),
               ("Cancel", OnCancel)]

    # ...

    def Setup(self):
        for text, handler in MyWidget.buttons:

            # This following line is the problem line.
            b = wx.Button(parent, label=text).Bind(wx.EVT_BUTTON, handler)

সমস্যাটি হ'ল যেহেতু এর মানগুলি সমস্ত handlerআনবাউন্ড পদ্ধতিগুলি, তাই আমার প্রোগ্রামটি দর্শনীয় জ্বলজ্বলে বিস্ফোরিত হয় এবং আমি কাঁদে।

তুলনামূলক সরল, সমাধানযোগ্য সমস্যা হওয়া উচিত বলে মনে হচ্ছে এমন একটি সমাধানের জন্য আমি অনলাইনে ঘুরে দেখছিলাম। দুর্ভাগ্যক্রমে আমি কিছুই পাইনি। এই মুহুর্তে, আমি functools.partialএটিকে ঘিরে কাজ করছি , তবে কেউ কি জানেন যে কোনও পরিষ্কার-অনুভূতি, স্বাস্থ্যকর, পাইথোনিক উপায় আছে যাতে কোনও উদাহরণস্বরূপ একটি আনবাউন্ড পদ্ধতি আবদ্ধ করে এবং এটি কল না করেই এটি অতিক্রম করে চলেছে?


6
@ ক্রিস্টোফার - এমন একটি পদ্ধতি যা এটিকে চুষিয়ে নেওয়া বস্তুর ক্ষেত্রের সাথে আবদ্ধ নয়, সুতরাং আপনাকে স্বতঃস্ফূর্তভাবে স্বতন্ত্রভাবে পাস করতে হবে।
আইডেন বেল

2
আমি বিশেষত "দর্শনীয় জ্বলজ্বল পছন্দ করি এবং আমি কাঁদি"।
jspencer

উত্তর:


174

সমস্ত ফাংশনগুলিও বর্ণনাকারী , যাতে আপনি তাদের __get__পদ্ধতিতে কল করে তাদের বেঁধে রাখতে পারেন :

bound_handler = handler.__get__(self, MyWidget)

বর্ণনাকারীদের জন্য এখানে আর। হেটিংজারের দুর্দান্ত গাইড


কীথের মন্তব্য থেকে স্ব-নিখুঁত উদাহরণ টানা :

def bind(instance, func, as_name=None):
    """
    Bind the function *func* to *instance*, with either provided name *as_name*
    or the existing name of *func*. The provided *func* should accept the 
    instance as the first argument, i.e. "self".
    """
    if as_name is None:
        as_name = func.__name__
    bound_method = func.__get__(instance, instance.__class__)
    setattr(instance, as_name, bound_method)
    return bound_method

class Thing:
    def __init__(self, val):
        self.val = val

something = Thing(21)

def double(self):
    return 2 * self.val

bind(something, double)
something.double()  # returns 42

3
যে বেশ শান্ত. আমি পছন্দ করি আপনি কীভাবে প্রকারটি বাদ দিতে পারেন এবং পরিবর্তে একটি "আবদ্ধ পদ্ধতি? .F" পেতে পারেন।
কিভ

আমি এই সমাধানটি MethodTypeএকটির চেয়ে পছন্দ করি কারণ এটি পাই 3 কে তে একই কাজ করে, যখন MethodTypeযুক্তিগুলি কিছুটা বদলে গেছে।
বিজিডব্লিউ

10
এবং এইভাবে, শ্রেণীর দৃষ্টান্তগুলিতে ফাংশনকে আবদ্ধ করার জন্য একটি ফাংশন: bind = lambda instance, func, asname: setattr(instance, asname, func.__get__(instance, instance.__class__))উদাহরণ:class A: pass; a = A(); bind(a, bind, 'bind')
কেথ পিনসন

2
হু, আপনি প্রতিদিন কিছু নতুন শিখেন। @ কাজার্ক পাইথন 3-তে অন্ততপক্ষে, আপনি এই ধরণের সরবরাহ সরবরাহও এড়িয়ে যেতে পারেন, যেহেতু __get__এটি বস্তুর প্যারামিটার থেকে স্পষ্টভাবে নেওয়া হবে take আমি সরবরাহ করি তবে এটি সরবরাহ করে কি না তা আমি নিশ্চিত নই, কারণ প্রথম প্যারামিটারের উদাহরণটি নির্বিশেষে দ্বিতীয় প্যারামিটার হিসাবে আমি কী ধরণের সরবরাহ করি তাতে কোন পার্থক্য হয় না। সুতরাং bind = lambda instance, func, asname=None: setattr(instance, asname or func.__name__, func.__get__(instance))কৌতুক পাশাপাশি করা উচিত। (যদিও আমি bindব্যক্তিগতভাবে সজ্জা হিসাবে ব্যবহারের যোগ্য হওয়া পছন্দ করতাম তবে এটি আলাদা বিষয়))
জ্যাব

1
বাহ, ফাংশন বর্ণনাকারী ছিল জানেন না। এটি একটি খুব মার্জিত নকশা, পদ্ধতিগুলি ক্লাসে কেবল সরল কাজ ' __dict__এবং বৈশিষ্ট্য অ্যাক্সেস আপনাকে সাধারণ বিবরণকারী প্রোটোকলের মাধ্যমে আনবাউন্ড বা আবদ্ধ পদ্ধতি দেয় methods আমি সর্বদা ধরে type.__new__()
নিয়েছিলাম

81

এটি ধরণের সাথে পরিষ্কারভাবে করা যায় .মেথডটাইপ । উদাহরণ:

import types

def f(self): print self

class C(object): pass

meth = types.MethodType(f, C(), C) # Bind f to an instance of C
print meth # prints <bound method C.f of <__main__.C object at 0x01255E90>>

10
+1 এটি দুর্দান্ত, তবে আপনার সরবরাহ করা URL টিতে পাইথন ডক্সে এর কোনও রেফারেন্স নেই।
কাইল ওয়াইল্ড

6
+1, আমি আমার কোডটিতে যাদু ফাংশনে কল না করা পছন্দ করি (অর্থাত __get__)। অজগরটির কোন সংস্করণের জন্য আপনি এটি পরীক্ষা করেছেন তা আমি জানি না তবে পাইথন ৩.৪-তে MethodTypeফাংশনটি দুটি আর্গুমেন্ট গ্রহণ করে। ফাংশন এবং উদাহরণ। সুতরাং এটিতে পরিবর্তন করা উচিত types.MethodType(f, C())
ড্যান মিলন

এটা এখানে! উদাহরণ wgt.flush = types.MethodType(lambda self: None, wgt)
প্যাচগুলি

2
এটি প্রকৃতপক্ষে ডক্সগুলিতে উল্লিখিত হয়েছে, তবে অন্য উত্তর থেকে বর্ণনাকারী পৃষ্ঠায়: ডকস.পিথথন.আর
কাই

9

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

self.method = (lambda self: lambda args: self.do(args))(self)

1
হ্যাঁ, এটি আমার আসল functools.partial(handler, self)
ফিক্সের

7

এই বাঁধবে selfকরতে handler:

bound_handler = lambda *args, **kwargs: handler(self, *args, **kwargs)

এটি selfফাংশনের প্রথম যুক্তি হিসাবে পাস করে কাজ করে। object.function()এর জন্য কেবল সিনট্যাকটিক চিনি function(object)


1
হ্যাঁ, তবে এটি পদ্ধতিটিকে কল করে। সমস্যাটি হ'ল আমাকে কলযোগ্য বস্তু হিসাবে সীমাবদ্ধ পদ্ধতিটি পাস করতে সক্ষম হতে হবে। আমার আনবাউন্ড পদ্ধতি এবং উদাহরণটি আমি এটির সাথে আবদ্ধ হতে চাই, তবে তা অবিলম্বে কল না করে কীভাবে
সমস্তকে

9
না এটি হয় না, আপনি কেবল বাউন্ডহ্যান্ডলার () করলে এটি পদ্ধতিটি কল করবে। ল্যাম্বডাকে সংজ্ঞায়িত করা ল্যাম্বডাকে ডাকে না।
ব্রায়ান-ব্রাজিল

1
আপনি আসলে functools.partialল্যাম্বডা সংজ্ঞায়নের পরিবর্তে ব্যবহার করতে পারেন । যদিও এটি সঠিক সমস্যাটি সমাধান করে না। আপনি এখনও একটি এর functionপরিবর্তে ডিল করছেন instancemethod
অ্যালান বরই

5
@ অ্যালান: functionযার প্রথম যুক্তিতে আপনি আংশিক-এড এবং এর মধ্যে পার্থক্য কী instancemethod; হাঁসের টাইপিং পার্থক্য দেখতে পারে না।
মিথ্যা রায়ান

2
@ লাইরিয়ান পার্থক্যটি হ'ল আপনি এখনও মৌলিক ধরণের সাথে আচরণ করছেন না। functools.partialকিছু মেটাডেটা ফেলে দেয়, যেমন __module__। (এছাড়াও আমি এই জবাবটি সম্পর্কে আমার প্রথম মন্তব্যটি যখন দেখি তখনই আমি সত্যই শক্তভাবে চূড়ান্তভাবে রেকর্ড করতে চাই)) আমার প্রশ্নে আমি উল্লেখ করেছি যে আমি ইতিমধ্যে ব্যবহার করছি functools.partialতবে আমার মনে হয়েছিল যে "বিশুদ্ধ" উপায় থাকতে হবে, যেহেতু এটি আনবাউন্ড এবং সীমাবদ্ধ উভয় পদ্ধতিই পাওয়া সহজ।
ড্যান পাসারো

1

পার্টিতে দেরীতে, তবে আমি এখানে একটি অনুরূপ প্রশ্ন নিয়ে এসেছি: আমার একটি ক্লাস পদ্ধতি এবং একটি উদাহরণ রয়েছে এবং আমি সেই পদ্ধতিটিতে উদাহরণটি প্রয়োগ করতে চাই।

ওপি-র প্রশ্নের উদ্বোধনের ঝুঁকিতে, আমি এখানে কিছু অল্প রহস্যজনক কাজ করেছিলাম যা এখানে পৌঁছে যাওয়া অন্যদের পক্ষে উপযোগী হতে পারে (সতর্কতা: আমি পাইথন 3 - ওয়াইএমএমভিতে কাজ করছি)।

এই সাধারণ শ্রেণি বিবেচনা করুন:

class Foo(object):

    def __init__(self, value):
        self._value = value

    def value(self):
        return self._value

    def set_value(self, value):
        self._value = value

আপনি এটি দিয়ে কী করতে পারেন তা এখানে:

>>> meth = Foo.set_value   # the method
>>> a = Foo(12)            # a is an instance with value 12
>>> meth(a, 33)            # apply instance and method
>>> a.value()              # voila - the method was called
33

এটি আমার সমস্যাটির সমাধান করে না - যা হ'ল আমি methযুক্তিটি না পাঠিয়ে চালিয়ে যেতে চেয়েছিলাম a(যার কারণেই আমি প্রথমে ব্যবহার করেছি functools.partial) - তবে আপনি যদি পদ্ধতিটি পাস করার প্রয়োজন না হন এবং এটি করতে পারেন তবে এটি পছন্দনীয় স্পট এ এটি প্রার্থনা। পাইথন 3-তে এটি পাইথন 2-
তেও

আপনার মূল প্রয়োজনীয়তা আরও যত্ন সহকারে না পড়ার জন্য ক্ষমা চাই। @ ব্রায়ান-ব্রাজিল স্ট্যাকওভারফ্লো . com / a / 1015355 / 558639 এ দেওয়া ল্যাম্বডা ভিত্তিক পদ্ধতির আমি আংশিক (শঙ্কিত উদ্দেশ্যে) - এটি যতটা খাঁটি তা আপনি পেতে পারেন about
নির্ভীক_ফুল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.