حلول أنيقة لمشاكل بيثون اليومية

in python •  7 years ago 

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

pyth.png
Image by :
Didriks. Modified by Opensource.com. CC BY-SA 4.0

طرق السحر
المزيد من موارد بايثون

ما هي بايثون؟
أعلى بيثون IDEs
أعلى الأطر بيثون واجهة المستخدم الرسومية
أحدث محتوى بيثون
المزيد من موارد المطورين
يمكن اعتبار الطرق السحرية السباكة من بايثون. إنها الأساليب التي يطلق عليها "تحت غطاء محرك السيارة" لبعض الأساليب والرموز والعمليات المضمنة. طريقة السحر الشائعة التي قد تكون معتادًا عليها هي init()التي تسمى عندما نرغب في تهيئة مثيل جديد للفئة.
ربما تكون قد شاهدت طرقًا سحرية شائعة أخرى ، مثل strو repr. هناك عالم كامل من الأساليب السحرية ، وبتطبيق عدد قليل منها ، يمكننا تعديل سلوك كائن ما أو حتى جعله يتصرف وكأنه نوع بيانات مضمّن ، مثل رقم أو قائمة أو قاموس.

لنأخذ هذا Moneyالفصل على سبيل المثال:

class money:

currency_rates = { 
    '$' : 1 ، 
    '€' : 0.88 ، 
} 

def __init__ ( self ، symbol ، amount ) : 
    self . رمز = رمز 
    النفس . المبلغ = مقدار 

def __repr__ ( self ) : 
    return '٪ s٪ .2f' ٪ ( self . symbol ، self . amount )

مواطنه تحويل ( الذات ، الآخر ) : 
    "" "تحويل مبلغ آخر لعملتنا" ""
    NEW_AMOUNT = (
        . البعض مبلغ / الذات . currency_rates [ . آخر رمز ]
        * النفس . currency_rates [ النفس . رمز ] ) 

    عودة الأموال ( النفس . الرمز ، new_amount )

يحدد الفصل سعر العملة لرمز معين وسعر الصرف ، ويحدد مُهيئًا (يُعرف أيضًا باسم المُنشئ) ، وينفذ repr، لذلك عندما نطبع الصف ، نرى تمثيلاً لطيفًا مثل $2.00مثال Money('$', 2.00)مع رمز العملة والكمية. الأهم من ذلك ، فهو يحدد طريقة تسمح لك بالتحويل بين العملات المختلفة مع أسعار صرف مختلفة.

باستخدام shell Python ، لنفترض أننا حددنا تكاليف عنصرين غذائيين بعملات مختلفة ، مثل:

soda_cost = المال ( '$' ، 5.25 )
soda_cost
$ 5.25

pizza_cost = المال ( '€' ، 7.99 )
pizza_cost
€ 7.99
يمكننا استخدام الأساليب السحرية لمساعدة أمثلة هذه الطبقة على التفاعل مع بعضها البعض. لنفترض أننا أردنا إضافة حالتين من هذا الصنف معًا ، حتى لو كانا بعملات مختلفة. لجعل هذا الأمر حقيقة ، يمكننا تنفيذ addالأسلوب السحري في صفنا Money:

class Money:

# ... methods methods ... 

def __add__ ( self ، other ) : 
    "" "إضافة 2 Money مثيلات باستخدام '+'" ""
    new_amount = self . المبلغ + النفس . تحويل ( أخرى ) . مبلغ 
    الإرجاع المال ( رمز . الذات ، new_amount )

الآن يمكننا استخدام هذا الفصل بطريقة بديهية للغاية:

soda_cost = المال ( '$' ، 5.25 )

pizza_cost = المال ( '€' ، 7.99 )

soda_cost + pizza_cost
$ 14.33

pizza_cost + soda_cost
€ 12.61
عندما نضيف حالتين معًا ، نحصل على نتيجة بالعملة المحددة الأولى. كل التحويل يتم بسلاسة تحت غطاء المحرك. إذا أردنا ذلك ، يمكننا أيضًا تنفيذ عملية subالطرح mulوالضرب وغير ذلك الكثير. اقرأ عن محاكاة الأنواع الرقمية ، أو اقرأ هذا الدليل إلى الأساليب السحرية للآخرين.

علمنا أن addالخرائط إلى المشغل المدمج +. طرق السحر الأخرى يمكن أن تعين لرموز مثل []. على سبيل المثال ، للوصول إلى عنصر حسب الفهرس أو المفتاح (في حالة وجود قاموس) ، استخدم getitemالطريقة:

d = { 'one' : 1 ، 'two' : 2 }

d [ 'two' ]
2
d. getitem ( 'two' )
2
بعض الطرق السحرية حتى تعين لوظائف مدمجة ، مثل len()، والتي تعين len().

class alphabet:
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

def __len__ ( self ) : 
    return len ( self . letters ) 

my_alphabet = Alphabet ( )
len ( my_alphabet )
26
التكرارات المخصصة
تكرارات مخصصة هي موضوع قوي بشكل لا يصدق ولكنه مثير للالتباس لبيثونستاس الجدد والمحنك على حد سواء.

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

لل طعام في [ "بيتزا" ، "بطاطا" ] :
طباعة ( الغذاء + "يم.! )

بيتزا. نعم !
فرايز. نعم !
كيف يمكننا التكرار عبر الفصول المخصصة الخاصة بنا؟ أولا ، دعونا نزيل بعض المصطلحات.

لكي نكون متكررين ، يجب على الصف أن ينفذ iter()
و iter()يحتاج طريقة ل تعود إلى مكرر
لكي تكون أحد المكرّسين ، يحتاج الفصل إلى تنفيذ next() (أو next() في Python 2 ) ، والتي يجب أن تثير StopIterationاستثناءً عندما لا توجد عناصر أخرى لتكرارها.
يا للعجب! يبدو الأمر معقدًا ، ولكن عندما تتذكر هذه المفاهيم الأساسية ، ستتمكن من التكرار في نومك.

متى قد نرغب في استخدام مكرر مخصص؟ دعونا نتصور سيناريو حيث لدينا Serverسبيل المثال تشغيل الخدمات المختلفة مثل httpو sshعلى منافذ مختلفة. بعض هذه الخدمات لها activeحالة بينما البعض الآخر inactive.

class Server:

services = [ 
    { active " : False ، 'protocol' : 'ftp' ، 'port' : 21 } ، 
    { 'active' : True ، 'protocol' : 'ssh' ، 'port' : 22 } ، 
    { 'active' : True ، 'protocol' : 'http' ، 'port' : 80 } ، 
]

عندما نتعثر على Serverحاضرتنا ، فنحن لا نريد سوى التكرار عبر activeالخدمات. لنقم بإنشاء فصل جديد ، وهو IterableServer:

class IterableServer:

def __init__ ( self ) : 
    self . current_pos = 0 

def __next__ ( self ) : 
    تمرير  # TODO: تطبيق وتذكر رفع StopIteration

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

class IterableServer:

def __init__ ( self ) : 
    self . current_pos = 0 .  # نقوم بتهيئة وضعنا الحالي إلى صفر 

صفر __iter__ ( ذاتي ) :   # يمكننا إرجاع الذات هنا ، لأنه يتم تنفيذ __next__ 
    return def الذاتي __next__ ( ذاتي ) : في حين self . current_pos < len ( self . services ) :             service =

النفس . خدمات [ النفس . current_pos ]
ذاتيا . current_pos + = 1
if service [ 'active' ] :
return service [ 'protocol' ] ، service [ 'port' ]
raise StopIteration

next = __next__   # optional python2 optional

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

لأننا تنفيذ next()الأسلوب الذي يثير StopIterationعند تستنفد ذلك، يمكن أن نعود selfمن iter()لأن IterableServerالطبقة تلتزم iterableالبروتوكول.

يمكننا الآن إجراء تكرار على مثيل IterableServer، مما يسمح لنا بالنظر إلى كل خدمة نشطة ، مثل:

لل بروتوكول ، ميناء في IterableServer ( ) :
طباعة ( "الخدمة٪ الصورة يعمل على المنفذ٪ d ' ٪ ( البروتوكول ، الميناء ) )

خدمة سه و تشغيل على المنفذ 22
خدمة HTTP و يعمل على المنفذ 21
هذا رائع جدًا ، لكن يمكننا أن نفعل ما هو أفضل! في مثال مثل هذا ، حيث لا يحتاج المبرمج لدينا إلى الحفاظ على الكثير من الحالة ، يمكننا تبسيط التعليمات البرمجية واستخدام مولد بدلاً من ذلك.

class Server:

services = [ 
    { active " : False ، 'protocol' : 'ftp' ، 'port' : 21 } ، 
    { 'active' : True ، 'protocol' : 'ssh' ، 'port' : 22 } ، 
    { 'active' : True ، 'protocol' : 'http' ، 'port' : 21 } ،
] 

def __iter__ (النفس ) : 
    لل خدمة في النفس . الخدمات : 
        إذا كانت الخدمة [ 'نشطة' ] : خدمة 
            العائد [ 'البروتوكول' ] ، الخدمة [ 'المنفذ' ]

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

هذا يعمل بسبب بعض السحر Python المضمنة. في وثائق بيثون لiter() يمكننا أن نرى أنه إذا iter()تم تنفيذ كمولد، فإنه سيعود تلقائيا كائن مكرر التي تزود iter()و next()الأساليب. اقرأ هذا المقال الرائع للحصول على معلومات أكثر عمقًا عن المتكررات والمتكررات والمولدات .

طريقة السحر
نظرًا لجوانبها الفريدة ، تقدم Python بعض الطرق السحرية المثيرة للاهتمام كجزء من اللغة.

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

def foo ( ) :
return 'foo'

foo ( )
'foo'

bar = foo

bar ( )
'foo'
سنرى لاحقًا كيف يمكن أن يكون هذا مفيدًا.

يوفر بيثون مفيد في البناء، ودعاgetattr() ، التي تأخذ object, name, defaultالمعلمات وإرجاع السمة nameعلى object. هذا يسمح لنا برمجيًا بالوصول إلى المتغيرات والطرق. فمثلا:

class Dog:
sound = 'Bark'
def speak ( self ) :
print ( self . sound + '!' ، self . sound + '!' )

fido = Dog ( )

fido. الصوت
"النباح"
getattr ( فيدو ، 'الصوت' )
'اللحاء'

فيدو. تحدث
< طريقة الكلاب المقيدة.من < main . كائن الكلب في 0x102db8828 >> >>> getattr ( فيدو ، 'تحدث' ) < ملزمة طريقة الكلب. تحدث عن < main . كائن الكلب في 0x102db8828 >> >>> فيدو. الكلام ( ) النباح ! النباح ! >>> speak_method = getattr ( fido ، 'speak' ) >>>

)
النباح ! النباح !
خدعة باردة ، ولكن كيف يمكننا استخدامها عمليا getattr؟ دعونا ننظر إلى مثال يسمح لنا بكتابة أداة سطر الأوامر الصغيرة لمعالجة الأوامر ديناميكيًا.

الطبقة العمليات:
صفر say_hi ( النفس ، اسم ) :
طباعة ( 'مرحبا' ، اسم )

مواطنه say_bye ( النفس ، اسم ) : 
    طباعة ( 'وداعا' ، اسم ) 

مواطنه الافتراضي ( النفس ، ARG ) : 
    طباعة ( 'هذه العملية غير مدعوم. ' ) 

إذا كانت name == ' main ' :
operations =العمليات ( )

# لنفترض أننا نقوم بمعالجة خطأ
الأمر ، وسيطة = المدخلات ( '>' ) . split ( )
func_to_call = getattr ( العمليات ، الأوامر ، العمليات. default )
func_to_call ( وسيطة )

إخراج نصنا هو:

$ python getattr.py

say_hi Nina
مرحبا ، نينا

بلاه بلاه
هذه العملية غير مدعومة.
بعد ذلك ، سننظر partial. على سبيل المثال ، functool.partial(func, *args, **kwargs)يسمح لك بإرجاع كائن جزئي جديد يتصرف مثل funcاستدعاء argsو kwargs. إذا argsتم تمرير المزيد ، فسيتم إلحاقها به args. إذا kwargsتم تمرير المزيد ، فإنها تمتد وتجاوز kwargs. دعونا نرى ذلك في العمل مع مثال موجز:

من functools استيراد جزئي
basetwo = جزئية ( كثافة العمليات ، قاعدة = 2 )
basetwo
< functools. كائن جزئي في 0x1085a09f0 > >>> basetwo ( '10010' ) 18 # هذا هو نفسه كـ >>> int ( '10010' ، base = 2 )

دعونا نرى كيف أن هذا الأسلوب العلاقات السحر معا في بعض نموذج التعليمات البرمجية من مكتبة استمتع باستخدام يسمىagithub ، وهو (ضعيف اسمه) العميل REST API مع تركيب وشفاف يسمح لك النموذج الأولي بسرعة أي API REST (وليس فقط جيثب) مع الحد الأدنى من التكوين . أجد هذا المشروع مثيراً للاهتمام لأنه قوي بشكل لا يصدق لكن فقط حوالي 400 سطر من بايثون. يمكنك إضافة دعم لأي واجهة برمجة تطبيقات REST في حوالي 30 سطرًا من رمز التكوين. agithubيعرف كل شيء يحتاج إلى بروتوكول ( REST، HTTP، TCP) ، لكنه لا يفترض شيئا عن API المنبع. دعونا الغوص في التنفيذ.

في ما يلي إصدار مبسط لكيفية تعريفنا لعنوان URL لنقطة النهاية لواجهة برمجة تطبيقات GitHub وأي خصائص اتصال أخرى ذات صلة. عرض الكود بالكامل بدلا من ذلك.

class GitHub ( API ) :

def __init__ ( self ، token = None ، * args ، ** kwargs ) : 
    props = ConnectionProperties ( api_url = kwargs. pop ( 'api_url' ، 'api.github.com' ) ) 
    self . setClient ( Client ( * args ، ** kwargs ) ) 
    self . setConnectionProperties (الدعائم )

بعد ذلك ، بمجرد تهيئة رمز الدخول الخاص بك ، يمكنك البدء في استخدام واجهة برمجة تطبيقات GitHub .

gh = GitHub ( 'token' )
status ، data = gh. المستخدم . ريبوس . الحصول على ( الرؤية = "الجمهور" ، نوع = 'خلق' )

^ خرائط إلى GET / المستخدم / اتفاقيات إعادة الشراء

البيانات
... [ "مكبر الصوت" ، "snipey ' ، ' ... ' ]
لاحظ أن الأمر متروك لك لتوضيح الأمور بشكل صحيح. لا يوجد التحقق من عنوان URL. إذا لم يكن عنوان URL موجودًا أو حدث أي خطأ آخر ، فسيتم إرجاع الخطأ الناتج عن واجهة برمجة التطبيقات. فكيف يعمل هذا كل شيء؟ دعونا معرفة ذلك. أولاً ، سوف نتحقق من مثال مبسط APIللفئة :

class API:

# ... methods methods ... 

def __getattr__ ( self ، key ) : 
    return IncompleteRequest ( self . client ) . __getatr__ ( مفتاح ) 
__getitem__ = __geteatr__

كل مكالمة في APIالفصل تنقل المكالمة إلى IncompleteRequestالفصل الدراسي المحدد key.

class IncompleteRequest:

# ... methods methods ... 

def __getattr__ ( self ، key ) : 
    if key in self . العميل . http_methods : 
        htmlMethod = getattr ( self . client ، key ) 
        return partial ( htmlMethod ، url = self . url ) 
    else : 
        self . url + = '/'+ str ( مفتاح ) 
        عودة الذاتي 
__getitem__ = __geteatr__ 

class العميل:
http_methods = ( 'get' ) # ... و post، put، patch، etc.

def get ( self ، url ، headers = { } ، ** params ) : 
    عودة النفس . طلب ( "GET" ، رابط ، لا شيء ، رؤوس )

إذا كانت المكالمة الأخيرة ليست طريقة HTTP (مثل "get" ، أو "post" ، إلخ) ، IncompleteRequestفستعرض الرسالة مسارًا ملحقًا به. خلاف ذلك ، فإنه يحصل على الوظيفة الصحيحة لطريقة HTTP المحددة من Clientالفئة وإرجاع أ partial.

ماذا يحدث إذا أعطينا مسارًا غير موجود؟

الحالة ، البيانات = هذا. المسار . لا . موجودة . get ( )
status
... 404
ولأنه getitemمستعار لـ getattr:

owner ، repo = 'nnja' ، 'tweeter '
status ، data = gh. repos [ مالك ] [ الريبو ] . يسحب . get ( )

^ Maps to GET / repos / nnja / tweeter / pulls

data
.... # {....}
الآن هذا هو بعض السحر طريقة خطيرة!

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

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!