python - لغة - كود بايثون




طرق ثابتة في بايثون؟ (6)

طرق ثابتة في بايثون؟

هل من الممكن أن يكون لديك أساليب ثابتة في بايثون حتى أتمكن من الاتصال بهم دون تهيئة فئة ، مثل:

ClassName.StaticMethod()

نعم ، يمكن إنشاء طرق ثابتة مثل هذا (على الرغم من أنه أكثر قليلا من استخدام Pythonic تسطير سفلي بدلاً من CamelCase للطرق):

class ClassName(object):

    @staticmethod
    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

ما ورد أعلاه يستخدم بنية الديكور. هذا النحو هو ما يعادل

class ClassName(object):

    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

    static_method = staticmethod(static_method)

يمكن استخدام هذا كما وصفت:

ClassName.static_method()

مثال str.maketrans() لأسلوب ثابت هو str.maketrans() في Python 3 ، والتي كانت دالة في وحدة نمطية string في Python 2.

هناك خيار آخر يمكن استخدامه كما classmethod هو classmethod ، والفرق هو أن classmethod يحصل على الفصل كحجة أولية ضمنية ، وإذا كان subclassed ، فإنه يحصل على الفئة الفرعية باعتبارها أول حجة ضمنية.

class ClassName(object):

    @classmethod
    def class_method(cls, kwarg1=None):
        '''return a value that is a function of the class and kwarg1'''

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

يتم استخدام هذه عادةً كمنشئات بديلة.

new_instance = ClassName.class_method()

مثال dict.fromkeys() هو dict.fromkeys() :

new_dict = dict.fromkeys(['key1', 'key2'])

هل من الممكن أن يكون لديك أساليب ثابتة في بايثون حتى أتمكن من الاتصال بهم دون تهيئة فئة ، مثل:

ClassName.StaticMethod ( )

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

(لاحظ أن هذه الإجابة تشير إلى Python 3.x. في Python 2.x ستحصل على TypeError لاستدعاء الطريقة على الفئة نفسها.)

فمثلا:

class Dog:
    count = 0 # this is a class variable
    dogs = [] # this is a class variable

    def __init__(self, name):
        self.name = name #self.name is an instance variable
        Dog.count += 1
        Dog.dogs.append(name)

    def bark(self, n): # this is an instance method
        print("{} says: {}".format(self.name, "woof! " * n))

    def rollCall(n): #this is implicitly a class method (see comments below)
        print("There are {} dogs.".format(Dog.count))
        if n >= len(Dog.dogs) or n < 0:
            print("They are:")
            for dog in Dog.dogs:
                print("  {}".format(dog))
        else:
            print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))

fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)

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

rex.rollCall(-1)

ومع ذلك ، قد يؤدي ذلك إلى ظهور استثناء لأنه سيقوم بإرسال وسيطتين: نفسها و -1 ، ويتم تعريف "rollCall" فقط لقبول وسيطة واحدة.

بالمناسبة ، يقوم rex.rollCall () بإرسال العدد الصحيح من الوسيطات ، ولكنه قد يتسبب أيضًا في ظهور استثناء لأن n سيكون الآن يمثل نسخة Dog (أي ، rex) عندما تتوقع الدالة n أن تكون رقمية.

هذا هو المكان الذي تأتي فيه الزخرفة: إذا قمنا باتباع أسلوب "rollCall" مع

@staticmethod

ثم ، من خلال القول صراحة أن الطريقة ثابتة ، يمكننا حتى أن نسميها من مثيل. الآن،

rex.rollCall(-1)

ستعمل. عندئذٍ يؤدي إدراجstaticmethod قبل تعريف الطريقة ، إلى إيقاف مثيل من إرسال نفسه كوسيطة.

يمكنك التحقق من ذلك من خلال تجربة التعليمة البرمجية التالية مع وبدون تعليق السطرstaticmethod.

class Dog:
    count = 0 # this is a class variable
    dogs = [] # this is a class variable

    def __init__(self, name):
        self.name = name #self.name is an instance variable
        Dog.count += 1
        Dog.dogs.append(name)

    def bark(self, n): # this is an instance method
        print("{} says: {}".format(self.name, "woof! " * n))

    @staticmethod
    def rollCall(n):
        print("There are {} dogs.".format(Dog.count))
        if n >= len(Dog.dogs) or n < 0:
            print("They are:")
            for dog in Dog.dogs:
                print("  {}".format(dog))
        else:
            print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))


fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
rex.rollCall(-1)

ربما يكون أبسط خيار هو وضع تلك الوظائف خارج الفصل:

class Dog(object):
    def __init__(self, name):
        self.name = name

    def bark(self):
        if self.name == "Doggy":
            return barking_sound()
        else:
            return "yip yip"

def barking_sound():
    return "woof woof"

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

لنفترض أن هذا الملف يسمى dogs.py لاستخدام هذه ، يمكنك استدعاء dogs.barking_sound() بدلاً من dogs.Dog.barking_sound .

إذا كنت حقا بحاجة إلى طريقة ثابتة لتكون جزءا من الصف ، يمكنك استخدام الديكور staticmethod .


نعم ، تحقق من الديكور staticmethod :

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World

واجهت هذا السؤال من وقت لآخر. حالة الاستخدام والمثال الذي أنا مغرم به هو:

[email protected]:/home/jeffs  $ python36
Python 3.6.1 (default, Sep  7 2017, 16:36:03) 
[GCC 6.3.0 20170406] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cmath
>>> print(cmath.sqrt(-4))
2j
>>>
>>> dir(cmath)
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cos', 'cosh', 'e', 'exp', 'inf', 'infj', 'isclose', 'isfinite', 'isinf', 'isnan', 'log', 'log10', 'nan', 'nanj', 'phase', 'pi', 'polar', 'rect', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau']
>>> 

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


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

# garden.py
def trim(a):
    pass

def strip(a):
    pass

def bunch(a, b):
    pass

def _foo(foo):
    pass

class powertools(object):
    """
    Provides much regarded gardening power tools.
    """
    @staticmethod
    def answer_to_the_ultimate_question_of_life_the_universe_and_everything():
        return 42

    @staticmethod
    def random():
        return 13

    @staticmethod
    def promise():
        return True

def _bar(baz, quux):
    pass

class _Dice(object):
    pass

class _6d(_Dice):
    pass

class _12d(_Dice):
    pass

class _Smarter:
    pass

class _MagicalPonies:
    pass

class _Samurai:
    pass

class Foo(_6d, _Samurai):
    pass

class Bar(_12d, _Smarter, _MagicalPonies):
    pass

...

# tests.py
import unittest
import garden

class GardenTests(unittest.TestCase):
    pass

class PowertoolsTests(unittest.TestCase):
    pass

class FooTests(unittest.TestCase):
    pass

class BarTests(unittest.TestCase):
    pass

...

# interactive.py
from garden import trim, bunch, Foo

f = trim(Foo())
bunch(f, Foo())

...

# my_garden.py
import garden
from garden import powertools

class _Cowboy(garden._Samurai):
    def hit():
        return powertools.promise() and powertools.random() or 0

class Foo(_Cowboy, garden.Foo):
    pass

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

وكثيراً ما أجد أنه من المجدي تطبيق هذا النهج على تنظيم رمز أداة المشروع. في كثير من الأحيان ، يهرع الناس على الفور ويخلقون حزمة utils وينتهي بهم المطاف بـ 9 وحدات تضم واحدة منها 120 LOC والباقي أكثر من عشرين LOC في أحسن الأحوال. أفضّل البدء بهذا وتحويله إلى حزمة وإنشاء وحدات فقط للوحوش التي تستحقها حقًا:

# utils.py
class socket(object):
    @staticmethod
    def check_if_port_available(port):
        pass

    @staticmethod
    def get_free_port(port)
        pass

class image(object):
    @staticmethod
    def to_rgb(image):
        pass

    @staticmethod
    def to_cmyk(image):
        pass




static-methods