Numpy: مشكلة في تتبع تنفيذ NEP-18 (__وظيفة __وظيفة __)

تم إنشاؤها على ٢٥ سبتمبر ٢٠١٨  ·  54تعليقات  ·  مصدر: numpy/numpy

  • [x] الوظيفة الأساسية لدعم التجاوزات:

    • [x] التنفيذ الأولي في لغة Python الخالصة (# 12005)

    • [x] التحقق من صحة وظائف المرسل في array_function_dispatch (https://github.com/numpy/numpy/pull/12099)



      • تعطيل التحقق عند عدم اختبار NumPy (إذا كان هناك تأثير قابل للقياس على أوقات الاستيراد) (غير ضروري)



    • [x] أضف سمة دالة .__skip_array_function__ للسماح بتخطي إرسال __array_function__ . (https://github.com/numpy/numpy/pull/13389)

  • [x] أعد تنفيذ أجزاء من numpy/core/overrides.py في C للسرعة (https://github.com/numpy/numpy/issues/12028):

    • [x] get_overloaded_types_and_args

    • [x] array_function_implementation_or_override

    • [x] ndarray.__array_function__ ؟

    • [x] array_function_dispatch ؟

  • [x] تجاوزات الدعم لجميع وظائف NumPy العامة

    • [x] numpy.core



      • [x] الجزء السهل (https://github.com/numpy/numpy/pull/12115)


      • [x] np.core.defchararray (# 12154)


      • [x] np.einsum و np.block (https://github.com/numpy/numpy/pull/12163)



    • [x] numpy.lib



      • [x] الجزء 1 (https://github.com/numpy/numpy/pull/12116)


      • [x] الجزء 2 (# 12119)



    • [x] numpy.fft / numpy.linalg (https://github.com/numpy/numpy/pull/12117)

    • [x] دالات مكتوبة بالكامل حاليًا بلغة C : blank_like، concatenate، inner، where، lexsort، can_cast، min_scalar_type، result_type، dot، vdot، is_busday، busday_offset، busday_count، datetime_as_string (https://github.com/numpy/numpy/ سحب / 12175)

    • [x] linspace

    • [] [ arange? ] (https://github.com/numpy/numpy/issues/12379)

  • [x] تحسينات الاستخدام

    • [x] [رسالة خطأ أفضل] (https://github.com/numpy/numpy/issues/12213) للوظائف غير المُنفَّذة (https://github.com/numpy/numpy/pull/12251)

    • [x] يجب ألا يعتمد ndarray.__repr__ على __array_function__ (https://github.com/numpy/numpy/pull/12212)

    • [x] يجب زيادة stacklevel بمقدار 1 للوظائف المغلفة ، لذلك تشير عمليات التتبع إلى المكان الصحيح (gh-13329)

  • [x] إصلاح جميع الأخطاء المعروفة / إخفاقات الاختبار النهائية
  • [ ] توثيق

    • [x] ملاحظات الإصدار (# 12028)

    • [x] وثائق السرد

    • [] الوثائق المنقحة لتوضيح الحجج المثقلة؟

__array_function__

التعليق الأكثر فائدة

هل هناك اقتراح حول إجراء هذا النوع من التغيير أم أنك تقول إن دعم إرسال np.array سيكون صعبًا حقًا ولذا لا يمكننا الحصول على دعم بنسبة 100٪؟

يناقش NEP 22 الخيارات هنا. لا أعتقد أنه يمكننا تغيير دلالات np.asarray() بأمان لإرجاع أي شيء بخلاف كائن numpy.ndarray - سنحتاج إلى بروتوكول جديد لهذا الغرض.

تكمن المشكلة في أن np.asarray() حاليًا هو الطريقة الاصطلاحية للإرسال إلى كائن مصفوفة numpy ، والذي يستخدم ويتوقع أن يتطابق تمامًا مع numpy.ndarray ، على سبيل المثال ، وصولاً إلى تخطيط الذاكرة.

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

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

نعم. لا يُقصد من NEP 18 أن يكون حلاً كاملاً لبدائل NumPy المنسدلة ، ولكنه خطوة في هذا الاتجاه.

ال 54 كومينتر

قد يكون من الجيد دمج "تزيين جميع وظائف NumPy العامة معarray_function_dispatch" لبعض الوظائف البارزة وطلب المستهلكين من البروتوكول لتجربته

بمجرد أن ندمج https://github.com/numpy/numpy/pull/12099 ، لديّ علاقات عامة أخرى جاهزة من شأنها إضافة ديكورات إرسال لمعظم numpy.core . سيكون من السهل جدًا إنهاء الأشياء - استغرق هذا الأمر أقل من ساعة لتجميعه.

سم مكعب @ اريك-يزرmrocklinmhvkhameerabbasi

راجع https://github.com/shoyer/numpy/tree/array-function-easy-impl لفرعي الذي ينفذ جميع التجاوزات "السهلة" على الوظائف باستخدام أغلفة Python. الأجزاء المتبقية هي np.block ، np.einsum وحفنة من وظائف الدالات المتعددة مكتوبة بالكامل في C (على سبيل المثال ، np.concatenate ). سأقسم هذا إلى مجموعة من العلاقات العامة بمجرد أن ننتهي من # 12099.

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

shoyer - في الاختبارات ، أوافق على أنه ليس من المفيد بشكل خاص كتابة الاختبارات لكل اختبار ؛ بدلاً من ذلك ، داخل numpy ، قد يكون من المنطقي البدء في استخدام التجاوزات بسرعة نسبيًا في MaskedArray .

يبدو mhvk جيدًا بالنسبة لي ، على الرغم من أنني سأسمح لشخص آخر يستخدم / يعرف MaskedArray بأخذ زمام المبادرة في ذلك.

راجع https://github.com/numpy/numpy/pull/12115 و https://github.com/numpy/numpy/pull/12116 و # 12119 و https://github.com/numpy/numpy/pull/ 12117 لـ PRs الذين يطبقون دعم __array_function__ للوظائف المحددة في Python.

shoyer - عند رؤية بعض التطبيقات ، لدي

  • بالنسبة لبعض الوظائف ، مثل reshape ، قدمت الوظيفة الأصلية بالفعل طريقة لتجاوزها ، من خلال تحديد طريقة reshape . نحن نستبعد ذلك فعليًا لأي فئة تحدد __array_function__ .
  • بالنسبة للوظائف الأخرى ، مثل np.median ، فإن الاستخدام الدقيق لـ np.asanyarray و ufuncs يضمن أن الفئات الفرعية يمكنها استخدامها بالفعل. ولكن لم يعد من الممكن الوصول إلى هذه الوظيفة مباشرة.

أعتقد بشكل عام أن هذين الأمرين هما على الأرجح فوائد ، نظرًا لأننا نبسط الواجهة ويمكننا جعل عمليات التنفيذ محسّنة لـ ndarray - على الرغم من أن الأخير يشير إلى أن ndarray.__array_function__ يجب أن يتولى قوائم التحويل ، وما إلى ذلك ، إلى ndarray ، بحيث يمكن للتطبيقات تخطي هذا الجزء). ومع ذلك ، اعتقدت أنني سألاحظ ذلك لأنه يجعلني أشعر بالرهبة من تنفيذ هذا مقابل Quantity أكثر قليلاً مما كنت أعتقد - من حيث مقدار العمل والضربة المحتملة في الأداء.

على الرغم من أن الأخير يقترح أن ndarray .__ يجب أن تتولى الدالة array_function__ تحويل القوائم ، وما إلى ذلك ، إلى ndarray ، بحيث يمكن للتطبيقات تخطي هذا الجزء).

لست متأكدًا من أنني أتابع هنا.

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

لست متأكدًا من أنني أتابع هنا.

أعتقد أن المشكلة تكمن في أننا إذا طبقنا __array_function__ لوظيفة واحدة ، فإن الآليات السابقة تنكسر تمامًا ولا توجد طريقة لتجاوز الفشل. ولهذا أقترح إعادة النظر في اقتراحي NotImplementedButCoercible .

hameerabbasi - نعم ، هذه هي المشكلة. على الرغم من أننا بحاجة إلى توخي الحذر هنا في مدى سهولة الاعتماد على حلول الشريط اللاصق التي نفضل التخلص منها حقًا ... (ولهذا السبب كتبت أعلاه أن "مشاكلي" قد تكون في الواقع فوائد ...) . ربما توجد حالة للمحاولة كما هي في 1.16 ثم اتخاذ قرار بشأن التجربة الفعلية فيما إذا كنا نريد توفير احتياطي لـ "تجاهل __array_function__ الخاص بي لهذه الحالة".

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

ومع ذلك ، فأنا لا أعارض أسلوب لامدا كثيرًا.

لقد ظهر الآن أسلوب كتابة وظائف المرسل في عدد قليل من العلاقات العامة. سيكون من الجيد اتخاذ خيار ثابت عبر NumPy.

لدينا بعض الخيارات:


الخيار 1 : اكتب مرسل منفصل لكل وظيفة ، على سبيل المثال ،

def _sin_dispatcher(a):
    return (a,)


@array_function_dispatch(_sin_dispatcher)
def sin(a):
     ...


def _cos_dispatcher(a):
    return (a,)


@array_function_dispatch(_cos_dispatcher)
def cos(a):
    ...

مزايا:

  • مقروء جدا
  • من السهل العثور على تعريفات وظائف المرسل
  • امسح رسالة الخطأ عند تقديم وسيطات خاطئة ، على سبيل المثال ، sin(x=1) -> TypeError: _sin_dispatcher() got an unexpected keyword argument 'x' .

سلبيات:

  • الكثير من التكرار ، حتى عندما يكون للعديد من الوظائف في الوحدة نفس التوقيع بالضبط.

الخيار 2 : إعادة استخدام وظائف المرسل داخل وحدة نمطية ، على سبيل المثال ،

def _unary_dispatcher(a):
    return (a,)


@array_function_dispatch(_unary_dispatcher)
def sin(a):
     ...


@array_function_dispatch(_unary_dispatcher)
def cos(a):
    ...

مزايا:

  • أقل تكرار
  • مقروء

سلبيات:

  • قد يكون من الصعب العثور على تعريفات لوظائف المرسل
  • رسائل خطأ أقل وضوحًا للوسيطات السيئة ، مثل sin(x=1) -> TypeError: _unary_dispatcher() got an unexpected keyword argument 'x'

الخيار 3 : استخدم وظائف lambda عندما يكون تعريف المرسل مناسبًا لسطر واحد ، على سبيل المثال ،

# inline style (shorter)
@array_function_dispatch(lambda a: (a,))
def sin(a):
     ...


@array_function_dispatch(lambda a, n=None, axis=None, norm=None: (a,))
def fft(a, n=None, axis=-1, norm=None):
     ...
# multiline style (more readable?)
@array_function_dispatch(
    lambda a: (a,)
)
def sin(a):
     ...


@array_function_dispatch(
    lambda a, n=None, axis=None, norm=None: (a,)
)
def fft(a, n=None, axis=-1, norm=None):
     ...

مزايا:

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

سلبيات:

  • كود متكرر أكثر من الخيار 2.
  • تبدو مشوشة جدًا إذا كان هناك أكثر من بضع حجج
  • يحتوي أيضًا على رسائل خطأ أقل وضوحًا ( TypeError: <lambda>() got an unexpected keyword argument 'x' )

shoyer : تم التعديل لإضافة تباعد PEP8 المكون من سطرين لجعل جانب "سطور الكود" أكثر واقعية

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

نعم ، يمكن أيضًا استخدام وحدة التزيين لتوليد تعريف الوظيفة (تستخدم طريقة مختلفة قليلاً لإنشاء الكود ، تشبه إلى حدٍ ما الاسمات المزدوجة من حيث أنها تستخدم exec() ).

طالما لم يتم حل الخطأ ، أعتقد أننا بحاجة إلى الالتزام بالخيارات مع المرسل الذي له اسم واضح. أود قليلاً أن أقوم بتجميع المرسلين معًا (2) لأسباب تتعلق بالذاكرة ، على الرغم من أنني سأضع رسالة الخطأ في الاعتبار كثيرًا ، لذلك أقترح استدعاء المرسل شيئًا مثل _dispatch_on_x .

على الرغم من أنه إذا تمكنا من تغيير الخطأ ، فإن الأشياء تتغير. على سبيل المثال ، قد يكون الأمر بسيطًا مثل التقاط الاستثناءات ، واستبدال <lambda> باسم الوظيفة في نص الاستثناء ، ثم إعادة الزيادة. (أم أن هذه السلسلة من الأشياء هذه الأيام؟)

أوافق على أن رسالة الخطأ يجب أن تكون واضحة ، ومن الأفضل ألا تتغير على الإطلاق.

حسنًا ، أعتقد في الوقت الحالي أنه من الأفضل تأجيل استخدام lambda ، ما لم نحصل على نوع من إنشاء الكود.

يضيف https://github.com/numpy/numpy/pull/12175 مسودة لما يمكن أن تبدو عليه تجاوزات وظائف المصفوفات المتعددة (مكتوبة بلغة C) إذا اتبعنا نهج غلاف Python.

mattip أين وصلنا عند تنفيذ matmul كـ ufunc؟ بمجرد الانتهاء من كل هذه التجاوزات __array_function__ ، أعتقد أن هذا هو آخر شيء نحتاجه لجعل واجهة برمجة تطبيقات NumPy العامة قابلة للتحميل بشكل زائد. سيكون من الجيد أن يكون كل شيء جاهزًا لـ NumPy 1.16!

يحقق PR # 11175 ، الذي ينفذ NEP 20 ، تقدمًا بطيئًا. وهو مانع لـ PR # 11133 ، والذي يحتوي على كود حلقة matmul. لا يزال هذا الشخص بحاجة إلى التحديث ثم التحقق من ذلك عبر معايير أن الكود الجديد ليس أبطأ من الرمز القديم.

لدي أربعة علاقات عامة للمراجعة والتي يجب أن تكمل المجموعة الكاملة من التجاوزات. سيكون موضع تقدير المراجعات / التوقيعات / الدمج النهائية حتى نتمكن من البدء في اختبار __array_function__ بشكل جدي! https://github.com/numpy/numpy/pull/12154 ، https://github.com/numpy/numpy/pull/12163 ، https://github.com/numpy/numpy/pull/12119 ، https: //github.com/numpy/numpy/pull/12175

تسببت إضافة التخطي إلى np.core فشل بعض اختبارات الباندا (https://github.com/pandas-dev/pandas/issues/23172). لسنا متأكدين تمامًا مما يحدث حتى الآن ، لكن يجب علينا بالتأكيد اكتشاف ذلك قبل الإفراج عنه.

راجع https://github.com/numpy/numpy/issues/12225 للحصول على أفضل تخمينات عن سبب تسبب هذا في فشل الاختبار في dask / pandas.

بعض المعايير القياسية لأوقات الاستيراد (على جهاز macbook Pro الخاص بي المزود بمحرك أقراص الحالة الصلبة):

  • NumPy 1.15.2: 152.451 مللي ثانية
  • NumPy الرئيسي: 156.5745 مللي ثانية
  • باستخدام decorator.decorate (# 12226): 183.694 مللي ثانية

البرنامج النصي المعياري الخاص بي

import numpy as np
import subprocess

times = []
for _ in range(100):
    result = subprocess.run("python -X importtime -c 'import numpy'",
                            shell=True, capture_output=True)
    last_line = result.stderr.rstrip().split(b'\n')[-1]
    time = float(last_line.decode('ascii')[-15:-7].strip().rstrip())
    times.append(time)

print(np.median(times) / 1e3)

أي فكرة عن استخدام الذاكرة (قبل / بعد)؟ هذا مفيد أيضًا ، خاصة لتطبيقات إنترنت الأشياء.

هل تعرف كيف تقيس بشكل موثوق استخدام الذاكرة لوحدة ما؟
يوم السبت 20 أكتوبر 2018 الساعة 6:56 صباحًا Hameer Abbasi [email protected]
كتب:

أي فكرة عن استخدام الذاكرة (قبل / بعد)؟ هذا نوع من المفيد مثل
حسنًا ، خاصة لتطبيقات إنترنت الأشياء.

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/numpy/numpy/issues/12028#issuecomment-431584123 ، أو كتم الصوت
الخيط
https://github.com/notifications/unsubscribe-auth/ABKS1k_IkrJ2YmYReaDrnkNvcH2X0-ZCks5umyuogaJpZM4W3kSC
.

أعتقد أن كتابة نص يحتوي على import numpy as np ، إضافة بيان النوم وذاكرة عملية التتبع يجب أن يكون جيدًا بما فيه الكفاية. https://superuser.com/questions/581108/how-can-i-track-and-log-cpu-and-memory-usage-on-a-mac

أي مطوري نواة آخرين يريدون إلقاء نظرة سريعة (حقًا ، إنه يتضمن وظيفتين فقط!) على https://github.com/numpy/numpy/pull/12163؟ إنها آخر العلاقات العامة التي تضيف array_function_dispatch إلى وظائف numpy الداخلية.

كمرجع ، إليك اختلاف الأداء الذي أراه عند تعطيل __array_function__ :

       before           after         ratio
     [45718fd7]       [4e5aa2cd]
     <master>         <disable-array-function>
+        72.5±2ms         132±20ms     1.82  bench_io.LoadtxtCSVdtypes.time_loadtxt_dtypes_csv('complex128', 10000)
-        44.9±2μs       40.8±0.6μs     0.91  bench_ma.Concatenate.time_it('ndarray', 2)
-      15.3±0.3μs       13.3±0.7μs     0.87  bench_core.CountNonzero.time_count_nonzero_multi_axis(2, 100, <type 'object'>)
-        38.4±1μs         32.7±2μs     0.85  bench_linalg.Linalg.time_op('norm', 'longfloat')
-        68.7±3μs         56.5±3μs     0.82  bench_linalg.Linalg.time_op('norm', 'complex256')
-        80.6±4μs         65.9±1μs     0.82  bench_function_base.Median.time_even
-        82.4±2μs         66.8±3μs     0.81  bench_shape_base.Block.time_no_lists(100)
-        73.5±3μs         59.3±3μs     0.81  bench_function_base.Median.time_even_inplace
-      15.2±0.3μs       12.2±0.6μs     0.80  bench_core.CountNonzero.time_count_nonzero_multi_axis(3, 100, <type 'str'>)
-      2.20±0.1ms      1.76±0.04ms     0.80  bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint64', (4, 4))
-        388±20μs         310±10μs     0.80  bench_lib.Pad.time_pad((10, 10, 10), 3, 'linear_ramp')
-        659±20μs         524±20μs     0.80  bench_linalg.Linalg.time_op('det', 'float32')
-      22.9±0.7μs       18.2±0.8μs     0.79  bench_function_base.Where.time_1
-        980±50μs         775±20μs     0.79  bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint32', (4, 4))
-        36.6±1μs         29.0±1μs     0.79  bench_ma.Concatenate.time_it('unmasked', 2)
-      16.4±0.7μs       12.9±0.6μs     0.79  bench_core.CountNonzero.time_count_nonzero_axis(3, 100, <type 'str'>)
-      16.4±0.5μs       12.9±0.4μs     0.79  bench_core.CountNonzero.time_count_nonzero_axis(2, 100, <type 'object'>)
-         141±5μs          110±4μs     0.78  bench_lib.Pad.time_pad((10, 100), (0, 5), 'linear_ramp')
-      18.0±0.6μs       14.1±0.6μs     0.78  bench_core.CountNonzero.time_count_nonzero_axis(3, 100, <type 'object'>)
-      11.9±0.6μs       9.28±0.5μs     0.78  bench_core.CountNonzero.time_count_nonzero_axis(1, 100, <type 'int'>)
-        54.6±3μs         42.4±2μs     0.78  bench_function_base.Median.time_odd_small
-        317±10μs          246±7μs     0.78  bench_lib.Pad.time_pad((10, 10, 10), 1, 'linear_ramp')
-      13.8±0.5μs       10.7±0.7μs     0.77  bench_reduce.MinMax.time_min(<type 'numpy.float64'>)
-        73.3±6μs         56.6±4μs     0.77  bench_lib.Pad.time_pad((1000,), (0, 5), 'mean')
-      14.7±0.7μs       11.4±0.3μs     0.77  bench_core.CountNonzero.time_count_nonzero_axis(2, 100, <type 'str'>)
-        21.5±2μs       16.5±0.6μs     0.77  bench_reduce.MinMax.time_min(<type 'numpy.int64'>)
-         117±4μs         89.2±3μs     0.76  bench_lib.Pad.time_pad((1000,), 3, 'linear_ramp')
-        43.7±1μs         33.4±1μs     0.76  bench_linalg.Linalg.time_op('norm', 'complex128')
-      12.6±0.6μs       9.55±0.2μs     0.76  bench_core.CountNonzero.time_count_nonzero_multi_axis(2, 100, <type 'int'>)
-        636±20μs         482±20μs     0.76  bench_ma.MA.time_masked_array_l100
-        86.6±4μs         65.6±4μs     0.76  bench_lib.Pad.time_pad((1000,), (0, 5), 'linear_ramp')
-         120±4μs         90.4±2μs     0.75  bench_lib.Pad.time_pad((1000,), 1, 'linear_ramp')
-         160±5μs          119±8μs     0.74  bench_ma.Concatenate.time_it('ndarray+masked', 100)
-      14.4±0.6μs       10.7±0.3μs     0.74  bench_core.CountNonzero.time_count_nonzero_multi_axis(1, 100, <type 'str'>)
-      15.7±0.4μs       11.7±0.6μs     0.74  bench_core.CountNonzero.time_count_nonzero_multi_axis(2, 100, <type 'str'>)
-        21.8±2μs       16.1±0.7μs     0.74  bench_reduce.MinMax.time_max(<type 'numpy.int64'>)
-      11.9±0.6μs       8.79±0.3μs     0.74  bench_core.CountNonzero.time_count_nonzero_axis(2, 100, <type 'bool'>)
-        53.8±3μs         39.4±2μs     0.73  bench_function_base.Median.time_even_small
-        106±20μs         76.7±4μs     0.73  bench_function_base.Select.time_select
-        168±10μs          122±4μs     0.72  bench_shape_base.Block2D.time_block2d((512, 512), 'uint32', (2, 2))
-      12.5±0.5μs       8.96±0.4μs     0.72  bench_core.CountNonzero.time_count_nonzero_multi_axis(1, 100, <type 'int'>)
-        162±10μs          115±5μs     0.71  bench_function_base.Percentile.time_percentile
-        12.9±1μs       9.12±0.4μs     0.71  bench_random.Random.time_rng('normal')
-      9.71±0.4μs       6.88±0.3μs     0.71  bench_core.CorrConv.time_convolve(1000, 10, 'full')
-      15.1±0.8μs       10.7±0.4μs     0.71  bench_reduce.MinMax.time_max(<type 'numpy.float64'>)
-         153±9μs          108±7μs     0.71  bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint8', (2, 2))
-         109±5μs         76.9±5μs     0.71  bench_ma.Concatenate.time_it('ndarray+masked', 2)
-        34.3±1μs       24.2±0.6μs     0.71  bench_linalg.Linalg.time_op('norm', 'complex64')
-      9.80±0.2μs       6.84±0.5μs     0.70  bench_core.CorrConv.time_convolve(1000, 10, 'same')
-        27.4±6μs         19.1±2μs     0.70  bench_core.CountNonzero.time_count_nonzero_axis(1, 10000, <type 'bool'>)
-      9.35±0.4μs       6.50±0.3μs     0.70  bench_core.CorrConv.time_convolve(50, 100, 'full')
-        65.2±4μs         45.2±1μs     0.69  bench_shape_base.Block.time_block_simple_row_wise(100)
-        12.9±1μs       8.89±0.3μs     0.69  bench_core.CountNonzero.time_count_nonzero_axis(3, 100, <type 'bool'>)
-        19.6±3μs       13.5±0.4μs     0.69  bench_core.CountNonzero.time_count_nonzero_multi_axis(3, 100, <type 'object'>)
-        75.6±2μs         52.1±3μs     0.69  bench_lib.Pad.time_pad((10, 10, 10), (0, 5), 'reflect')
-        12.4±1μs       8.51±0.4μs     0.69  bench_core.CountNonzero.time_count_nonzero_multi_axis(3, 100, <type 'bool'>)
-        172±30μs          117±4μs     0.68  bench_ma.Concatenate.time_it('unmasked+masked', 100)
-      23.1±0.5μs       15.8±0.9μs     0.68  bench_linalg.Linalg.time_op('norm', 'int16')
-      8.18±0.9μs       5.57±0.1μs     0.68  bench_core.CorrConv.time_correlate(1000, 10, 'full')
-         153±5μs          103±3μs     0.68  bench_function_base.Percentile.time_quartile
-       758±100μs         512±20μs     0.68  bench_linalg.Linalg.time_op('det', 'int16')
-        55.4±6μs         37.4±1μs     0.68  bench_ma.Concatenate.time_it('masked', 2)
-        234±30μs          157±5μs     0.67  bench_shape_base.Block.time_nested(100)
-         103±4μs         69.3±3μs     0.67  bench_linalg.Eindot.time_dot_d_dot_b_c
-      19.2±0.4μs       12.9±0.6μs     0.67  bench_core.Core.time_tril_l10x10
-         122±7μs         81.7±4μs     0.67  bench_lib.Pad.time_pad((10, 10, 10), 3, 'edge')
-        22.9±1μs       15.3±0.5μs     0.67  bench_linalg.Linalg.time_op('norm', 'int32')
-        16.6±2μs       11.0±0.3μs     0.66  bench_core.CountNonzero.time_count_nonzero_multi_axis(1, 100, <type 'object'>)
-      9.98±0.3μs       6.58±0.1μs     0.66  bench_core.CorrConv.time_convolve(1000, 10, 'valid')
-         118±6μs         77.9±4μs     0.66  bench_shape_base.Block2D.time_block2d((512, 512), 'uint16', (2, 2))
-        212±50μs          140±8μs     0.66  bench_lib.Pad.time_pad((10, 10, 10), (0, 5), 'mean')
-      21.9±0.7μs       14.4±0.5μs     0.66  bench_linalg.Linalg.time_op('norm', 'int64')
-         131±5μs         85.9±5μs     0.65  bench_lib.Pad.time_pad((10, 10, 10), 3, 'constant')
-        56.8±2μs         37.0±3μs     0.65  bench_lib.Pad.time_pad((1000,), (0, 5), 'constant')
-        58.9±3μs         38.1±1μs     0.65  bench_lib.Pad.time_pad((10, 100), (0, 5), 'reflect')
-        72.1±2μs         46.5±3μs     0.64  bench_lib.Pad.time_pad((10, 100), (0, 5), 'constant')
-      8.66±0.3μs       5.58±0.2μs     0.64  bench_core.CorrConv.time_correlate(50, 100, 'full')
-        300±30μs         193±10μs     0.64  bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint8', (4, 4))
-        15.9±5μs       10.2±0.3μs     0.64  bench_core.CountNonzero.time_count_nonzero_axis(3, 100, <type 'int'>)
-      13.7±0.5μs       8.80±0.1μs     0.64  bench_random.Random.time_rng('uniform')
-      8.60±0.5μs       5.50±0.2μs     0.64  bench_core.CorrConv.time_correlate(1000, 10, 'same')
-        44.7±2μs       28.5±0.7μs     0.64  bench_lib.Pad.time_pad((1000,), 1, 'reflect')
-        72.7±3μs         46.2±2μs     0.64  bench_lib.Pad.time_pad((10, 10, 10), 3, 'wrap')
-        567±50μs         360±40μs     0.63  bench_shape_base.Block2D.time_block2d((512, 512), 'uint64', (2, 2))
-        58.0±3μs         36.7±2μs     0.63  bench_lib.Pad.time_pad((10, 100), 3, 'reflect')
-        219±30μs          138±7μs     0.63  bench_lib.Pad.time_pad((10, 100), 1, 'mean')
-        261±60μs         164±10μs     0.63  bench_lib.Pad.time_pad((10, 100), 1, 'linear_ramp')
-       825±100μs         519±30μs     0.63  bench_shape_base.Block2D.time_block2d((512, 512), 'uint64', (4, 4))
-         121±5μs         75.7±2μs     0.63  bench_lib.Pad.time_pad((10, 10, 10), 1, 'constant')
-      8.16±0.2μs       5.08±0.4μs     0.62  bench_core.CorrConv.time_convolve(50, 100, 'same')
-        66.6±3μs         41.3±2μs     0.62  bench_lib.Pad.time_pad((1000,), 3, 'constant')
-        53.1±3μs       32.9±0.8μs     0.62  bench_lib.Pad.time_pad((10, 100), 3, 'wrap')
-        285±60μs         177±10μs     0.62  bench_lib.Pad.time_pad((10, 10, 10), (0, 5), 'linear_ramp')
-      8.30±0.9μs       5.14±0.1μs     0.62  bench_core.CorrConv.time_correlate(1000, 10, 'valid')
-         115±3μs         71.2±3μs     0.62  bench_shape_base.Block2D.time_block2d((256, 256), 'uint64', (2, 2))
-      19.1±0.5μs       11.8±0.6μs     0.62  bench_linalg.Linalg.time_op('norm', 'float64')
-        95.3±5μs         58.6±2μs     0.62  bench_lib.Pad.time_pad((10, 100), 1, 'constant')
-        44.6±1μs       27.2±0.9μs     0.61  bench_lib.Pad.time_pad((1000,), (0, 5), 'edge')
-        447±20μs         270±10μs     0.61  bench_shape_base.Block2D.time_block2d((1024, 1024), 'uint16', (4, 4))
-        53.9±2μs         32.6±2μs     0.60  bench_lib.Pad.time_pad((10, 100), 1, 'wrap')
-        11.6±1μs       6.97±0.4μs     0.60  bench_reduce.MinMax.time_max(<type 'numpy.float32'>)
-        95.9±5μs         57.7±2μs     0.60  bench_lib.Pad.time_pad((10, 100), 3, 'constant')
-        47.2±2μs         28.2±2μs     0.60  bench_lib.Pad.time_pad((1000,), (0, 5), 'reflect')
-      5.51±0.2μs      3.27±0.07μs     0.59  bench_core.CountNonzero.time_count_nonzero(3, 100, <type 'object'>)
-        74.3±3μs         44.0±2μs     0.59  bench_lib.Pad.time_pad((10, 10, 10), (0, 5), 'wrap')
-        76.2±3μs       45.0±0.8μs     0.59  bench_lib.Pad.time_pad((10, 10, 10), 1, 'reflect')
-        57.1±1μs         33.5±2μs     0.59  bench_lib.Pad.time_pad((10, 100), (0, 5), 'wrap')
-        52.0±2μs         30.4±1μs     0.58  bench_lib.Pad.time_pad((1000,), 1, 'edge')
-        42.6±2μs       24.9±0.9μs     0.58  bench_lib.Pad.time_pad((1000,), 3, 'wrap')
-        15.0±3μs       8.73±0.3μs     0.58  bench_core.CountNonzero.time_count_nonzero_multi_axis(1, 100, <type 'bool'>)
-        16.0±3μs       9.29±0.3μs     0.58  bench_core.CountNonzero.time_count_nonzero_multi_axis(3, 100, <type 'int'>)
-        53.1±1μs         30.9±2μs     0.58  bench_lib.Pad.time_pad((1000,), 3, 'edge')
-        88.0±8μs         51.1±3μs     0.58  bench_lib.Pad.time_pad((10, 10, 10), 3, 'reflect')
-        44.6±2μs         25.9±1μs     0.58  bench_lib.Pad.time_pad((1000,), (0, 5), 'wrap')
-        90.3±5μs         51.9±1μs     0.57  bench_shape_base.Block2D.time_block2d((512, 512), 'uint8', (2, 2))
-      15.6±0.5μs       8.93±0.3μs     0.57  bench_linalg.Linalg.time_op('norm', 'float32')
-         102±6μs       58.3±0.9μs     0.57  bench_lib.Pad.time_pad((10, 10, 10), 1, 'edge')
-        80.1±4μs         45.6±3μs     0.57  bench_lib.Pad.time_pad((10, 100), 3, 'edge')
-        44.2±2μs         24.9±1μs     0.56  bench_lib.Pad.time_pad((1000,), 1, 'wrap')
-        71.6±8μs         39.5±1μs     0.55  bench_lib.Pad.time_pad((10, 10, 10), 1, 'wrap')
-       81.7±10μs         44.8±2μs     0.55  bench_lib.Pad.time_pad((10, 100), 1, 'edge')
-        420±90μs         230±10μs     0.55  bench_shape_base.Block.time_3d(10, 'block')
-        114±20μs         62.3±2μs     0.55  bench_lib.Pad.time_pad((10, 10, 10), (0, 5), 'constant')
-      5.76±0.1μs      3.13±0.08μs     0.54  bench_core.CorrConv.time_convolve(50, 10, 'same')
-      5.30±0.1μs      2.84±0.08μs     0.54  bench_core.CorrConv.time_correlate(50, 100, 'valid')
-        92.5±4μs         49.3±1μs     0.53  bench_shape_base.Block2D.time_block2d((256, 256), 'uint32', (2, 2))
-        13.5±3μs       7.07±0.2μs     0.52  bench_reduce.MinMax.time_min(<type 'numpy.float32'>)
-        7.66±1μs       3.88±0.2μs     0.51  bench_core.CorrConv.time_convolve(50, 100, 'valid')
-        29.0±3μs       14.5±0.8μs     0.50  bench_shape_base.Block.time_no_lists(10)
-      6.62±0.3μs       3.30±0.2μs     0.50  bench_core.CorrConv.time_convolve(1000, 1000, 'valid')
-        74.2±7μs       36.2±0.9μs     0.49  bench_shape_base.Block2D.time_block2d((256, 256), 'uint16', (2, 2))
-      5.55±0.3μs       2.70±0.2μs     0.49  bench_core.CorrConv.time_convolve(50, 10, 'valid')
-       73.9±20μs         35.8±2μs     0.48  bench_lib.Pad.time_pad((10, 100), 1, 'reflect')
-        224±20μs          107±7μs     0.48  bench_shape_base.Block2D.time_block2d((256, 256), 'uint64', (4, 4))
-      3.87±0.1μs      1.83±0.06μs     0.47  bench_core.CountNonzero.time_count_nonzero(2, 100, <type 'str'>)
-        109±30μs         51.5±3μs     0.47  bench_lib.Pad.time_pad((10, 10, 10), (0, 5), 'edge')
-        240±20μs          112±4μs     0.47  bench_shape_base.Block2D.time_block2d((512, 512), 'uint16', (4, 4))
-        337±40μs          158±7μs     0.47  bench_shape_base.Block2D.time_block2d((512, 512), 'uint32', (4, 4))
-         188±8μs         88.0±2μs     0.47  bench_shape_base.Block2D.time_block2d((512, 512), 'uint8', (4, 4))
-      4.39±0.2μs      2.04±0.09μs     0.47  bench_core.CountNonzero.time_count_nonzero(3, 10000, <type 'bool'>)
-        73.2±4μs       33.9±0.5μs     0.46  bench_shape_base.Block2D.time_block2d((128, 128), 'uint64', (2, 2))
-        5.48±1μs       2.44±0.1μs     0.45  bench_core.CountNonzero.time_count_nonzero(2, 100, <type 'object'>)
-      4.46±0.1μs      1.97±0.08μs     0.44  bench_core.CorrConv.time_correlate(50, 10, 'full')
-        30.4±9μs       13.3±0.3μs     0.44  bench_shape_base.Block.time_no_lists(1)
-      7.05±0.2μs      3.05±0.06μs     0.43  bench_reduce.SmallReduction.time_small
-        7.35±1μs       3.12±0.2μs     0.42  bench_core.CorrConv.time_convolve(50, 10, 'full')
-      4.36±0.1μs      1.84±0.07μs     0.42  bench_core.CorrConv.time_correlate(50, 10, 'same')
-      3.51±0.2μs      1.46±0.05μs     0.42  bench_core.CountNonzero.time_count_nonzero(1, 100, <type 'object'>)
-     4.03±0.05μs       1.66±0.1μs     0.41  bench_core.CorrConv.time_correlate(1000, 1000, 'valid')
-        199±10μs         80.1±3μs     0.40  bench_shape_base.Block2D.time_block2d((256, 256), 'uint32', (4, 4))
-      3.98±0.2μs      1.60±0.08μs     0.40  bench_core.CountNonzero.time_count_nonzero(2, 10000, <type 'bool'>)
-        61.8±2μs         24.8±1μs     0.40  bench_shape_base.Block2D.time_block2d((256, 256), 'uint8', (2, 2))
-      4.13±0.1μs      1.62±0.05μs     0.39  bench_core.CorrConv.time_correlate(50, 10, 'valid')
-        61.6±2μs         23.9±1μs     0.39  bench_shape_base.Block2D.time_block2d((128, 128), 'uint32', (2, 2))
-        184±10μs         70.5±3μs     0.38  bench_shape_base.Block2D.time_block2d((256, 256), 'uint16', (4, 4))
-        56.1±4μs       21.0±0.9μs     0.38  bench_shape_base.Block2D.time_block2d((64, 64), 'uint64', (2, 2))
-        40.0±2μs       15.0±0.6μs     0.37  bench_shape_base.Block.time_block_simple_column_wise(10)
-         121±2μs         45.1±2μs     0.37  bench_shape_base.Block.time_nested(1)
-         179±4μs         66.1±4μs     0.37  bench_shape_base.Block2D.time_block2d((128, 128), 'uint64', (4, 4))
-        59.8±2μs         22.0±1μs     0.37  bench_shape_base.Block2D.time_block2d((128, 128), 'uint16', (2, 2))
-     3.19±0.05μs      1.17±0.02μs     0.37  bench_core.CountNonzero.time_count_nonzero(1, 100, <type 'str'>)
-        54.0±3μs         19.7±1μs     0.37  bench_shape_base.Block2D.time_block2d((32, 32), 'uint64', (2, 2))
-        56.9±1μs       20.7±0.7μs     0.36  bench_shape_base.Block2D.time_block2d((64, 64), 'uint32', (2, 2))
-      3.14±0.1μs      1.14±0.04μs     0.36  bench_core.CountNonzero.time_count_nonzero(1, 10000, <type 'bool'>)
-        92.7±2μs         33.7±2μs     0.36  bench_shape_base.Block.time_block_complicated(1)
-         104±4μs         37.8±1μs     0.36  bench_shape_base.Block.time_block_complicated(10)
-         128±5μs         45.5±2μs     0.36  bench_shape_base.Block.time_nested(10)
-       196±100μs         69.4±3μs     0.35  bench_ma.Concatenate.time_it('unmasked+masked', 2)
-         153±5μs         53.9±2μs     0.35  bench_shape_base.Block2D.time_block2d((128, 128), 'uint16', (4, 4))
-        39.4±2μs       13.8±0.5μs     0.35  bench_shape_base.Block.time_block_simple_column_wise(1)
-        53.5±2μs         18.7±1μs     0.35  bench_shape_base.Block2D.time_block2d((32, 32), 'uint8', (2, 2))
-        55.2±2μs       19.3±0.6μs     0.35  bench_shape_base.Block2D.time_block2d((32, 32), 'uint16', (2, 2))
-        16.9±1μs       5.89±0.5μs     0.35  bench_core.Core.time_dstack_l
-        60.6±3μs       21.1±0.6μs     0.35  bench_shape_base.Block2D.time_block2d((128, 128), 'uint8', (2, 2))
-      25.5±0.2μs       8.88±0.3μs     0.35  bench_shape_base.Block.time_block_simple_row_wise(10)
-        54.6±3μs       19.0±0.6μs     0.35  bench_shape_base.Block2D.time_block2d((16, 16), 'uint64', (2, 2))
-        52.6±2μs       18.2±0.7μs     0.35  bench_shape_base.Block2D.time_block2d((16, 16), 'uint16', (2, 2))
-        6.57±2μs      2.25±0.08μs     0.34  bench_core.CountNonzero.time_count_nonzero(3, 100, <type 'str'>)
-        24.3±1μs       8.30±0.6μs     0.34  bench_shape_base.Block.time_block_simple_row_wise(1)
-         148±3μs         50.0±3μs     0.34  bench_shape_base.Block2D.time_block2d((16, 16), 'uint32', (4, 4))
-         171±8μs         57.9±4μs     0.34  bench_shape_base.Block2D.time_block2d((256, 256), 'uint8', (4, 4))
-         159±5μs         53.8±1μs     0.34  bench_shape_base.Block2D.time_block2d((64, 64), 'uint64', (4, 4))
-        171±20μs         57.7±2μs     0.34  bench_shape_base.Block2D.time_block2d((128, 128), 'uint32', (4, 4))
-      3.15±0.3μs      1.06±0.03μs     0.34  bench_core.CountNonzero.time_count_nonzero(3, 100, <type 'int'>)
-        55.7±5μs       18.7±0.2μs     0.34  bench_shape_base.Block2D.time_block2d((16, 16), 'uint8', (2, 2))
-         158±7μs         52.6±3μs     0.33  bench_shape_base.Block2D.time_block2d((128, 128), 'uint8', (4, 4))
-         153±4μs         50.7±1μs     0.33  bench_shape_base.Block2D.time_block2d((32, 32), 'uint64', (4, 4))
-         152±7μs         50.3±1μs     0.33  bench_shape_base.Block2D.time_block2d((16, 16), 'uint8', (4, 4))
-        53.6±3μs       17.7±0.4μs     0.33  bench_shape_base.Block2D.time_block2d((16, 16), 'uint32', (2, 2))
-         156±4μs         51.4±3μs     0.33  bench_shape_base.Block2D.time_block2d((64, 64), 'uint8', (4, 4))
-         148±3μs         48.2±2μs     0.33  bench_shape_base.Block2D.time_block2d((16, 16), 'uint16', (4, 4))
-        160±10μs         52.0±1μs     0.33  bench_shape_base.Block2D.time_block2d((64, 64), 'uint32', (4, 4))
-         159±8μs         51.4±3μs     0.32  bench_shape_base.Block2D.time_block2d((64, 64), 'uint16', (4, 4))
-        59.8±3μs         19.3±1μs     0.32  bench_shape_base.Block2D.time_block2d((32, 32), 'uint32', (2, 2))
-         153±4μs         49.4±2μs     0.32  bench_shape_base.Block2D.time_block2d((32, 32), 'uint32', (4, 4))
-      15.6±0.6μs       5.03±0.3μs     0.32  bench_core.Core.time_vstack_l
-         154±7μs         49.7±2μs     0.32  bench_shape_base.Block2D.time_block2d((32, 32), 'uint8', (4, 4))
-        59.6±6μs       19.1±0.8μs     0.32  bench_shape_base.Block2D.time_block2d((64, 64), 'uint8', (2, 2))
-      3.03±0.4μs         969±30ns     0.32  bench_core.CountNonzero.time_count_nonzero(2, 100, <type 'int'>)
-        120±10μs         38.4±2μs     0.32  bench_shape_base.Block.time_3d(1, 'block')
-         156±5μs         49.3±1μs     0.32  bench_shape_base.Block2D.time_block2d((16, 16), 'uint64', (4, 4))
-        164±10μs         49.3±2μs     0.30  bench_shape_base.Block2D.time_block2d((32, 32), 'uint16', (4, 4))
-       65.7±10μs       19.6±0.7μs     0.30  bench_shape_base.Block2D.time_block2d((64, 64), 'uint16', (2, 2))
-     2.82±0.08μs         732±30ns     0.26  bench_core.CountNonzero.time_count_nonzero(1, 100, <type 'int'>)
-     2.77±0.07μs         664±30ns     0.24  bench_core.CountNonzero.time_count_nonzero(2, 100, <type 'bool'>)
-      2.61±0.1μs         624±20ns     0.24  bench_core.CountNonzero.time_count_nonzero(1, 100, <type 'bool'>)
-        16.8±3μs       3.97±0.2μs     0.24  bench_core.Core.time_hstack_l
-      2.78±0.1μs         637±20ns     0.23  bench_core.CountNonzero.time_count_nonzero(3, 100, <type 'bool'>)
-      2.36±0.2μs          207±5ns     0.09  bench_overrides.ArrayFunction.time_mock_broadcast_to_numpy
-      2.68±0.1μs          221±7ns     0.08  bench_overrides.ArrayFunction.time_mock_concatenate_numpy
-      2.58±0.1μs         201±10ns     0.08  bench_overrides.ArrayFunction.time_mock_broadcast_to_duck
-      3.02±0.2μs          222±6ns     0.07  bench_overrides.ArrayFunction.time_mock_concatenate_duck
-      4.29±0.3μs          216±6ns     0.05  bench_overrides.ArrayFunction.time_mock_concatenate_mixed
-        142±20μs          213±8ns     0.00  bench_overrides.ArrayFunction.time_mock_concatenate_many

SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY.

راجع أيضًا https://docs.google.com/spreadsheets/d/15-AFI_cmZqfkU6mo2p1znsQF2E52PEXpF68QqYqEar4/edit#gid = 0 للحصول على جدول بيانات.

ليس من المستغرب أن يكون الاختلاف الأكبر في الأداء للوظائف التي تستدعي وظائف numpy أخرى داخليًا عدة مرات ، على سبيل المثال ، لـ np.block() .

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

shoyer - لقد ذكرهما هنا أيضًا:

  1. هل يجب تضمين كافة الأنواع الفريدة من الوسائط التي تشبه المصفوفة في types ؟ (وليس مجرد الحجج التي توفر تجاوزًا). قد يبدو من المفيد معرفة عمليات التنفيذ. (انظر # 12327).
  2. هل يجب أن يقبل تطبيق ndarray.__array_function__ الفئات الفرعية حتى لو تجاوزت __array_function__ ؟ سيكون هذا معقولًا نظرًا لمبدأ استبدال Liskov وبالنظر إلى أن الفئة الفرعية لديها بالفعل فرصة للانقاذ. قد يعني ذلك استدعاء التنفيذ بدلاً من الوظيفة العامة داخل ndarray.__array_function__ . (وشيء مشابه في __array_ufunc__ ...) انظر # 12328 لتجربة مقابل __array_function__ فقط.

shoyer - راجع # 12327 للحصول على تنفيذ سريع لـ (1) - إذا

و # 12328 لتجربة (2) ، لترى في الغالب كيف يبدو.

أنا +1 على كلا التعديلين هنا.

ظهر اسم وظائف المرسل في رسائل الخطأ مرة أخرى في https://github.com/numpy/numpy/pull/12789 ، حيث فوجئ شخص ما برؤية TypeError: _pad_dispatcher missing 1 required positional argument

بالإضافة إلى البدائل الموضحة أعلاه https://github.com/numpy/numpy/issues/12028#issuecomment -429377396 (نستخدم حاليًا 2) ، سأضيف خيارًا رابعًا:

الخيار 4 : اكتب مرسل منفصل لكل وظيفة ، بنفس اسم الوظيفة:

def sin(a):
    return (a,)


@array_function_dispatch(sin)
def sin(a):
     ...


def cos(a):
    return (a,)


@array_function_dispatch(cos)
def cos(a):
    ...

مزايا:

  • توفر Python الآن دائمًا أسماء الوظائف الصحيحة في رسالة الخطأ.

سلبيات:

  • المزيد من تكرار الكود
  • المزيد من المراوغة - انها لم يعد واضحا وهو اسم الدالة pad تلقى الحجج خاطئة (لكننا إجراء اختبارات للتحقق من أنها يتم الاحتفاظ بها في مزامنة).

أعتقد أنه من أجل الحفاظ على عمل الكود الحالي ، يجب أن تأتي الوظيفة الفعلية _after_ المرسل.

حسنًا ، لكن يمكننا إعطائها نفس اسم المرسل. سيتم الكتابة فوق اسم المرسل.

سيكون من الرائع أن تكون قادرًا على تحديد إرسال مخصص لوظيفة مثل np.arange أو np.empty.

أعتقد أن أحد الخيارات هو إرسال NumPy على العددية وكذلك المصفوفات. هل هذا يتعارض مع السياسة الاقتصادية الجديدة؟ هل أي شيء يقطع هذا التغيير؟

للمناقشة حول np.arange ، راجع https://github.com/numpy/numpy/issues/12379.

لا أرى كيف يمكن أن يقوم np.empty() بالإرسال - لا يوجد شيء للإرسال ، مجرد شكل ونوع. ولكن من المؤكد أن np.empty_like() يمكنه إرسال شكل مكتوب - وهذا هو بالضبط ما يدور https://github.com/numpy/numpy/pull/13046 حول دعمه.

الخيار 4 : اكتب مرسل منفصل لكل وظيفة ، بنفس اسم الوظيفة:

أي اعتراضات على هذا الخيار؟ أعتقد أنه من المحتمل أن يكون الخيار الأكثر صداقة من منظور المستخدم.

لا أرى كيف يمكن لـ np.empty () القيام بالإرسال - لا يوجد شيء للإرسال ، مجرد شكل ونوع dtype

قد ترغب في إرسال أي من هؤلاء. على سبيل المثال ، إليك كائن شكل مخصص ، قد نرغب في إرساله بشكل مختلف.

Screen Shot 2019-04-03 at 1 06 46 PM

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

class ExprShape:
    def __getitem__(self, i):
        return ('getitem', self, i)
    def __len__(self):
        return ('len', self)

numpy.empty(ExprShape())

الذي أود تجاوزه لإرجاع شيء مثل ExprArray('empty', ExprShape()) .

نعم ، من حيث المبدأ يمكننا أن ننتقل بالشكل أيضًا. سيضيف ذلك تعقيدًا إضافيًا / عبء إضافي إلى البروتوكول. هل لديك حالات استخدام لا يكفي فيها استخدام مصفوفة كقالب (مثل empty_like مع shape

في حالات أخرى أستطيع أن أفكر في هو size حجة ل np.random.RandomState الأساليب، ولكن لاحظ أننا حاليا لا تدعم تلك على الإطلاق - راجع http://www.numpy.org/ neps / nep-0018-array-function-protocol.html # callable -objects-created-at-runtime

هل لديك حالات استخدام لا يكفي فيها استخدام مصفوفة كقالب (مثل فارغ _ مثل مع شكل)؟

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

على سبيل المثال ، لنفترض أننا كنا نحاول استدعاء scipy.optimize.differential_evolution باستخدام مصفوفات NP مثل المصفوفات ، التي تنشئ رسمًا بيانيًا للمكالمات بدلاً من تنفيذها على الفور.

يمكنك أن ترى هنا أنه سيكون من المفيد إذا تمكنا من تغيير np.full لإنشاء مصفوفة رمزية بدلاً من مصفوفة افتراضية ، إذا كان الإدخال الذي تم تمريره إليه رمزيًا أيضًا.

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

هذا غير ممكن بشكل عام. من المؤكد أن إنشاء مجموعة صريحة مثل np.array() سيحتاج إلى إعادة كتابته ليكون متوافقًا مع كتابة البط.

في هذه الحالة ، يبدو تبديل energies = np.full(num_members, np.inf) إلى energies = np.full_like(population, np.inf, shape=num_members) تغييرًا سهلاً ومقروءًا.

هذا غير ممكن بشكل عام. إن إنشاء المصفوفة الصريحة مثل np.array () سيحتاج بالتأكيد إلى إعادة كتابته ليكون متوافقًا مع كتابة البط.

هل هناك اقتراح حول إجراء هذا النوع من التغيير أم أنك تقول إن دعم إرسال np.array سيكون صعبًا حقًا ولذا لا يمكننا الحصول على دعم بنسبة 100٪؟

في هذه الحالة ، يبدو تبديل الطاقات = np.full (num_members، np.inf) إلى طاقات = np.full_like (السكان ، np.inf ، الشكل = num_members) تغييرًا سهلاً ويمكن قراءته.

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

هناك طرق أخرى لتزويد المستخدمين بهذه التجربة مثل:

  • توفير وحدة جديدة تعمل مثل numpy ولكنها تتصرف بالطريقة التي تريدها. يتطلب من المستخدمين تغيير وارداتهم
  • افحص المصدر لفهم السلوك. علاء نومبا أو الظل.

قد يكون كلا الخيارين مطلوبًا في حالات معينة (مثل السماح للمستخدمين بالاتصال بـ np.full وإرجاع نتيجة رمزية حاليًا) ، ولكن إذا فهمت بشكل صحيح ، فإن الهدف من NEP-18 هو محاولة الحد عند الحاجة. والسماح للأشخاص باستخدام NumPy الأصلي في المزيد من الحالات.

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

هل هناك اقتراح حول إجراء هذا النوع من التغيير أم أنك تقول إن دعم إرسال np.array سيكون صعبًا حقًا ولذا لا يمكننا الحصول على دعم بنسبة 100٪؟

يناقش NEP 22 الخيارات هنا. لا أعتقد أنه يمكننا تغيير دلالات np.asarray() بأمان لإرجاع أي شيء بخلاف كائن numpy.ndarray - سنحتاج إلى بروتوكول جديد لهذا الغرض.

تكمن المشكلة في أن np.asarray() حاليًا هو الطريقة الاصطلاحية للإرسال إلى كائن مصفوفة numpy ، والذي يستخدم ويتوقع أن يتطابق تمامًا مع numpy.ndarray ، على سبيل المثال ، وصولاً إلى تخطيط الذاكرة.

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

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

نعم. لا يُقصد من NEP 18 أن يكون حلاً كاملاً لبدائل NumPy المنسدلة ، ولكنه خطوة في هذا الاتجاه.

لقد قمت بصياغة مراجعة لـ NEP-18 لإضافة سمة __numpy_implementation__ :
https://github.com/numpy/numpy/pull/13305

يخطر ببالي أننا ننسى تشويه الوظائف في numpy.testing : https://github.com/numpy/numpy/issues/13588

سأفعل ذلك قريبًا ...

هناك مراجعة واحدة أود رؤيتها في NEP ، على وجه التحديد لتوضيح ما يضمن عروض NEP-18 لمؤلفي الفئات الفرعية: https://github.com/numpy/numpy/pull/13633

لقد حددت مهام قابلية الاستخدام مكتملة منذ أن تم إصلاح gh-13329. قررنا- # 13588 يمكن الانتظار حتى ما بعد إصدار 1.17. هذا يترك تحسينات الوثائق و arange gh-12379 لا يزال مفتوحًا للتضمين في 1.17.

هناك أيضًا # 13728 - خطأ في المرسل مقابل histogram[2d]d

هذا يترك تحسينات الوثائق و arange gh-12379 لا يزال مفتوحًا للإدراج في 1.17.

كانت هناك مشكلة في التوثيق مفقودة ، لذلك فتحت gh-13844. أعتقد أن المستندات أهم بكثير من المشكلة المفتوحة arange .

@ shoyer هل يمكننا إغلاق هذا؟

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

Kreol64 picture Kreol64  ·  3تعليقات

MareinK picture MareinK  ·  3تعليقات

marcocaccin picture marcocaccin  ·  4تعليقات

inducer picture inducer  ·  3تعليقات

toddrjen picture toddrjen  ·  4تعليقات