- كم عدد المهندسين المعماريين الذين تحتاجهم لتطبيق لغة البرمجة؟
- مائة. سيكتب المرء التنفيذ ، وسوف يقول 99 ما الذي يمكنهم فعله بشكل أفضل.
في هذه المقالة ، لا أريد تغطية اللغة نفسها بقدر تفاصيل تفاصيل تطبيق CPython ومكتبتها القياسية ، والتي تضمن أنه لن يكون لديك أي طرق سهلة لجعل تطبيق Python إما متعدد مؤشرات الترابط أو سريعًا أو مدعومًا بسهولة ، ولماذا تم إنشاؤه كثيرًا تطبيقات بديلة (PyPy و Cython و Jython و IronPython و Python for .NET و Parakeet و Nuitka و Stackless و Unladen Swallow) ، وقد توفي نصفها بالفعل ؛ وفهم القليلون السبب وراء عدم حظ البدائل في كسب النضال من أجل البقاء ضد اللغات الأخرى. نعم ، هناك GDScript ، المصمم لحل مشاكل الأداء ، هناك Nim ، المصمم لحل جميع المشكلات بشكل عام ، دون مطالبة المستخدم بالإفصاح الواضح عن الأنواع. ومع ذلك ، وبالنظر إلى القصور الهائل في الصناعة ، أدركت أن اللغات الجديدة لن تشغل بالتأكيد مكانة مهمة خلال السنوات العشر القادمة. ومع ذلك ، أعتقد أنه يمكن جعل الثعبان فعالًا عن طريق تغيير نمط رمز الكتابة ، مع الاحتفاظ في معظمه بالصيغة الأصلية ، والحفاظ بشكل كامل على إمكانية التفاعل بين كود النمط القديم والجديد. سوف أركز على مشاكل CPython ، وليس أقرب منافسيها ، PyPy ، لأن PyPy تتغلب فعليًا على جميع مشكلات CPython.
أنا مبرمج وله سبع سنوات من الخبرة ، وأشارك بشكل رئيسي في تطوير تطبيقات سطح المكتب ، مع بعض التركيز على الويب وقواعد البيانات المتعددة الخيوط. أنت تسأل ، "انتظر لحظة ، لكن ما الذي تشترك به بيثون مع واجهة المستخدم ، وواجهات الويب ، وتعدد مؤشرات الترابط؟". وسأجيب "هذا كل شيء - لا شيء". لقد استخدمت C و Delphi و JavaScript و SQL لمهامي. لم أكن سعيدًا جدًا بهذا الموقف ، ومنذ فترة معينة حاولت المشاركة في مشروع Eric Snow لتطبيق دعم المترجمين الفوريين متعددين في CPython:
https://www.python.org/dev/peps/pep-0554/
https://github.com/ericsnowcurrently/multi-core-python
لسوء الحظ ، سرعان ما جاء الفهم:
- يتم دعم CPython بشكل ضعيف إلى حد ما لمثل هذا المشروع الشعبي ، ولديه مجموعة من المشاكل القديمة التي تظهر عند محاولة إعادة رسم التنفيذ. نتيجة لذلك ، قام إريك باختيار المترجم الفوري مع تقدم متغير لعدة سنوات ؛
- حتى بعد التنفيذ الناجح لمترجمين فوريين متعددين ، فليس من الواضح كيفية تنظيم التنفيذ الموازي أكثر. يقترح PEP استخدام قنوات بسيطة ، لكن هذه الأداة تصبح خطرة لأن المهمة تصبح أكثر تعقيدًا ، مع تهديدات بالتجميد والسلوك غير المتوقع ؛
- اللغة نفسها لديها مشاكل كبيرة تمنع المترجمين الفوريين من تبادل البيانات مباشرة وإعطاء بعض الضمانات للسلوك الذي يمكن التنبؤ به.
الآن بمزيد من التفاصيل حول المشاكل.
تعريفات فئة قابلة للتعديل
نعم ، أنا أفهم أن فئة في الثعبان يتم الإعلان عنها في وقت التشغيل. ولكن اللعنة ، لماذا وضع المتغيرات في ذلك؟ لماذا تضيف أساليب جديدة إلى الأشياء القديمة؟ لا يمكنك التصريح عن الوظائف والمتغيرات خارج الفصول في أي جافا ، ولكن لا يوجد مثل هذا التقييد في بيثون (وقد تم إنشاء بيثون قبل جافا). علاوة على ذلك ، أطلب منك الانتباه إلى كيف تحتاج إلى الانحناء مع السرطان من أجل إضافة أساليب مماثلة للكائن نفسه ، وليس للفصل - وهذا يتطلب أنواعًا.النمط المثالي ، الوظيفة. get get__ ، functools.partial ، وما إلى ذلك.
بالنسبة للمبتدئين ، أود طرح سؤال غريب: لماذا تحتاج الثعابين إلى طرق على الإطلاق؟ ليس وظائف ، كما هو الحال في جافا سكريبت وثيق ، ولكن أساليب الطبقة. أحد العوامل: لم يقدم Guido طرقًا أفضل لعمل أسماء مختصرة للوظائف (بحيث لا يوجد gtk_button_set_focus_on_click) ، لأنه ليس من الواضح كيفية التحديد من كومة من الوظائف المتشابهة مع اسم قصير مطلوب لهذا الكائن المعين. ومع ذلك ، فإن len ، iter ، التالي ، isinstance ، شريحة ، dict ، dir ، str ، repr ، hash ، type ، ظهر في python - الآن هذه هي غلافات على الطرق الصفية المقابلة مع الشرطة السفلية في الاسم ، وبمجرد أن الأنواع البسيطة المدمجة لم تكن الطبقات وعملت فقط من خلال هذه الوظائف. شخصيا ، لا أرى فرقًا كبيرًا بين تسجيل الأسلوب (الكائن) والكائن. الطريقة - خاصةً إذا كانت الطريقة دالة ثابتة ، والتي عمومًا لا تهتم بالحجة الأولى (الذاتية) التي يجب قبولها.
تعريفات الطبقة الديناميكية في الحالة العامة:
- لا تعطي اختبار وحدات. قد ينتج عن أي جزء من التعليمات البرمجية التي تم إجراؤها بشكل صحيح في الاختبار خطأ عندما يعمل النظام بالكامل ، ولن تكون محميًا من هذا داخل CPython ؛
- خلق صعوبات كبيرة من التحسين . إعلان الفصل لا يضمن لك التشغيل الفعلي للفصل. لهذا السبب ، يستخدم مشروع المُحسِّن الوحيد الناجح في PyPy عملية التتبع لاكتشاف التسلسل الفعلي للإجراءات التي يتم تنفيذها بواسطة طريقة التحقيق ؛
- لا ترسو مع تنفيذ التعليمات البرمجية المتوازية . على سبيل المثال ، تعمل نفس المعالجة المتعددة مع نسخ من تعريفات الفصل ، وإذا غير الله ، غيّر وصف الفئات في إحدى النُسخ ، فعندئذٍ يخاطر تطبيقك بالانهيار.
هناك إصدار أكثر دقة من الفئات الديناميكية هو تجاوز الوصول إلى السمة من خلال __getattribute__ و __getattr__ وغيرها. غالبًا ما يتم استخدامها كمسؤولين عن getter العادية ، لتفويض الوظائف إلى كائن حقل ، وأحيانًا لتنظيم DSL . يمكن تنفيذ كل هذه الوظائف بطريقة أكثر تحضراً ، دون تحويل الفئة إلى تفريغ للأوصاف ، يصعب أحيانًا ضمان سلوكه. بالمناسبة ، في حالة getters / setters ، مثل هذه الآلية موجودة بالفعل - هذه هي واصفات السمة: https://www.python.org/dev/peps/pep-0252/#id5
هناك حاجة إلى تبديل ساخن للفئات من أجل تصحيح الأخطاء والترميز الشائع ، ولكن لا يزال يجب أن يكون أداة متخصصة للمطور ، وليس أداة في وقت التشغيل لا يمكن التخلص منها.
تعد الفئات المترجمة مجرد خطوة صغيرة اتخذها Cython و Nuitka بالفعل ، لكن هذه الخطوة وحدها دون تغييرات أخرى لا تكفي للحصول على أي تأثير كبير حتى من حيث سرعة التنفيذ ، لأنه على سبيل المثال ، يستخدم python بشكل مكثف الربط المتغير الديناميكي ، الذي ليس في أي مكان لا يذهب بعيدا في التعليمات البرمجية المترجمة.
وراثة متعددة
أعتقد أن هذا هو قائد موكب القبعة. أنها ليست حتى على مستوى وظائف C في تنفيذ بيثون نفسه وملحقاته. "لكن ماذا عن واجهات؟" أنت تعترض. هناك حاجة إلى واجهات في C ++ و Java في دور الإعلان عن بروتوكولات استدعاء أساليب كائن لغرض التحقق ثابت لاحق من هذه البروتوكولات في التحويل البرمجي ، وكذلك لإنشاء جداول الطريقة التي سيتم استخدامها في وقت التشغيل بواسطة رمز آخر لا يعرف أي شيء عن الكائن المصدر. هذه الأدوار تضيع بالكامل تقريبًا في الثعبان ، لذلك لا يوجد مبرر لوجودها. أنا أحب الطريقة التي يتم بها صنع واجهات في Go - أنها تشبه إلى حد بعيد بيثون ABC: https://www.python.org/dev/peps/pep-3119
الميراث المتعدد ليس مشكلة مباشرة للموازنة والتحسين ، ولكنه يعقد تعقيد قابلية قراءة الكود وقابليته للصيانة - وهذا ما يسمى كود اللازانيا (بالقياس إلى رمز السباغيتي).
مولدات
هذه حالة مهملة حقًا من GoTo ، عندما لا ينتقل التنفيذ بشكل لا يمكن السيطرة عليه فوق الشفرة - إنه يقفز فوق المداخن. تحدث اللعبة الشرسة بشكل خاص عندما تتقاطع المولدات مع مدراء السياق (hello PEP 567). إذا كان هناك ميل عام في الثعبان لربط التطبيق في كرة ضيقة من الحالات القابلة للتغيير ذات الصلة والتي لا تعطي مساحة للاختبار ، والموازنة ، ومناورات تحسين البرنامج ، فإن المولدات هي كرز على هذه الكعكة.
ما رأيك سيكون نتيجة البرنامج:
import contextlib
@contextlib.contextmanager
def context_manager():
try:
print('')
yield
finally:
print('')
def gen_in_manager():
m = context_manager()
with m:
for i in range(5):
yield i
g1 = gen_in_manager()
next(g1)
print('')
, :
import contextlib
@contextlib.contextmanager
def context_manager():
try:
print('')
yield
finally:
print('')
def gen_in_manager():
m = context_manager()
with m:
for i in range(5):
yield i
def test():
g1 = gen_in_manager()
next(g1)
test()
print('')
.
, , : async/await, .
: RPython -. , . , , .
https://stackoverflow.com/questions/530530/python-2-x-gotchas-and-landmines
>>> a = ([42],)
>>> a[0] += [43, 44]
TypeError: 'tuple' object does not support item assignment
>>> a
([42, 43, 44],)
>>> a = ([42],)
>>> b = a[0]
>>> b += [43, 44]
>>> a
([42, 43, 44],)
>>> x = y = [1,2,3]
>>> x = x + [4]
>>> x == y
False
>>> x = y = [1,2,3]
>>> x += [4]
>>> x == y
True
>>> x = [[]]*5
>>> x
[[], [], [], [], []]
>>> x[0].append(0)
>>> x
[[0], [0], [0], [0], [0]]
, «'tuple' object does not support item assignment» : . , , , , . , , x[0].append(0) , CPython , . , .
— [] ? , , . , Clojure , - partial-copy-on-write . , .
? , , . , copy-on-write , : b.append.., b[].., b +=… : , , — , , . , , , , // , .
copy-on-write? , , (), ( ), , .
- . ? , copy-on-write, «({'first': 1, 'second': 2},)», , , , , , «{'first': 1, 'second': 2}».
https://ru.wikipedia.org/wiki/_()
« — »
: https://en.wikipedia.org/wiki/Multiple_dispatch#Use_in_practice
, 13–32% (a.k.a. ), 2.7–6.5% — . : , , , . , , .
, — , . , , . , double char, , double .
float a = 2.0;
float *src = &a;
char *dest = malloc(sizeof(float));
memcpy(dest, src, sizeof(float));
printf("%f", *(double*)dest);
, (, , ) — - , , , .
, ( ) . : «a = b + c», , . ?
- : «if (Py_TYPE(obj) == &PyLong_Type) {long val = PyLong_AsLong...}» type();
- : «PyArg_ParseTuple()» , «this.number = int(param1); this.text = str(param2)» — , . , , ( , );
- // . — .
, . , ? CPython, , , , , . , : . , ? : , / , / . C «a = b + c» ( , ):
def PyNumber_Add(b, c):
slotb = b.__add__
if not type(b) is type(c) and c.__add__:
slotc = c.__add__
if slotc is slotb:
slotc = None
if slotb:
if slotc and isinstance(c, b.__class__):
return slotc(b, c)
else:
return slotb(b, c)
else:
return slotb(b, c)
if isinstance(b, str) and isinstance(c, str):
a = unicode_concatenate(b, c)
else:
a = PyNumber_Add(b, c)
, , . « » — , , , , . , , , « », «», «», ; — .
: , . , . : , . , , — .
, . , , . , - , .
, , ( ), ( ), . , , ( ). , , — , ? .
— : , . , , . , , - , , : . , , — MRO:
https://www.python.org/download/releases/2.3/mro/
https://ru.wikipedia.org/wiki/C3-
, 3.4 « » ( Argument — Monty Python ), . « »… , : 3.4 2014, 1991.
. , (trait) Rust ( , , , , ):
https://doc.rust-lang.org/1.8.0/book/traits.html
, , , , , . «». , , . , - , , Rust-. , __iter__ — «». , , , , . , « - , ». , , C++ ranges, , , .
:
from collections.abc import Iterable, Container
from itertools import filterfalse
class MyList(Trait, Iterable, Container):
pass
def __sub__(a: MyList, b: object):
return list(filterfalse(lambda x: x == b, a))
def __sub__(a: MyList, b: Container):
return list(filterfalse(lambda x: x in b, a))
a = MyList([1, 2, 3, 4, 5])
print(a - [2, 5]) # , print(__sub__(a, b))
# : [1, 3, 4]
print(a - 3)
# : [1, 2, 4, 5]
MyList, Iterable ( __iter__) Container ( __contains__), list, list MyList, MyList list, list MyList. :
from collections.abc import Container
from itertools import filterfalse
class MyList(list):
def __sub__(self, b):
if isinstance(b, Container):
return list(filterfalse(lambda x: x in b, a))
else:
return list(filterfalse(lambda x: x == b, a))
a = MyList([1, 2, 3, 4, 5])
print(a - [2, 5])
# : [1, 3, 4]
print(a - 3)
# : [1, 2, 4, 5]
: , «a», . « », -, .
, — , , , . , , .
, , . , , , , , , . - , — - , . :
>>> a = [1, 2, 3]
...
>>> a = '15'
...
>>> for i in map(lambda x: x*2, a):
>>> print(i)
11
55
2
4
6
.
, , . None — , NoneType. , — , - , . :
>>> class A():
>>> def __init__(self, value):
>>> self.val = value
>>>
>>> a = A('2')
>>> a.val = []
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only assign str (not "list") to str
>>> a.myattr = []
>>> a.myattr = 2
A val, . , - (myattr) — , , .
, . — , , . , :
>>> class A():
>>> def __init__(self, value):
>>> self.val = value
>>>
>>> def func():
>>> a = A(None)
>>> a.val = 2
>>> print(a.__dict__)
>>>
>>> func()
{'val': 2}
A<None or Int>, . , , .
: , : , , , «-», «». — , ; - , , , , . , , «list», , , list comprehension, , , BUILD_LIST LIST_APPEND ( CPython) — ? , « », « - ».
, - () , «a.val = int(newval)». , , , . , __setattr__ __setattribute__, c 2.2 __set__ ( https://www.python.org/dev/peps/pep-0252/ ). : , , — C++/Java/C#. , : __set__, __get__, __delete__, , :
>>> a = StrictDict({'first': 1 })
>>> a = { 'dummy': 666 }
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StrictDictError: "first" key is missing in the assignment source
, ( « »): copy-on-write , , -, copy-on-write :
>>> a = COWList([1, 2, 3])
>>> b = a
>>> a.append(4)
>>> b.append(5)
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3, 5]
, CPython , «»:
https://github.com/python/cpython/blob/master/Objects/typeobject.c#L5074
, __slots__ . , , , , , , , , . ( ) . , : __slots__ , PyHeapTypeObject->ht_slots, __dict__, PyTypeObject->tp_dictoffset. , .
, , . , , , , , « , ; — "", ""», . , , . «<> = new <>()», «var = new <>()». , ReasonML , , — JS , , .
PyPy, V8 JavaScript LuaJIT, , . - , , . AOT , asm.js, WebAssembly, PNaCl.
:
- Bauer, A.M. and Saal, H.J. (1974). Does APL really need run-time checking? Software — Practice and Experience 4: 129–138.
- Kaplan, M.A. and Ullman, J.D. (1980). A scheme for the automatic inference of variable types. J. A CM 27(1): 128–145.
- Borning, A.H. and Ingalls, D.H.H. (1982). A type declaration and inference system for Smalltalk. In Conference Record of the Ninth Annual ACM Symposium on Principles of Programming Languages (pp. 133–141)
- https://ru.wikipedia.org/wiki/Standard_ML — 1984 .
, Standard ML , , .
, - , . , , — , , ( ), :
- Frank Pfenning. (1988). Partial polymorphic type inference and higher-order unification. In Proceedings of the 1988 ACM Conference on Lisp and Functional Programming, pp. 153–163
- Cardelli, Luca; Martini, Simone; Mitchell, John C.; Scedrov, Andre (1994). An extension of system F with subtyping. Information and Computation, vol. 9. North Holland, Amsterdam. pp. 4–56
- Benjamin C. Pierce, and David N. Turner. (1997). Local type inference. Indiana University CSCI Technical Report #493, pp. 1-25
(1998) Local type inference. POPL '98 Proceedings of the 25th ACM SIGPLAN-SIGACT symposium on Principles of programming languages, pp. 252-265
(2000). Local type inference. ACM Transactions on Programming Languages and Systems (TOPLAS). Vol. 22(1), pp. 1-44
— , Scala, 2001 .
1991 , 1994 — , 1995 — «Matz», . , , . , , — , , , , , ZeroMQ, RabbitMQ, Kafka. , , , , , . , ? . - , Crystal, , .
— . , , .