python - لماذا لا يتم حفظstaticmethod عبر الصفوف ، عندما يكون @ classlasshod؟




python-2.7 static-methods class-method python-descriptors (3)

classmethod و staticmethod هي واصفات ، ولا يفعل أي منهم ما تتوقعه ، وليس فقط staticmethod .

عندما تقوم بالوصول إلى A.one ، يقوم بإنشاء أسلوب منضم على A ، ثم يجعل ذلك سمة B ، ولكن نظرًا لارتباطه بـ A ، فإن وسيطة cls ستكون دائمًا A ، حتى إذا اتصلت بـ B.one (هذه هي الحالة على كل من Python 2 و Python 3 ؛ إنه خطأ في كل مكان).

عند الوصول إلى A.two ، تقوم بإرجاع كائن الدالة الأولية (لا يحتاج واصف staticmethod إلى القيام بأي شيء خاص جانباً من منع الربط الذي يمكن أن يمرر self أو cls ، بحيث يقوم فقط بإرجاع ما تم لفه). لكن كائن الوظيفة الخام هذا يتم ربطه B كأسلوب مثيل غير staticmethod ، لأنه بدون التفاف staticmethod ، تمامًا كما لو كنت تعرفه بشكل طبيعي.

السبب في أن هذا الأخير يعمل في Python 3 هو أن Python 3 ليس لديه مفهوم عن الطرق غير المحدودة. لها وظائف (والتي إذا تم الوصول إليها عن طريق طبقة من طبقة أصبحت طرق مرتبطة) وطرق مقيد ، حيث بيثون 2 لها وظائف وأساليب غير منضمة وطرق مقيد.

تحقق الطرق غير المحدودة من أنه يتم استدعاؤها باستخدام كائن من النوع الصحيح ، وبالتالي خطأك. تريد الدوال البسيطة فقط العدد الصحيح من الوسيطات.

لا staticmethod الديكور staticmethod في Python 3 يعيد كائن الوظيفة الأولية ، لكن في Python 3 ، هذا جيد. نظرًا لأنه ليس كائنًا ذا طريقة خاصة غير منضمية ، إذا كنت تسميها في الفصل نفسه ، فهي تشبه وظيفة namespaced فقط ، وليست طريقة من أي نوع. سترى المشكلة إذا حاولت أن تفعل:

B().two()

على الرغم من ذلك ، لأن ذلك سيجعل طريقة منضم من هذا المثال من B والوظيفة two ، تمرير وسيطة إضافية ( self ) التي لا تقبل two . في الأساس ، على staticmethod 3 ، فإن staticmethod هو وسيلة تسمح لك باستدعاء الوظيفة في الحالات دون التسبب في الربط ، ولكن إذا قمت فقط باستدعاء الوظيفة من خلال الإشارة إلى الطبقة نفسها ، فلا حاجة إليها ، لأنها مجرد وظيفة بسيطة ، وليس Python 2 "طريقة غير محدودة".

إذا كان لديك سبب ما لتنفيذ هذه النسخة (عادةً ، أقترح عليك أن ترث من A ، ولكن أيا كان) ، وتريد التأكد من حصولك على نسخة ملفوفة من الدالة ، وليس كل ما يعطيكه الواصف عند الوصول إليه على A ، يمكنك تجاوز بروتوكول الواصف عن طريق الوصول مباشرة إلى A ' __dict__ :

class B(object):
    one = A.__dict__['one']
    two = A.__dict__['two']

بالنسخ مباشرة من قاموس الفصل ، لا يتم استدعاء سحر بروتوكول الواصف مطلقًا ، وستحصل على staticmethod و classmethod الملفوفة من one two .

خذ البرنامج النصي التالي:

class A(object):
    @classmethod
    def one(cls):
        print("I am class")

    @staticmethod
    def two():
        print("I am static")


class B(object):
    one = A.one
    two = A.two


B.one()
B.two()

عندما أقوم بتشغيل هذا البرنامج النصي مع Python 2.7.11 ، أحصل على:

I am class
Traceback (most recent call last):
  File "test.py", line 17, in <module>
    B.two()
TypeError: unbound method two() must be called with B instance as first argument (got nothing instead)

يبدو أن الديكورclassmethod محفوظ عبر الطبقات ، لكنstaticmethod ليس كذلك.

Python 3.4 سلوك كما هو متوقع:

I am class
I am static

لماذا لا تحتفظ Python2 بـstaticmethod ، وهل هناك حل بديل؟

تحرير: أخذ اثنين من فئة (والإبقاء علىstaticmethod) يبدو أن العمل ، ولكن هذا لا يزال يبدو غريبا بالنسبة لي.


إخلاء المسئولية: هذه ليست إجابة في الحقيقة ، ولكنها لا تنسجم مع تنسيق التعليقات أيضًا.

لاحظ أنه مع Python2 لم يتم @classmethod @ @classmethod بشكل صحيح عبر الطبقات سواء. في التعليمات البرمجية أدناه ، تعمل المكالمة إلى B.one() كما لو تم استدعاؤها من خلال الفئة A :

$ cat test.py 
class A(object):
    @classmethod
    def one(cls):
        print("I am class", cls.__name__)

class A2(A):
    pass

class B(object):
    one = A.one


A.one()
A2.one()
B.one()

$ python2 test.py 
('I am class', 'A')
('I am class', 'A2')
('I am class', 'A')

ربما تغير هذا ، لكنني قادر على تصفية السجلات على أساس الحقول الفارغة .

عندما أحاول الاستعلام GQL SELECT * FROM Contact WHERE demo=NULL ، فإنه يؤدي إلى إرجاع السجلات التي يفتقد إليها الحقل التجريبي فقط.

وفقًا للمستند http://code.google.com/appengine/docs/python/datastore/gqlreference.html :

يمكن أن يكون الجانب الأيمن من المقارنة واحدًا مما يلي (وفقًا لنوع بيانات الخاصية): [...] a Boolean literal، as TRUE or FALSE؛ الحرف NULL ، الذي يمثل قيمة فارغة (بلا في Python).

لست متأكدًا من أن كلمة "null" هي نفسها "مفقودة" : في حالتي ، كانت هذه الحقول موجودة بالفعل في النموذج ، ولكن لم يتم نشرها عند الإنشاء. ربما Federico يمكنك إعلامنا إذا كان الاستعلام NULL يعمل في حالتك المحددة؟





python python-2.7 static-methods class-method python-descriptors