यदि कोई वस्तु एक संख्या है, तो यह जांचने का सबसे पैथोनिक तरीका क्या है?


114

एक मनमानी अजगर वस्तु को देखते हुए, यह निर्धारित करने का सबसे अच्छा तरीका है कि क्या यह एक संख्या है? यहाँ isके रूप में परिभाषित किया गया है acts like a number in certain circumstances

उदाहरण के लिए, मान लें कि आप एक वेक्टर क्लास लिख रहे हैं। यदि एक और वेक्टर दिया जाता है, तो आप डॉट उत्पाद खोजना चाहते हैं। यदि एक स्केलर दिया जाता है, तो आप पूरे वेक्टर को स्केल करना चाहते हैं।

जाँच हो रही है अगर कुछ है int, float, long, boolकष्टप्रद है और उपयोगकर्ता परिभाषित वस्तुओं है कि संख्या की तरह काम कर सकते हैं कवर नहीं करता। लेकिन, __mul__उदाहरण के लिए, जाँच करना बहुत अच्छा नहीं है क्योंकि मेरे द्वारा वर्णित वेक्टर क्लास परिभाषित होगी __mul__, लेकिन यह उस तरह की संख्या नहीं होगी जैसा मैं चाहता हूँ।

जवाबों:


135

परीक्षण करने के Numberलिए numbersमॉड्यूल से उपयोग करें isinstance(n, Number)(2.6 के बाद से उपलब्ध)।

>>> from numbers import Number
... from decimal import Decimal
... from fractions import Fraction
... for n in [2, 2.0, Decimal('2.0'), complex(2, 0), Fraction(2, 1), '2']:
...     print(f'{n!r:>14} {isinstance(n, Number)}')
              2 True
            2.0 True
 Decimal('2.0') True
         (2+0j) True
 Fraction(2, 1) True
            '2' False

यह, निश्चित रूप से, बतख टाइपिंग के विपरीत है। यदि आप इस बारे में अधिक चिंतित हैं कि कोई वस्तु क्या है इसके बजाय यह कैसे काम करती है , तो अपना संचालन करें जैसे कि आपके पास एक संख्या है और अपवादों का उपयोग करें अन्यथा आपको बताएं।


3
स्मार्ट बात कर रही है, बल्कि बतख बात से, पसंद किया जाता है जब आप एक्स से एक सदिश गुणा कर रहे हैं इस मामले तुम क्या एक्स के आधार पर अलग अलग बातें करना चाहता हूँ में है । (यह उस चीज के रूप में कार्य कर सकता है जो गुणा करता है, लेकिन परिणाम निरर्थक हो सकता है।)
एवगेनी सर्गेव

3
यह उत्तर देता है कि यह सच है कि एक संख्या है .. जो संभवतः हमेशा नहीं है जो आप चाहते हैं। मल त्यागने के लिए (लगता है कि सत्यापन फे), मैं कहूंगाisinstance(value, Number) and type(value) != bool
यो लुडके

32

आप जांचना चाहते हैं कि क्या कोई वस्तु है

कुछ परिस्थितियों में संख्या की तरह काम करता है

यदि आप पायथन 2.5 या पुराने का उपयोग कर रहे हैं, तो एकमात्र वास्तविक तरीका उन "कुछ परिस्थितियों" की जांच करना और देखना है।

2.6 या बेहतर में, आप नंबरों केisinstance साथ उपयोग कर सकते हैं। निंबर - एक सार बेस क्लास (एबीसी) जो इस उद्देश्य के लिए बिल्कुल मौजूद है (बहुत अधिक एबीसी collectionsसंग्रह / कंटेनरों के विभिन्न रूपों के लिए मॉड्यूल में मौजूद हैं , फिर से 2.6 के साथ शुरू होता है; और;) केवल उन रिलीज में भी, आप आसानी से अपने स्वयं के सार आधार वर्गों को जोड़ सकते हैं यदि आपको आवश्यकता है)।

2.5 और उससे पहले बाख, "को जोड़ा जा सकता है 0और यह चलने योग्य नहीं है" कुछ मामलों में एक अच्छी परिभाषा हो सकती है। लेकिन, क्या तुम सच में अपने आप से पूछना करने के लिए, कि यह क्या है कि आप पूछ रहे हैं कि क्या आप पर विचार करना चाहते "एक नंबर" निश्चित रूप से करने के लिए सक्षम होना चाहिए की जरूरत करना है, और क्या यह बिल्कुल होना चाहिए असमर्थ और जाँच - क्या करना है।

2.6 या बाद में इसकी आवश्यकता हो सकती है, शायद अपने स्वयं के पंजीकरण बनाने के उद्देश्य से आप उन प्रकारों को जोड़ते हैं जिनके बारे में आप पहले से पंजीकृत नहीं हैं numbers.Numbers- यदि आप कुछ प्रकारों को बाहर करना चाहते हैं जो दावा करते हैं कि वे संख्याएं हैं, लेकिन आप बस नहीं संभाल सकता है, कि और भी अधिक देखभाल करता है, क्योंकि एबीसी के पास कोई unregisterतरीका नहीं है [[उदाहरण के लिए आप अपना खुद का एबीसी बना सकते हैं WeirdNumऔर वहां इस तरह के सभी अजीब-से-प्रकार दर्ज कर सकते हैं, फिर isinstanceआगे बढ़ने से पहले जमानत के लिए पहले जांच लें isinstanceसामान्य रूप numbers.Numberसे सफलतापूर्वक जारी रखने के लिए जाँच करना।

BTW, अगर और जब आपको जांचने की आवश्यकता है xकि क्या कुछ कर सकते हैं या नहीं कर सकते हैं, तो आपको आम तौर पर कुछ ऐसा करने की कोशिश करनी होगी:

try: 0 + x
except TypeError: canadd=False
else: canadd=True

__add__प्रति se की उपस्थिति आपको कुछ भी उपयोगी नहीं बताती है, जैसे कि सभी अनुक्रमों में अन्य अनुक्रमों के साथ संयोजन के उद्देश्य से है। यह चेक परिभाषा के बराबर है "एक संख्या कुछ ऐसी है कि इस तरह की चीजों का एक क्रम अंतर्निहित फ़ंक्शन के लिए एक वैध एकल तर्क है sum", उदाहरण के लिए। पूरी तरह से अजीब प्रकार (उदाहरण के लिए, जो 0 में अभिव्यक्त होने पर "गलत" अपवाद को बढ़ाते हैं, जैसे कि, कहते हैं, एक ZeroDivisionErrorया ValueErrorसी) अपवाद का प्रचार करेंगे, लेकिन यह ठीक है, उपयोगकर्ता को ASAP बताएं कि ऐसे पागल प्रकार केवल अच्छे में स्वीकार्य नहीं हैं कंपनी ;-); लेकिन, एक "वेक्टर" जो एक स्केलर के लिए योग्य है (पायथन के मानक पुस्तकालय में एक नहीं है, लेकिन निश्चित रूप से वे तीसरे पक्ष के एक्सटेंशन के रूप में लोकप्रिय हैं) यहां भी गलत परिणाम देगा, इसलिए (जैसे"अनुमति नहीं दी जा सकती है" एक (उदाहरण के लिए, चेक जो iter(x)उठाता है TypeError, या विशेष पद्धति की उपस्थिति के लिए __iter__- यदि आप 2.5 या इससे पहले के हैं और इस प्रकार आपको अपने स्वयं के चेक की आवश्यकता है)।

इस तरह की जटिलताओं पर एक संक्षिप्त झलक आपको जब भी संभव हो, सार आधार वर्गों पर भरोसा करने के लिए प्रेरित करने के लिए पर्याप्त हो सकती है ... ;-)।


लेकिन संख्या मॉड्यूल में संख्या के लिए एक एबीसी है। डॉक्स का दावा है: "संख्या मॉड्यूल (PEP 3141) संख्यात्मक सार आधार वर्गों की एक पदानुक्रम को परिभाषित करता है जो उत्तरोत्तर अधिक संचालन को परिभाषित करता है।"
स्टीवन रंबलस्की

17

यह एक अच्छा उदाहरण है जहां अपवाद वास्तव में चमकते हैं। बस आप संख्यात्मक प्रकार के साथ क्या करेंगे और TypeErrorबाकी सब चीज़ों को पकड़ें।

लेकिन जाहिर है, यह केवल जांच करता है कि क्या कोई ऑपरेशन काम करता है , न कि यह समझ में आता है ! इसके लिए एकमात्र वास्तविक समाधान यह है कि कभी भी प्रकारों को न मिलाएं और हमेशा यह जानें कि आपके मान किस टाइप के हैं।


1
बतख टंकण के लिए +1: इससे कोई फर्क नहीं पड़ता कि मेरा डेटा किस प्रकार का है, बस मैं वह कर सकता हूं या नहीं जो मैं इसके साथ चाहता हूं।
systempuntoout

12
यह पारंपरिक दृष्टिकोण था, लेकिन ABC को शुद्ध बतख टाइपिंग से दूर करने के लिए और कुछ दूरी को दुनिया की ओर स्थानांतरित करने के लिए अच्छे हिस्से में पेश किया गया है, जहां isinstanceवास्तव में कई मामलों में उपयोगी हो सकता है (== "यह समझ में आता है" और साथ ही औपचारिक प्रयोज्यता के संचालन)। लंबे समय तक पायथन-केवल लोगों के लिए कठिन बदलाव, लेकिन पायथन के दर्शन में एक बहुत ही महत्वपूर्ण प्रवृत्ति है कि इसे अनदेखा करना एक गंभीर त्रुटि होगी।
एलेक्स मार्टेली

@ एलेक्स: ट्रू और आई टाइपक्लासेस (ज्यादातर collections.Sequenceऔर दोस्तों) से प्यार करते हैं । लेकिन afaik, संख्या, वैक्टर या किसी भी अन्य गणितीय वस्तुओं के लिए ऐसी कक्षाएं नहीं हैं।
जोहान रिट्जेल

1
बतख टाइपिंग के खिलाफ कुछ भी नहीं। यह मैं क्या करूँगा। लेकिन संख्याओं के लिए एक सार आधार वर्ग है: संख्या। नम्बर।
स्टीवन रूमालस्की

4

वस्तु को शून्य से गुणा करें। कोई भी संख्या शून्य शून्य है। किसी अन्य परिणाम का अर्थ है कि वस्तु एक संख्या नहीं है (अपवादों सहित)

def isNumber(x):
    try:
        return bool(0 == x*0)
    except:
        return False

.Number का उपयोग करना इस प्रकार निम्नलिखित आउटपुट देगा:

class A: pass 

def foo(): return 1

for x in [1,1.4, A(), range(10), foo, foo()]:
    answer = isNumber(x)
    print('{answer} == isNumber({x})'.format(**locals()))

आउटपुट:

True == isNumber(1)
True == isNumber(1.4)
False == isNumber(<__main__.A instance at 0x7ff52c15d878>)
False == isNumber([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
False == isNumber(<function foo at 0x7ff52c121488>)
True == isNumber(1)

दुनिया में शायद कुछ गैर-संख्याएं हैं जो __mul__शून्य से गुणा करने पर शून्य पर लौटने को परिभाषित करती हैं लेकिन यह एक चरम अपवाद है। यह समाधान सभी को शामिल करना चाहिए सामान्य और समझदार कोड है कि आप उत्पन्न / encouter।

numpy.array उदाहरण:

import numpy as np

def isNumber(x):
    try:
        return bool(x*0 == 0)
    except:
        return False

x = np.array([0,1])

answer = isNumber(x)
print('{answer} == isNumber({x})'.format(**locals()))

उत्पादन:

False == isNumber([0 1])

5
True * 0 == 0
एंडोलिथ

4
आपका कार्य गलत रूप से कहेगा कि
बूलियन

1
@endolith, बूलियन बिल्कुल नंबरों की तरह काम करते हैं। सच हमेशा == 1 और हमेशा गलत == 0. यह बिल्कुल सवाल पूछने वाला है, "यहाँ 'को' कुछ परिस्थितियों में संख्या की तरह काम करता है 'के रूप में परिभाषित किया गया है।"
shrewmouse

1
@endolith, वास्तव में, बूलियन नंबर हैं। बूलियन व्युत्पन्न intइसलिए मेरे कार्य सही ढंग से कहेंगे कि बूलियन संख्याएं हैं।
1933 में 19

1
@ निकोलसएब्रिल, 0 * x == 0 को isnumber के अंदर एक बूल में बदलें।
19

3

अपने प्रश्न को फिर से समझने के लिए, आप यह निर्धारित करने की कोशिश कर रहे हैं कि क्या कुछ संग्रह या एक मूल्य है। यह तुलना करने की कोशिश करना कि क्या कोई वेक्टर है या एक नंबर सेब की तुलना संतरे से कर रहा है - मेरे पास तार या संख्या का एक वेक्टर हो सकता है, और मेरे पास एक स्ट्रिंग या एकल संख्या हो सकती है। आप कितने (1 या अधिक) में रुचि रखते हैं , न कि आपके पास वास्तव में किस प्रकार का है।

इस समस्या का मेरा समाधान यह देखना है कि इनपुट एकल मान है या संग्रह की उपस्थिति की जाँच करके __len__। उदाहरण के लिए:

def do_mult(foo, a_vector):
    if hasattr(foo, '__len__'):
        return sum([a*b for a,b in zip(foo, a_vector)])
    else:
        return [foo*b for b in a_vector]

या, बतख-टाइपिंग दृष्टिकोण के लिए, आप fooपहले पर पुनरावृत्ति करने की कोशिश कर सकते हैं :

def do_mult(foo, a_vector):
    try:
        return sum([a*b for a,b in zip(foo, a_vector)])
    except TypeError:
        return [foo*b for b in a_vector]

अंततः, यह परीक्षण करना आसान है कि क्या कुछ वेक्टर-जैसा है, यह परीक्षण करने की तुलना में कि क्या कुछ स्केलर जैसा है। यदि आपके पास आने वाले विभिन्न प्रकार (यानी स्ट्रिंग, संख्यात्मक, आदि) के मान हैं, तो आपके कार्यक्रम के तर्क को कुछ काम की आवश्यकता हो सकती है - आपने पहली बार एक संख्यात्मक वेक्टर द्वारा एक स्ट्रिंग को गुणा करने की कोशिश कैसे की?


3

मौजूदा तरीकों का सारांश / मूल्यांकन करने के लिए:

Candidate    | type                      | delnan | mat | shrewmouse | ant6n
-------------------------------------------------------------------------
0            | <type 'int'>              |      1 |   1 |          1 |     1
0.0          | <type 'float'>            |      1 |   1 |          1 |     1
0j           | <type 'complex'>          |      1 |   1 |          1 |     0
Decimal('0') | <class 'decimal.Decimal'> |      1 |   0 |          1 |     1
True         | <type 'bool'>             |      1 |   1 |          1 |     1
False        | <type 'bool'>             |      1 |   1 |          1 |     1
''           | <type 'str'>              |      0 |   0 |          0 |     0
None         | <type 'NoneType'>         |      0 |   0 |          0 |     0
'0'          | <type 'str'>              |      0 |   0 |          0 |     1
'1'          | <type 'str'>              |      0 |   0 |          0 |     1
[]           | <type 'list'>             |      0 |   0 |          0 |     0
[1]          | <type 'list'>             |      0 |   0 |          0 |     0
[1, 2]       | <type 'list'>             |      0 |   0 |          0 |     0
(1,)         | <type 'tuple'>            |      0 |   0 |          0 |     0
(1, 2)       | <type 'tuple'>            |      0 |   0 |          0 |     0

(मैं इस सवाल से यहाँ आया था )

कोड

#!/usr/bin/env python

"""Check if a variable is a number."""

import decimal


def delnan_is_number(candidate):
    import numbers
    return isinstance(candidate, numbers.Number)


def mat_is_number(candidate):
    return isinstance(candidate, (int, long, float, complex))


def shrewmouse_is_number(candidate):
    try:
        return 0 == candidate * 0
    except:
        return False


def ant6n_is_number(candidate):
    try:
        float(candidate)
        return True
    except:
        return False

# Test
candidates = (0, 0.0, 0j, decimal.Decimal(0),
              True, False, '', None, '0', '1', [], [1], [1, 2], (1, ), (1, 2))

methods = [delnan_is_number, mat_is_number, shrewmouse_is_number, ant6n_is_number]

print("Candidate    | type                      | delnan | mat | shrewmouse | ant6n")
print("-------------------------------------------------------------------------")
for candidate in candidates:
    results = [m(candidate) for m in methods]
    print("{:<12} | {:<25} | {:>6} | {:>3} | {:>10} | {:>5}"
          .format(repr(candidate), type(candidate), *results))

खुद के लिए TODO:, float('nan'), 'nan', '123.45', '42', '42a', '0x8', '0xa'जोड़ेंmath.isnan
मार्टिन थोमा

2

संभवतः यह बेहतर है कि आप इसे दूसरे तरीके से करें: आप जाँचते हैं कि यह एक वेक्टर है या नहीं। यदि यह है, तो आप एक डॉट उत्पाद करते हैं और अन्य सभी मामलों में आप स्केलर गुणन का प्रयास करते हैं।

वेक्टर की जांच करना आसान है, क्योंकि यह आपके वेक्टर वर्ग प्रकार (या इससे विरासत में मिला हुआ) का होना चाहिए। आप केवल एक डॉट-उत्पाद करने के लिए पहले प्रयास कर सकते हैं, और यदि वह विफल रहता है (= यह वास्तव में एक वेक्टर नहीं था), तो स्केलर गुणा पर वापस गिरें।


1

बस जोड़ने के लिए। शायद हम isinstance और isdigit के संयोजन का उपयोग इस प्रकार कर सकते हैं कि क्या कोई मान एक संख्या है (int, float, आदि)

यदि आइंस्टीन (num1, int) या आइंस्टीन (num1, फ्लोट) या num1.isdigit ():


0

काल्पनिक वेक्टर वर्ग के लिए:

मान लीजिए vकि एक सदिश राशि है, और हम इसे गुणा कर रहे हैं x। यदि यह प्रत्येक घटक को गुणा करने के लिए समझ में आता vहैx , तो हम शायद इसका मतलब है, इसलिए पहले प्रयास करें। यदि नहीं, तो शायद हम डॉट कर सकते हैं? अन्यथा यह एक प्रकार की त्रुटि है।

EDIT - नीचे दिया गया कोड काम नहीं करता है, क्योंकि 2*[0]==[0,0]इसके बजाय a TypeError। मैं इसे छोड़ देता हूं क्योंकि यह टिप्पणी की गई थी।

def __mul__( self, x ):
    try:
        return [ comp * x for comp in self ]
    except TypeError:
        return [ x * y for x, y in itertools.zip_longest( self, x, fillvalue = 0 )

अगर xएक वेक्टर है तो [comp * x for comp in self]के बाहरी उत्पाद निकलेगा xएक v। यह रैंक 2 टेंसर है, स्केलर नहीं है।
अरोनस्टरलिंग

"नहीं स्केलर" को "वेक्टर नहीं" बदलें। कम से कम मूल वेक्टर अंतरिक्ष में नहीं।
आराओनस्टरलिंग

हे, वास्तव में हम दोनों गलत हैं। आपको लगता है कि यह सोचते रहे comp*xस्केल करेगा xद्वारा comp, मैं यह सोचते गया था कि यह एक लेखन त्रुटि उठाएंगे। दुर्भाग्य से, यह वास्तव xमें खुद के compसमय के साथ घनीभूत होगा । उफ़।
कैटरियल

हुंह। अगर xएक सदिश राशि है तो उसमें एक __rmul__विधि ( __rmul__ = __mul__) comp * xहोनी चाहिए ताकि वह xउसी तरह x * compसे मापनी चाहिए , जैसा कि जाहिर है।
२०

0

मेरे पास एक समान मुद्दा था, जब एक प्रकार का वेक्टर वर्ग लागू किया गया था। किसी संख्या की जांच करने का एक तरीका सिर्फ एक को परिवर्तित करना है, अर्थात उपयोग करके

float(x)

यह उन मामलों को अस्वीकार करना चाहिए जहां x को किसी संख्या में परिवर्तित नहीं किया जा सकता है; लेकिन अन्य प्रकार की संख्या जैसी संरचनाओं को भी अस्वीकार कर सकता है जो मान्य हो सकते हैं, उदाहरण के लिए जटिल संख्या।


0

यदि आप तर्क प्रकार (ओं) के आधार पर विभिन्न तरीकों को कॉल करना चाहते हैं, तो देखें multipledispatch

उदाहरण के लिए, मान लें कि आप एक वेक्टर क्लास लिख रहे हैं। यदि एक और वेक्टर दिया जाता है, तो आप डॉट उत्पाद खोजना चाहते हैं। यदि एक स्केलर दिया जाता है, तो आप पूरे वेक्टर को स्केल करना चाहते हैं।

from multipledispatch import dispatch

class Vector(list):

    @dispatch(object)
    def __mul__(self, scalar):
        return Vector( x*scalar for x in self)

    @dispatch(list)
    def __mul__(self, other):
        return sum(x*y for x,y in zip(self, other))


>>> Vector([1,2,3]) * Vector([2,4,5])   # Vector time Vector is dot product
25
>>> Vector([1,2,3]) * 2                 # Vector times scalar is scaling
[2, 4, 6]

दुर्भाग्य से, (मेरे ज्ञान के अनुसार) हम लिख नहीं सकते @dispatch(Vector)क्योंकि हम अभी भी प्रकार को परिभाषित कर रहे हैं Vector, इसलिए उस प्रकार का नाम अभी तक परिभाषित नहीं है। इसके बजाय, मैं आधार प्रकार का उपयोग कर रहा हूं list, जो आपको ए Vectorऔर ए के डॉट उत्पाद को खोजने की अनुमति देता है list


0

छोटा और सरल तरीका:

obj = 12345
print(isinstance(obj,int))

आउटपुट:

True

यदि ऑब्जेक्ट एक स्ट्रिंग है, तो 'गलत' लौटा दी जाएगी:

obj = 'some string'
print(isinstance(obj,int))

आउटपुट:

False

0

आपके पास एक डेटा आइटम है, जो कहता है rec_dayकि जब फ़ाइल में लिखा जाएगा तो ए float। लेकिन प्रोग्राम प्रोसेसिंग के दौरान यह या तो हो सकता है float, intया strटाइप (ए)str नए रिकॉर्ड को शुरू करते समय इसका उपयोग किया जाता है और इसमें डमी फ्लैग वैल्यू होती है)।

फिर आप यह देखने के लिए देख सकते हैं कि क्या आपके पास इसका कोई नंबर है

                type(rec_day) != str 

मैंने इस तरह से एक पायथन प्रोग्राम को संरचित किया है और इसे एक संख्यात्मक जांच के रूप में उपयोग करके 'रखरखाव पैच' में रखा है। क्या यह पाइथोनिक तरीका है? सबसे अधिक संभावना नहीं है क्योंकि मैं COBOL में प्रोग्राम करता था।


-1

आप isdigit () फ़ंक्शन का उपयोग कर सकते हैं।

>>> x = "01234"
>>> a.isdigit()
True
>>> y = "1234abcd"
>>> y.isdigit()
False

"01234" एक संख्या नहीं है, यह एक चरित्र स्ट्रिंग है।
एलेक्सी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.