[python] ما هي الطرق الطبقية في بيثون؟



Answers

تعتبر أساليب المصنع (المنشئ البديل) في الواقع مثالًا كلاسيكيًا على طرق الصف.

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

على سبيل المثال ، في وحدة unipath ممتازة:

الدليل الحالي

  • Path.cwd()
    • إرجاع الدليل الحالي الفعلي ؛ على سبيل المثال ، Path("/tmp/my_temp_dir") . هذه طريقة طبقية.
  • .chdir()
    • جعل النفس الدليل الحالي.

نظرًا لأن الدليل الحالي عبارة عن عملية واسعة ، فإن طريقة cwd لا تحتوي على مثيل معين يجب ربطه به. ومع ذلك ، فإن تغيير cwd إلى دليل مثيل Path معين يجب أن يكون بالفعل أسلوب مثيل.

هممم ... كما في Path.cwd() بإرجاع نسخة Path ، أعتقد أنه يمكن اعتبار طريقة مصنع ...

Question

أنا أدرس نفسي Python وكان آخر درس لي هو أن Python ليست Java ، ولذلك قضيت وقتًا طويلاً في تحويل كل أساليب الفصل إلى وظائف.

أدرك الآن أنني لست بحاجة إلى استخدام أساليب الفصل لما كنت سأفعله بأساليب static في Java ، لكنني الآن لست متأكداً متى سأستخدمها. كل النصيحة التي يمكن أن أجدها حول أساليب بايثون هي على غرار المبتدئين مثلي ، يجب أن يتجنبوا ذلك ، والوثائق القياسية في معظمها مبهمة عند مناقشتها.

هل لدى أي شخص مثال جيد على استخدام طريقة Class في Python أو على الأقل يمكن لأي شخص أن يقول لي متى يمكن استخدام أساليب Class بشكل معقول؟




بكل صراحه؟ لم أجد أبدًا استخدامًا لـ staticmethod أو classmethod. لم أر حتى الآن عملية لا يمكن القيام بها باستخدام وظيفة عالمية أو طريقة مثيل.

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

عادة ، أرى الناس الذين يستخدمون staticmethods و classmethods عندما كل ما يحتاجون فعله هو استخدام الأسس على مستوى الوحدة النمطية python على نحو أفضل.




اعتدت على العمل مع PHP ومؤخرا كنت أسأل نفسي ، ما الذي يحدث مع هذا classmethod؟ دليل بايثون تقني جدا وقصير جدا في الكلمات لذا لن يساعد في فهم تلك الميزة. كنت googling وغوغلينغ وجدت الإجابة -> http://code.anjanesh.net/2007/12/python-classmethods.html .

إذا كنت كسول للنقر عليه. توضيحي هو أقصر وأدناه. :)

في PHP (ربما لم تكن جميعًا تعرف لغة PHP ، ولكن هذه اللغة واضحة جدًا بحيث يجب على الجميع فهم ما أتحدث عنه) لدينا متغيرات ثابتة مثل:


class A
{

    static protected $inner_var = null;

    static public function echoInnerVar()
    {
        echo self::$inner_var."\n";
    }

    static public function setInnerVar($v)
    {
        self::$inner_var = $v;
    }

}

class B extends A
{
}

A::setInnerVar(10);
B::setInnerVar(20);

A::echoInnerVar();
B::echoInnerVar();

سيكون الناتج في كلتا الحالتين 20.

ولكن في python يمكننا إضافة decoratorclassmethod وبالتالي يمكن إنتاج 10 و 20 على التوالي. مثال:


class A(object):
    inner_var = 0

    @classmethod
    def setInnerVar(cls, value):
        cls.inner_var = value

    @classmethod
    def echoInnerVar(cls):
        print cls.inner_var


class B(A):
    pass


A.setInnerVar(10)
B.setInnerVar(20)

A.echoInnerVar()
B.echoInnerVar()

ذكية ، أليس كذلك؟




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

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

يمكن العثور أيضًا على مزيد من التفاصيل حول هذا الموضوع في الوثائق: التسلسل الهرمي القياسي (انتقل لأسفل إلى قسم طرائق المثيل )




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

module.py (file 1)
---------
def f1() : pass
def f2() : pass
def f3() : pass


usage.py (file 2)
--------
from module import *
f1()
f2()
f3()
def f4():pass 
def f5():pass

usage1.py (file 3)
-------------------
from usage import f4,f5
f4()
f5()

إن الشفرة الإجرائية المذكورة أعلاه ليست منظمة بشكل جيد ، كما يمكنك رؤيتها بعد 3 وحدات فقط تصبح مربكة ، ماذا تفعل كل طريقة؟ يمكنك استخدام أسماء وصفية طويلة للوظائف (كما هو الحال في جافا) ولكن لا يزال بإمكانك التحكم في شفرتك بسرعة كبيرة.

والطريقة الموجهة للكائن هي تحطيم شفرتك إلى كتل يمكن التحكم فيها ، أي أن الفصول والأشياء والوظائف يمكن أن ترتبط بحالات كائنات أو بفئات.

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

class FileUtil ():
  def copy(source,dest):pass
  def move(source,dest):pass
  def copyDir(source,dest):pass
  def moveDir(source,dest):pass

//usage
FileUtil.copy("1.txt","2.txt")
FileUtil.moveDir("dir1","dir2")

بهذه الطريقة أكثر مرونة وأكثر قابلية للإصلاح ، تقوم بتجميع الوظائف معًا وأكثر وضوحًا لما تقوم به كل وظيفة. كما يمكنك منع تعارضات الأسماء ، على سبيل المثال قد توجد نسخة الوظيفة في وحدة نمطية مستوردة أخرى (على سبيل المثال نسخة الشبكة) التي تستخدمها في التعليمات البرمجية ، لذلك عند استخدام الاسم الكامل FileUtil.copy () تقوم بإزالة المشكلة وكلا من وظائف النسخ يمكن استخدامها جنبا إلى جنب.




أنه موضوع شيق. يؤخذ على ذلك أن python classmethod يعمل مثل singleton بدلاً من مصنع (الذي يعيد إنتاج مثيل لفئة). السبب في ذلك هو أن هناك كائن مشترك يتم إنتاجه (القاموس) ولكن مرة واحدة للفصل الدراسي ولكن مشاركته في جميع الحالات.

لتوضيح هذا هنا هو مثال على ذلك. لاحظ أن جميع الأمثلة لها مرجع إلى القاموس الواحد. هذا ليس نمط مصنع كما أفهمها. ربما هذا هو فريد جدا لبيثون.

class M():
 @classmethod
 def m(cls, arg):
     print "arg was",  getattr(cls, "arg" , None),
     cls.arg = arg
     print "arg is" , cls.arg

 M.m(1)   # prints arg was None arg is 1
 M.m(2)   # prints arg was 1 arg is 2
 m1 = M()
 m2 = M() 
 m1.m(3)  # prints arg was 2 arg is 3  
 m2.m(4)  # prints arg was 3 arg is 4 << this breaks the factory pattern theory.
 M.m(5)   # prints arg was 4 arg is 5



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

لذا فقد استخدمت متغيرات الصنف @classmethod لتحقيق ذلك.

من خلال فصيلي "التسجيل" البسيط ، يمكنني القيام بما يلي:

Logger._level = Logger.DEBUG

ثم ، في رمز بلدي ، إذا أردت أن يبصق مجموعة من المعلومات التصحيح ، كان علي أن أقوم برمجيا

Logger.debug( "this is some annoying message I only want to see while debugging" )

يمكن أن تكون الأخطاء مع

Logger.error( "Wow, something really awful happened." )

في بيئة "الإنتاج" ، يمكنني تحديد

Logger._level = Logger.ERROR

والآن ، سيتم إخراج رسالة الخطأ فقط. لن يتم طباعة رسالة التصحيح.

إليكم صفي:

class Logger :
    ''' Handles logging of debugging and error messages. '''

    DEBUG = 5
    INFO  = 4
    WARN  = 3
    ERROR = 2
    FATAL = 1
    _level = DEBUG

    def __init__( self ) :
        Logger._level = Logger.DEBUG

    @classmethod
    def isLevel( cls, level ) :
        return cls._level >= level

    @classmethod
    def debug( cls, message ) :
        if cls.isLevel( Logger.DEBUG ) :
            print "DEBUG:  " + message

    @classmethod
    def info( cls, message ) :
        if cls.isLevel( Logger.INFO ) :
            print "INFO :  " + message

    @classmethod
    def warn( cls, message ) :
        if cls.isLevel( Logger.WARN ) :
            print "WARN :  " + message

    @classmethod
    def error( cls, message ) :
        if cls.isLevel( Logger.ERROR ) :
            print "ERROR:  " + message

    @classmethod
    def fatal( cls, message ) :
        if cls.isLevel( Logger.FATAL ) :
            print "FATAL:  " + message

وبعض الرموز التي تختبره قليلاً:

def logAll() :
    Logger.debug( "This is a Debug message." )
    Logger.info ( "This is a Info  message." )
    Logger.warn ( "This is a Warn  message." )
    Logger.error( "This is a Error message." )
    Logger.fatal( "This is a Fatal message." )

if __name__ == '__main__' :

    print "Should see all DEBUG and higher"
    Logger._level = Logger.DEBUG
    logAll()

    print "Should see all ERROR and higher"
    Logger._level = Logger.ERROR
    logAll()





Links