ক্লাস বডির মধ্যে ক্লাস স্ট্যাটিকমেডথ বলে?


159

আমি যখন ক্লাসের বডি থেকে কোনও স্ট্যাটিক পদ্ধতি ব্যবহার করার চেষ্টা করি, এবং বিল্ট-ইন staticmethodফাংশনটি ডেকরেটর হিসাবে ব্যবহার করে স্থির পদ্ধতিটি সংজ্ঞায়িত করি :

class Klass(object):

    @staticmethod  # use as decorator
    def _stat_func():
        return 42

    _ANS = _stat_func()  # call the staticmethod

    def method(self):
        ret = Klass._stat_func() + Klass._ANS
        return ret

আমি নিম্নলিখিত ত্রুটি পেয়েছি:

Traceback (most recent call last):<br>
  File "call_staticmethod.py", line 1, in <module>
    class Klass(object): 
  File "call_staticmethod.py", line 7, in Klass
    _ANS = _stat_func() 
  TypeError: 'staticmethod' object is not callable

আমি বুঝতে পারি যে এটি কেন ঘটছে (বর্ণনাকারী বাঁধাই) , এবং _stat_func()এর সর্বশেষ ব্যবহারের পরে ম্যানুয়ালি একটি স্ট্যাটিকমেথডে রূপান্তর করে এটির মতো কাজ করতে পারে:

class Klass(object):

    def _stat_func():
        return 42

    _ANS = _stat_func()  # use the non-staticmethod version

    _stat_func = staticmethod(_stat_func)  # convert function to a static method

    def method(self):
        ret = Klass._stat_func() + Klass._ANS
        return ret

সুতরাং আমার প্রশ্নটি হ'ল:

ক্লিনার বা আরও বেশি "পাইথোনিক" এর মতো আরও ভাল, এটি সম্পন্ন করার উপায়গুলি কি?


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

1
@ পারসোড: হ্যাঁ, আমি সেই বিকল্প সম্পর্কে সচেতন। তবে প্রকৃত কোডে যেখানে আমি এই সমস্যার মুখোমুখি হয়েছি, সেখানে ফাংশনটিকে মডিউল-স্তরে রাখার চেয়ে স্থিতিশীল পদ্ধতি হিসাবে তৈরি করা আমার প্রশ্নের ক্ষেত্রে ব্যবহৃত সাধারণ উদাহরণের চেয়ে বেশি বোঝায়।
মার্টিনো

উত্তর:


179

staticmethodবস্তুগুলিতে স্পষ্টতই __func__মূল কাঁচা ফাংশন সংরক্ষণ করে একটি বৈশিষ্ট্য রয়েছে (তাদের বোঝায় যে বোঝা যায়)। সুতরাং এটি কাজ করবে:

class Klass(object):

    @staticmethod  # use as decorator
    def stat_func():
        return 42

    _ANS = stat_func.__func__()  # call the staticmethod

    def method(self):
        ret = Klass.stat_func()
        return ret

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

>>> class Foo(object):
...     @staticmethod
...     def foo():
...         return 3
...     global z
...     z = foo

>>> z
<staticmethod object at 0x0000000002E40558>
>>> Foo.foo
<function foo at 0x0000000002E3CBA8>
>>> dir(z)
['__class__', '__delattr__', '__doc__', '__format__', '__func__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
>>> z.__func__
<function foo at 0x0000000002E3CBA8>

একটি ইন্টারেক্টিভ সেশনে অনুরূপ ধরণের খনন ( dirখুব সহায়ক) প্রায়ই এই ধরণের প্রশ্নটি খুব দ্রুত সমাধান করতে পারে।


ভাল আপডেট ... আমি ডকুমেন্টেশনে এটি দেখতে না পাওয়ায় আপনি এটি কীভাবে জানলেন তা জিজ্ঞাসা করতেই এসেছি - যা এটি ব্যবহার সম্পর্কে আমাকে একটু ঘাবড়ে যায় কারণ এটি "বাস্তবায়ন বিশদ" হতে পারে।
মার্টিনো

আরও পড়ার পরে আমি দেখতে পাচ্ছি যে এটির __func__অন্য একটি নাম im_funcএবং পাইথন 3 ফরোয়ার্ডস-সামঞ্জস্যের জন্য পাই 2.6 এ যুক্ত করা হয়েছিল।
মার্টিনো

2
আমি দেখতে পাচ্ছি, প্রযুক্তিগতভাবে এটি এই প্রসঙ্গে নিঃসংশ্লিষ্ট।
মার্টিনো

1
@ অক্ষয়হাজারী __func__একটি স্থির পদ্ধতির বৈশিষ্ট্যটি আপনাকে মূল ফাংশনটির জন্য একটি রেফারেন্স দেয়, ঠিক যেমন আপনি কখনও staticmethodসজ্জা ব্যবহার করেন নি । সুতরাং যদি আপনার ফাংশনে যুক্তিগুলির প্রয়োজন হয়, কল করার সময় আপনাকে সেগুলি পাস করতে হবে __func__। ত্রুটি বার্তাটি আপনাকে বেশ মনে হচ্ছে আপনি এটিকে কোনও আর্গুমেন্ট দিয়েছেন নি। যদি stat_funcএই পোস্টের উদাহরণটিতে দুটি যুক্তি গ্রহণ করা হয় তবে আপনি ব্যবহার করতে পারেন_ANS = stat_func.__func__(arg1, arg2)
বেন

1
@ অক্ষয়হাজারী আমি নিশ্চিত বুঝতে পারছি না। এগুলি ভেরিয়েবল হতে পারে, তাদের কেবল ইন-স্কোপ ভেরিয়েবল হতে হবে: হয় একই স্কোপে যেখানে আগে ক্লাস সংজ্ঞায়িত হয় (প্রায়শই গ্লোবাল), বা ক্লাস স্কোপের মধ্যে আগে সংজ্ঞায়িত হয় ( stat_funcনিজেই এ জাতীয় একটি ভেরিয়েবল)। আপনি কি বোঝাতে চেয়েছেন যে আপনি যে শ্রেণীর সংজ্ঞা দিচ্ছেন তার উদাহরণ বৈশিষ্ট্য আপনি ব্যবহার করতে পারবেন না? এটি সত্য, তবে অবাক করা কিছু নয়; আমরা না আছে যেহেতু আমরা এখনও শ্রেণী সংজ্ঞায়িত করছি, ক্লাসের একটা নিদর্শন! তবে যাইহোক, আমি তাদের বোঝাতে চাইছি আপনি যে কোনও যুক্তিই পাস করতে চেয়েছিলেন; আপনি সেখানে আক্ষরিক ব্যবহার করতে পারেন।
বেন

24

এই উপায়টি আমি পছন্দ করি:

class Klass(object):

    @staticmethod
    def stat_func():
        return 42

    _ANS = stat_func.__func__()

    def method(self):
        return self.__class__.stat_func() + self.__class__._ANS

আমি DRY নীতিরKlass.stat_func কারণে এই সমাধানটি পছন্দ করি । পাইথন 3 এ নতুন কেন আছে তার কারণটি আমাকে মনে করিয়ে দেয় :)super()

তবে আমি অন্যদের সাথে একমত, সাধারণত মডিউল স্তরের ফাংশনটি সংজ্ঞায়িত করা সবচেয়ে ভাল পছন্দ।

উদাহরণস্বরূপ @staticmethodফাংশন সহ, পুনরাবৃত্তি খুব ভাল দেখাচ্ছে না (আপনার Klass.stat_funcভিতরে কল করে DRY নীতিটি ভঙ্গ করতে হবে Klass.stat_func)। কারণ আপনার selfস্থির পদ্ধতির অভ্যন্তর কোনও রেফারেন্স নেই । মডিউল স্তরের ফাংশন সহ, সবকিছু ঠিক থাকবে will


যদিও আমি একমত যে self.__class__.stat_func()নিয়মিত পদ্ধতিতে ব্যবহারের সুবিধাগুলি (ডিআরওয়াই এবং এগুলি সমস্ত) ব্যবহারের পরেও Klass.stat_func()আসলে এটি আমার প্রশ্নের বিষয় ছিল না - আসলে আমি অসামঞ্জস্যতার বিষয়টি মেঘলা না করার জন্য প্রাক্তনটিকে ব্যবহার করা এড়িয়ে গেছি।
মার্টিনো

1
এটি সত্যিকার অর্থে DRY এর কোনও সমস্যা নয়। self.__class__ভাল কারণ একটি উপশ্রেণী ওভাররাইড হয় stat_func, তারপর Subclass.methodউপশ্রেণী এর ডাকব stat_func। তবে পুরোপুরি সত্যি বলতে, এই পরিস্থিতিতে স্থিতাবস্থার পরিবর্তে একটি আসল পদ্ধতি ব্যবহার করা আরও ভাল।
asmeurer

@ এসম্যুরার: আমি আসল পদ্ধতিটি ব্যবহার করতে পারি না কারণ ক্লাসের কোনও উদাহরণ এখনও তৈরি হয়নি — কারণ এটি ক্লাস নিজেই এখনও সম্পূর্ণরূপে সংজ্ঞায়িত হয়নি।
মার্টিনো

আমি আমার ক্লাসের জন্য স্থিতিশীল পদ্ধতিটি কল করার একটি উপায় চেয়েছিলাম (যা উত্তরাধিকার সূত্রে প্রাপ্ত; তাই পিতামাতার আসলে কার্যকারিতা রয়েছে) এবং এটি এখন পর্যন্ত সেরা বলে মনে হচ্ছে (এবং পরে আমি ওভাররাইড করলেও এটি কাজ করবে)।
whitey04

11

শ্রেণীর সংজ্ঞার পরে শ্রেণীর বৈশিষ্ট্য ইনজেকশন সম্পর্কে কী?

class Klass(object):

    @staticmethod  # use as decorator
    def stat_func():
        return 42

    def method(self):
        ret = Klass.stat_func()
        return ret

Klass._ANS = Klass.stat_func()  # inject the class attribute with static method value

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

11

এটি স্ট্যাটিসমেডোথ বর্ণনাকারী হওয়ার কারণে এবং এর জন্য বর্ণনাকারী প্রোটোকলটি অনুশীলন করতে এবং প্রকৃত কলযোগ্য পেতে একটি শ্রেণি-স্তরের অ্যাট্রিবিউট আনতে হবে।

উত্স কোড থেকে:

এটি ক্লাসে (যেমন C.f()) বা কোনও উদাহরণে (যেমন C().f()) বলা যেতে পারে ; উদাহরণটি এর শ্রেণি ব্যতীত উপেক্ষা করা হবে।

এটি সংজ্ঞায়িত করার সময় ক্লাসের ভিতরে থেকে সরাসরি নয়।

তবে একজন মন্তব্যকারী যেমন উল্লেখ করেছেন, এটি আসলে কোনও "পাইথোনিক" নকশা নয়। পরিবর্তে কেবল একটি মডিউল স্তরের ফাংশন ব্যবহার করুন।


আমি আমার প্রশ্নে যেমন বলেছি, আমি বুঝতে পারি যে মূল কোডটি কেন কাজ করে না। আপনি কী ব্যাখ্যা করতে পারেন (বা এমন কোনও লিঙ্ক সরবরাহ করতে পারে যা এটি অযৌক্তিক বলে বিবেচিত হয়?
মার্টিনো

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

কোন সংস্করণ (বা উভয়) এর ছাপ? এবং কেন, বিশেষভাবে?
মার্টিনো

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

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

8

এই সমাধান সম্পর্কে কি? এটি @staticmethodসাজসজ্জার বাস্তবায়নের জ্ঞানের উপর নির্ভর করে না । ইনার ক্লাস স্ট্যাটিকমেথড স্ট্যাটিক ইনিশিয়ালেশন ফাংশনগুলির ধারক হিসাবে খেলে।

class Klass(object):

    class StaticMethod:
        @staticmethod  # use as decorator
        def _stat_func():
            return 42

    _ANS = StaticMethod._stat_func()  # call the staticmethod

    def method(self):
        ret = self.StaticMethod._stat_func() + Klass._ANS
        return ret

2
সৃজনশীলতার জন্য +1, তবে আমি ব্যবহারের জন্য আর চিন্তিত নই __func__কারণ এটি এখন আনুষ্ঠানিকভাবে নথিভুক্ত হয়েছে ( পাইথন ২.7-এ নতুন কী কী আছে তার অন্যান্য ভাষা পরিবর্তনগুলি এবং ইস্যুতে Iss৯৮২ এর রেফারেন্স দেখুন )। আপনার সমাধানটি আরও বেশি বহনযোগ্য, কারণ এটি সম্ভবত ২. 2.-এর আগে পাইথন সংস্করণেও কাজ করবে (যখন __func__এটি প্রথমে প্রতিশব্দ হিসাবে প্রথম পরিচয় হয়েছিল im_func)।
মার্টিনো

এটিই একমাত্র সমাধান যা পাইথন ২.6 এর সাথে কাজ করে।
বেনসেলমে

@ বেনসেলমে: আমি আপনার দাবিটি যাচাই করতে পারছি না কারণ আমার কাছে পাইথন ২.6 ইনস্টল করা হয়নি, তবে গুরুতর সন্দেহ যে এটিই একমাত্র ...
মার্টিনো
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.