python - مشاريع - الميزات المخفية لبيثون




مشاريع بلغة بايثون (20)

إنشاء أنواع جديدة بطريقة ديناميكية بالكامل

>>> NewType = type("NewType", (object,), {"x": "hello"})
>>> n = NewType()
>>> n.x
"hello"

وهو بالضبط نفس

>>> class NewType(object):
>>>     x = "hello"
>>> n = NewType()
>>> n.x
"hello"

ربما لا يكون الشيء الأكثر فائدة ، ولكن من الجميل أن تعرف.

تحرير : اسم ثابت من النوع الجديد ، يجب أن يكون NewType ليكون الشيء نفسه تمامًا مثل بيان class .

تعديل : عدّل العنوان لتوضيح الميزة بشكل أكثر دقة.


الربط بين مشغلي المقارنة:

>>> x = 5
>>> 1 < x < 10
True
>>> 10 < x < 20 
False
>>> x < 10 < x*10 < 100
True
>>> 10 > x <= 9
True
>>> 5 == x > 4
True

في حال كنت تفكر في القيام به 1 < x ، والذي يخرج كما True ، ثم مقارنة True < 10 ، وهو أيضا True ، ثم لا ، هذا في الواقع ليس ما يحدث (انظر المثال الأخير.) إنه حقا ترجمة إلى 1 < x and x < 10 ، و x < 10 and 10 < x * 10 and x*10 < 100 ، ولكن مع كتابة أقل ويتم تقييم كل مصطلح مرة واحدة فقط.


واصفات

They're the magic behind a whole bunch of core Python features.

When you use dotted access to look up a member (eg, xy), Python first looks for the member in the instance dictionary. If it's not found, it looks for it in the class dictionary. If it finds it in the class dictionary, and the object implements the descriptor protocol, instead of just returning it, Python executes it. A descriptor is any class that implements the __get__ , __set__ , or __delete__ methods.

Here's how you'd implement your own (read-only) version of property using descriptors:

class Property(object):
    def __init__(self, fget):
        self.fget = fget

    def __get__(self, obj, type):
        if obj is None:
            return self
        return self.fget(obj)

and you'd use it just like the built-in property():

class MyClass(object):
    @Property
    def foo(self):
        return "Foo!"

Descriptors are used in Python to implement properties, bound methods, static methods, class methods and slots, amongst other things. Understanding them makes it easy to see why a lot of things that previously looked like Python 'quirks' are the way they are.

Raymond Hettinger has an excellent tutorial that does a much better job of describing them than I do.


Doctest : documentation and unit-testing at the same time.

Example extracted from the Python documentation:

def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    If the result is small enough to fit in an int, return an int.
    Else return a long.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result

def _test():
    import doctest
    doctest.testmod()    

if __name__ == "__main__":
    _test()

ROT13 هو ترميز صالح لرمز المصدر ، عندما تستخدم تصريح الترميز الصحيح في أعلى ملف الكود:

#!/usr/bin/env python
# -*- coding: rot13 -*-

cevag "Uryyb fgnpxbiresybj!".rapbqr("rot13")

إذا كنت لا تحب استخدام المسافات البيضاء للدلالة على النطاقات ، فيمكنك استخدام النمط C {} بإصدار:

from __future__ import braces

من 2.5 فصاعدا dicts لها طريقة خاصة __missing__ التي يتم استدعاؤها للعناصر المفقودة:

>>> class MyDict(dict):
...  def __missing__(self, key):
...   self[key] = rv = []
...   return rv
... 
>>> m = MyDict()
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

هناك أيضاً فئة فرعية dict في collections تسمى defaultdict التي لها نفس الشيء تقريباً ولكنها تستدعي دالة بدون وسيطات للعناصر الموجودة:

>>> from collections import defaultdict
>>> m = defaultdict(list)
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

أوصي تحويل هذه dicts إلى dicts العادية قبل تمريرها إلى وظائف لا تتوقع مثل هذه الفئات الفرعية. تستخدم الكثير من التعليمات البرمجية d[a_key] وتسجيل KeyErrors للتحقق مما إذا كان هناك عنصر موجود والذي سيضيف عنصرًا جديدًا إلى الأمر dict.


وسيطة الخطوة في مشغلي شريحة. فمثلا:

a = [1,2,3,4,5]
>>> a[::2]  # iterate over the whole list in 2-increments
[1,3,5]

الحالة الخاصة x[::-1] هي تعبير مفيد لـ "x عكس".

>>> a[::-1]
[5,4,3,2,1]

Conditional Assignment

x = 3 if (y == 1) else 2

It does exactly what it sounds like: "assign 3 to x if y is 1, otherwise assign 2 to x". Note that the parens are not necessary, but I like them for readability. You can also chain it if you have something more complicated:

x = 3 if (y == 1) else 2 if (y == -1) else 1

Though at a certain point, it goes a little too far.

Note that you can use if ... else in any expression. فمثلا:

(func1 if y == 1 else func2)(arg1, arg2) 

Here func1 will be called if y is 1 and func2, otherwise. In both cases the corresponding function will be called with arguments arg1 and arg2.

Analogously, the following is also valid:

x = (class1 if y == 1 else class2)(arg1, arg2)

where class1 and class2 are two classes.


Interactive Interpreter Tab Completion

try:
    import readline
except ImportError:
    print "Unable to load readline module."
else:
    import rlcompleter
    readline.parse_and_bind("tab: complete")


>>> class myclass:
...    def function(self):
...       print "my function"
... 
>>> class_instance = myclass()
>>> class_instance.<TAB>
class_instance.__class__   class_instance.__module__
class_instance.__doc__     class_instance.function
>>> class_instance.f<TAB>unction()

You will also have to set a PYTHONSTARTUP environment variable.


Operator overloading for the set builtin:

>>> a = set([1,2,3,4])
>>> b = set([3,4,5,6])
>>> a | b # Union
{1, 2, 3, 4, 5, 6}
>>> a & b # Intersection
{3, 4}
>>> a < b # Subset
False
>>> a - b # Difference
{1, 2}
>>> a ^ b # Symmetric Difference
{1, 2, 5, 6}

مزيد من التفاصيل من مرجع المكتبة القياسي: Set Types


Re-raising exceptions :

# Python 2 syntax
try:
    some_operation()
except SomeError, e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

# Python 3 syntax
try:
    some_operation()
except SomeError as e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

The 'raise' statement with no arguments inside an error handler tells Python to re-raise the exception with the original traceback intact , allowing you to say "oh, sorry, sorry, I didn't mean to catch that, sorry, sorry."

If you wish to print, store or fiddle with the original traceback, you can get it with sys.exc_info(), and printing it like Python would is done with the 'traceback' module.


إنشاء كائنات المولدات

إذا كنت تكتب

x=(n for n in foo if bar(n))

يمكنك الخروج من المولد وتعيينه إلى x. الآن يعني أنه يمكنك القيام به

for n in x:

ميزة هذا هو أنك لا تحتاج إلى تخزين وسيط ، والذي ستحتاج إليه إذا كنت ترغب في ذلك

x = [n for n in foo if bar(n)]

في بعض الحالات ، يمكن أن يؤدي ذلك إلى تسريع كبير.

يمكنك إلحاق العديد من العبارات إذا كانت نهاية المولد ، تتكرر بشكل أساسي متداخلة للحلقات:

>>> n = ((a,b) for a in range(0,2) for b in range(4,6))
>>> for i in n:
...   print i 

(0, 4)
(0, 5)
(1, 4)
(1, 5)

احصل على شجرة النتوء regex python لتصحيح تعبيرك المعتاد.

تعتبر التعبيرات العادية ميزة رائعة في python ، ولكن تصحيح الأخطاء قد يكون بمثابة ألم ، ومن السهل جدًا الحصول على تعبير منطقي خاطئ.

لحسن الحظ ، يمكن لبيثون طباعة شجرة التحليل re.DEBUG ، عن طريق تمرير العلامة المخفية غير الموثقة ، التجريبية ، المخبأة re.DEBUG (فعليًا ، 128) لإعادة re.compile .

>>> re.compile("^\[font(?:=(?P<size>[-+][0-9]{1,2}))?\](.*?)[/font]",
    re.DEBUG)
at at_beginning
literal 91
literal 102
literal 111
literal 110
literal 116
max_repeat 0 1
  subpattern None
    literal 61
    subpattern 1
      in
        literal 45
        literal 43
      max_repeat 1 2
        in
          range (48, 57)
literal 93
subpattern 2
  min_repeat 0 65535
    any None
in
  literal 47
  literal 102
  literal 111
  literal 110
  literal 116

بمجرد فهم بناء الجملة ، يمكنك اكتشاف الأخطاء الخاصة بك. هناك يمكننا أن نرى أنني نسيت أن أهرب من [] في [/font] .

بالطبع يمكنك دمجها مع أي أعلام تريدها ، مثل regexes المعلق:

>>> re.compile("""
 ^              # start of a line
 \[font         # the font tag
 (?:=(?P<size>  # optional [font=+size]
 [-+][0-9]{1,2} # size specification
 ))?
 \]             # end of tag
 (.*?)          # text between the tags
 \[/font\]      # end of the tag
 """, re.DEBUG|re.VERBOSE|re.DOTALL)

ديكور

يسمح Decorators بحفظ وظيفة أو طريقة في وظيفة أخرى يمكنها إضافة وظائف أو تعديل الحجج أو النتائج ، وما إلى ذلك. تكتب زخرفة في سطر واحد فوق تعريف الدالة ، تبدأ بعلامة "at" (@).

يوضح المثال ديكور print_args الذي يقوم بطباعة وسائط الدالة المزخرفة قبل أن يطلق عليها:

>>> def print_args(function):
>>>     def wrapper(*args, **kwargs):
>>>         print 'Arguments:', args, kwargs
>>>         return function(*args, **kwargs)
>>>     return wrapper

>>> @print_args
>>> def write(text):
>>>     print text

>>> write('foo')
Arguments: ('foo',) {}
foo


مبادلة القيمة في المكان

>>> a = 10
>>> b = 5
>>> a, b
(10, 5)

>>> a, b = b, a
>>> a, b
(5, 10)

الجانب الأيمن من المهمة هو تعبير يؤدي إلى إنشاء فئة جديدة. يقوم الجانب الأيسر من المهمة على الفور بفك مجموعة (unberferenced) إلى الأسماء a و b .

بعد التعيين ، لا يتم تمييز المجموعة الجديدة وتمييزها بعلامة جمع البيانات المهملة ، وقد تم تبديل القيم المرتبطة بـ a و b .

كما هو مذكور في قسم بيثون التعليمي حول هياكل البيانات ،

لاحظ أن التعيين المتعدد هو في الحقيقة مجرد مجموعة من تعبئة المجموعة وتسلسل تفريغ.


مدراء السياق و " with " بيان

المقدمة في PEP 343 ، مدير سياق هو كائن يعمل كسياق وقت التشغيل لمجموعة من عبارات.

نظرًا لأن الميزة تستخدم كلمات رئيسية جديدة ، يتم تقديمها تدريجيًا: فهي متوفرة في Python 2.5 عبر التوجيه __future__ . Python 2.6 وما فوق (بما في ذلك Python 3) يتوفر بشكل افتراضي.

لقد استخدمت العبارة "with" كثيرًا لأنني أعتقد أنها بنية مفيدة جدًا ، إليك عرضًا توضيحيًا سريعًا:

from __future__ import with_statement

with open('foo.txt', 'w') as f:
    f.write('hello!')

ما يحدث هنا من وراء الكواليس ، هو أن عبارة "with" تستدعي __enter__ و __exit__ في كائن الملف. يتم أيضًا تمرير تفاصيل الاستثناء إلى __exit__ إذا تم طرح أي استثناء من نص العبارة ، مما يسمح بمعاملة الاستثناء.

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

حالات الاستخدام الشائعة الأخرى لهذا تتضمن التأمين مع مؤشرات الترابط ومعاملات قاعدة البيانات.


Exception else clause:

try:
  put_4000000000_volts_through_it(parrot)
except Voom:
  print "'E's pining!"
else:
  print "This parrot is no more!"
finally:
  end_sketch()

The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn't raised by the code being protected by the try ... except statement.

See http://docs.python.org/tut/node10.html


Nested list comprehensions and generator expressions:

[(i,j) for i in range(3) for j in range(i) ]    
((i,j) for i in range(4) for j in range(i) )

These can replace huge chunks of nested-loop code.





hidden-features