python - لغة - كود بايثون
طرق ثابتة في بايثون؟ (6)
هل من الممكن أن يكون لديك أساليب ثابتة في بايثون حتى أتمكن من الاتصال بهم دون تهيئة فئة ، مثل:
ClassName.StaticMethod ( )
طرق ثابتة في بايثون؟
هل من الممكن أن يكون لديك أساليب ثابتة في بايثون حتى أتمكن من الاتصال بهم دون تهيئة فئة ، مثل:
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'])
أعتقد أن ستيفن في الحقيقة صحيح. للإجابة عن السؤال الأصلي ، إذاً ، من أجل إعداد طريقة فصل ، افترض ببساطة أن الوسيطة الأولى لن تكون نسخة استدعاء ، ثم تأكد من أنك تقوم فقط باستدعاء الطريقة من الصف.
(لاحظ أن هذه الإجابة تشير إلى 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