سؤال

لنفترض أنني أعلن عن فصل دراسي C وعدد قليل من التصريحات متشابهة جدا.أرغب في استخدام وظيفة f لتقليل تكرار التعليمات البرمجية لهذه الإعلانات.من الممكن فقط الإعلان والاستخدام f كل عادة:

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     w = f(42)
... 
>>> C.v
'<9>'
>>> C.w
'<42>'
>>> C.f(4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method f() must be called with C instance as first argument (got int instance instead)

أُووبس!لقد كشفت عن غير قصد f إلى العالم الخارجي، لكن الأمر لا يستغرق وقتًا self حجة (ولا يمكن لأسباب واضحة).أحد الاحتمالات هو أن del الوظيفة بعد أن أستخدمها:

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     del f
... 
>>> C.v
'<9>'
>>> C.f
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'C' has no attribute 'f'

ولكن ماذا لو كنت أريد استخدامها f مرة أخرى في وقت لاحق، بعد الإعلان؟لن يكون من المفيد حذف الوظيفة.يمكنني جعله "خاصًا" (أي، بادئة اسمه بـ __) واعطائها @staticmethod العلاج، ولكن الاحتجاج staticmethod الكائنات عبر القنوات غير الطبيعية تصبح غير تقليدية للغاية:

>>> class C(object):
...     @staticmethod
...     def __f(num):
...             return '<' + str(num) + '>'
...     v = __f.__get__(1)(9)   # argument to __get__ is ignored...
... 
>>> C.v
'<9>'

لا بد لي من استخدام الجنون أعلاه لأنه staticmethod الكائنات، التي هي واصفات، ليست في حد ذاتها قابلة للاستدعاء.أحتاج إلى استعادة الوظيفة المغلفة بواسطة ملف staticmethod الكائن قبل أن أتمكن من تسميته.

يجب أن تكون هناك طريقة أفضل للقيام بذلك.كيف يمكنني الإعلان عن وظيفة في الفصل بشكل واضح، واستخدامها أثناء الإعلان عنها، وكذلك استخدامها لاحقًا من داخل الفصل؟هل ينبغي لي أن أفعل هذا؟

هل كانت مفيدة؟

المحلول

وبكل بساطة، والحل هو أن و لا تحتاج إلى أن تكون عضوا في الطبقة. وأنا على افتراض بأن ما تتمتعون به عملية التفكير قد ذهب من خلال مرشح لغة Javaish مما تسبب في إعاقة ذهنية. وغني قليلا بشيء من هذا القبيل:

def f(n):
    return '<' + str(num) + '>'

class C(object):

    v = f(9)
    w = f(42)

وبعد ذلك عندما تريد استخدام و مرة أخرى، مجرد استخدامه

>>> f(4)
'<4>'

وأعتقد أن المغزى من القصة هو "في بيثون، كنت لا <م> هل لديك لإجبار كل شيء في فئة".

نصائح أخرى

تمتد علياءإجابة ، إذا كنت ترغب حقًا في تجنب F في مساحة اسم الوحدة النمطية (واستخدام اسم غير محرر مثل _F ، أو إعداد __All__ غير كافٍ) ، فيمكنك تحقيق ذلك عن طريق إنشاء الفصل داخل الإغلاق.

def create_C():
    def f(num):
        return '<' + str(num) + '>'

    class C(object):
        v = f(9)
        def method_using_f(self, x):  return f(x*2)
    return C

C=create_C()
del create_C

وبهذه الطريقة ، تتمتع C بالوصول إلى F ضمن تعريفها وطرقها ، ولكن لا شيء آخر لا يفعله (باستثناء تنفيذ أساليبها إلى حد ما (C.method_using_f.im_func.func_closure))

من المحتمل أن يكون هذا مبالغة في معظم الأغراض - توثيق أن F داخلي باستخدام اتفاقية اسم "_" يجب أن تكون اتفاقية الاسم البادئة كافية بشكل عام.

[يحرر] أحد الخيارات الأخرى هو الاحتفاظ بمرجع إلى كائن الوظيفة المغلف مسبقًا في الطرق التي ترغب في استخدامه فيها.على سبيل المثال، عن طريق تعيينها كوسيطة افتراضية:

class C(object):
    def f(num):
        return '<' + str(num) + '>'

    v = f(9)
    def method_using_f(self, x, f=f):  return f(x*2)

    del f

(على الرغم من أنني أعتقد أن نهج الإغلاق ربما يكون أفضل)

وهذا هو احتمال واحد:

class _C:
    # Do most of the function definitions in here
    @classmethod
    def f(cls):
        return 'boo'

class C(_C):
    # Do the subsequent decoration in here
    v = _C.f()

وأعتقد أنك تحاول القيام بذلك:

class C():
...     class F():
...         def __call__(self,num):
...             return "<"+str(num)+">"
...     f=F()
...     v=f(9)
>>> C.v
'<9>'
>>> C.f(25)
'<25>'
>>> 

وربما هناك حل أفضل أو أكثر pythonic ...

<اقتباس فقرة>   

و"اعلان وظيفة في فئة، واستخدامها خلال إعلانها، وأيضا استخدامه في وقت لاحق من داخل الطبقة"

     

وعذرا. لا يمكن القيام به.

و"لا يمكن أن يتم ذلك" لا يبدو للحصول على جنبا إلى جنب مع بيثون

وخيار واحد: إرسال staticmethod أفضل:

class staticfunc(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kw):
        return self.func(*args, **kw)
    def __repr__(self):
        return 'staticfunc(%r)' % self.func

لنبدأ من البداية.

"الإعلان عن دالة في الفصل، واستخدامها أثناء الإعلان عنها، وكذلك استخدامها لاحقًا من داخل الفصل"

آسف.لا يمكن القيام به."في الفصل" يتناقض مع "المستخدم أثناء الإعلان".

  • في الفصل يعني أنه تم إنشاؤه كجزء من الإعلان.
  • المستخدمة أثناء الإعلان تعني أنها موجودة خارج الفصل.في كثير من الأحيان كفئة التعريف.ومع ذلك، هناك طرق أخرى.

ليس من الواضح ما هو C.w وC.v.هل هي مجرد خيوط؟إذا كان الأمر كذلك، وظيفة خارجية f هو الحل الأفضل.إن عبارة "عدم فوضى مساحة الاسم" خادعة بعض الشيء.بعد كل شيء، تريد استخدامه مرة أخرى.

إنه في نفس الوحدة النمطية مثل C.لهذا السبب تمتلك بايثون وحدات.فهو يربط الوظيفة والفئة معًا.

import myCmod

myCmod.C.w
myCmod.C.v
myCmod.f(42)

إذا لم تكن w وv عبارة عن سلاسل بسيطة، فهناك حل جيد حقًا يوفر قدرًا كبيرًا من المرونة.

بشكل عام، بالنسبة لمتغيرات مستوى الفصل ("الثابت") مثل هذه، يمكننا استخدام فئات أخرى.ليس من الممكن تحقيق واجهة برمجة التطبيقات المطلوبة بشكل كامل، ولكن هذا قريب.

>>> class F(object):
    def __init__( self, num ):
        self.value= num
        self.format= "<%d>" % ( num, )

>>> class C(object):
    w= F(42)
    v= F(9)

>>> C.w
<__main__.F object at 0x00C58C30>
>>> C.w.format
'<42>'
>>> C.v.format
'<9>'

وميزة ذلك هي أن F شيء مناسب من الدرجة الأولى يمكن تمديده.ليس شيئًا "مخفيًا" نحاول تجنب كشفه.إنها حقيقة من حقائق الحياة، لذا يجب علينا أيضًا أن نتبع مبدأ مفتوح/مغلق ونجعله مفتوحًا للتوسيع.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top