यह जांचने का सबसे तेज़ तरीका है कि क्या किसी वर्ग को परिभाषित किया गया है?


132

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

यहाँ मैं फंस गया हूं: मैं बार-बार मूल स्थिति को पुन: उत्पन्न करने से बचना चाहता हूं, इसलिए मेरे पास निम्नलिखित कार्य हैं, जो उन कार्यों को वापस करता है जो कानूनी रूप से किसी भी राज्य में लागू हो सकते हैं:

def get_operations(self, include_parent=True):
    ops = self._get_operations()
    if not include_parent and self.path.parent_op:
        try:
            parent_inverse = self.invert_op(self.path.parent_op)
            ops.remove(parent_inverse)
        except NotImplementedError:
            pass
    return ops

और invert_op फ़ंक्शन डिफ़ॉल्ट रूप से फेंकता है।

क्या यह देखने के लिए जांच करने का एक तेज़ तरीका है कि क्या फ़ंक्शन को अपवाद को पकड़ने की तुलना में परिभाषित नहीं किया गया है?

मैं dir में वर्तमान के लिए जाँच की तर्ज पर कुछ सोच रहा था, लेकिन यह सही नहीं लगता। hasattr को getattr पर कॉल करके लागू किया जाता है और अगर यह उठता है तो जाँच करता है कि मुझे क्या चाहिए।


8
"हयात को गेटअटर कहकर लागू किया जाता है और अगर यह उठता है तो जांच करता है कि मुझे क्या चाहिए।" क्यों नहीं? आपको परवाह क्यों है कि कार्यान्वयन क्या करता है?
detly

4
has_op = lambda obj, op: callable(getattr(obj, op, None))
नमूनाब

1
प्रयास करें: hasattr(connection, 'invert_opt')
kenorb

जवाबों:


204

हां, getattr()विशेषता प्राप्त करने के लिए उपयोग करें, और callable()यह सत्यापित करने के लिए एक विधि है:

invert_op = getattr(self, "invert_op", None)
if callable(invert_op):
    invert_op(self.path.parent_op)

ध्यान दें कि getattr()आम तौर पर अपवाद तब फेंकता है जब विशेषता मौजूद न हो। हालाँकि, यदि आप एक डिफ़ॉल्ट मान ( Noneइस मामले में) निर्दिष्ट करते हैं, तो यह बदले में वापस आ जाएगा।


3
यह भी ध्यान दें कि getattrइस मामले में कार्यान्वयन चुपचाप एक अपवाद को पकड़ता है और इसके बजाय डिफ़ॉल्ट मान लौटाता है, ठीक उसी तरह hasattr, जैसे ओपी किसी कारण से था।
सांता

3
क्या होगा यदि फ़ंक्शन उस वर्ग में नहीं है, लेकिन मूल वर्ग पर है ?। इस मामले में मुझे एक सत्य मिलता है, यहां तक ​​कि जब बच्चे कभी भी उस फ़ंक्शन को लागू नहीं करते हैं (हॅटट्रा का उपयोग करके)
darkgaze

46

यह पायथन 2 और पायथन 3 दोनों में काम करता है

hasattr(connection, 'invert_opt')

hasattrTrueयदि कनेक्शन ऑब्जेक्ट में कोई फ़ंक्शन invert_optपरिभाषित है तो रिटर्न । यहाँ आप के लिए दस्तावेज है चरने के लिए

https://docs.python.org/2/library/functions.html#hasattr https://docs.python.org/3/library/functions.html#hasattr


5
हालांकि कोड की सराहना की जाती है, लेकिन इसका हमेशा साथ होना चाहिए। यह लंबा होना जरूरी नहीं है, लेकिन यह अपेक्षित है।
पीटर -

अच्छा है, आप एक लेख की ओर इशारा कर सकते हैं, हालांकि यह चोट नहीं
पहुँचाएगा

5
यदि कनेक्शन में कोई विशेषता है तो यह भी सही है connection.invert_opt = 'foo'
रॉबर्ट होनिग

20

क्या यह देखने के लिए जांच करने का एक तेज़ तरीका है कि क्या फ़ंक्शन को अपवाद को पकड़ने की तुलना में परिभाषित नहीं किया गया है?

आप उसके खिलाफ क्यों हैं? अधिकांश पायथोनिक मामलों में, अनुमति से माफी मांगना बेहतर है। ;-)

hasattr को getattr पर कॉल करके लागू किया जाता है और अगर यह उठता है तो जाँच करता है कि मुझे क्या चाहिए।

फिर, वह क्यों है? निम्नलिखित काफी पायथोनिक है:

    try:
        invert_op = self.invert_op
    except AttributeError:
        pass
    else:
        parent_inverse = invert_op(self.path.parent_op)
        ops.remove(parent_inverse)

या,

    # if you supply the optional `default` parameter, no exception is thrown
    invert_op = getattr(self, 'invert_op', None)  
    if invert_op is not None:
        parent_inverse = invert_op(self.path.parent_op)
        ops.remove(parent_inverse)

ध्यान दें, हालांकि, getattr(obj, attr, default)यह मूल रूप से एक अपवाद को पकड़ने के द्वारा लागू किया गया है, भी। पायथन भूमि में ऐसा कुछ भी गलत नहीं है!


4

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

तो यह उबलता है: यदि किसी ऑब्जेक्ट obj में विशेषता अट्रिबिट है, तो यह जांचने का सबसे तेज़ तरीका क्या है। उत्तर है

'attrib' in obj.__dict__

ऐसा इसलिए है क्योंकि एक तानाशाह ने अपनी चाबियों को हैश में कर लिया है, इसलिए कुंजी के अस्तित्व की जांच तेज है।

समय की तुलना नीचे देखें।

>>> class SomeClass():
...         pass
...
>>> obj = SomeClass()
>>>
>>> getattr(obj, "invert_op", None)
>>>
>>> %timeit getattr(obj, "invert_op", None)
1000000 loops, best of 3: 723 ns per loop
>>> %timeit hasattr(obj, "invert_op")
The slowest run took 4.60 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 674 ns per loop
>>> %timeit "invert_op" in obj.__dict__
The slowest run took 12.19 times longer than the fastest. This could mean that an intermediate result is being cached.
10000000 loops, best of 3: 176 ns per loop

यह उन वर्गों पर विफल है जो उपयोग करते हैं __slots____slots__मदद की गति तक पहुँच की सुविधा ~ 10%। stackoverflow.com/a/14119024/1459669
noɐɹƆz

3

मुझे नाथन ओस्टगार्ड का जवाब पसंद है और मैंने इसे वोट दिया। लेकिन एक और तरीका है कि आप अपनी समस्या को हल कर सकते हैं एक मेमोइज़िंग डेकोरेटर का उपयोग करना, जो फ़ंक्शन कॉल के परिणाम को कैश करेगा। तो आप आगे बढ़ सकते हैं और एक महंगा फ़ंक्शन हो सकता है जो किसी चीज़ का पता लगाता है, लेकिन तब जब आप इसे कॉल करते हैं और बाद में कॉल तेजी से होते हैं; फ़ंक्शन का मेमोअटेड संस्करण एक तानाशाही में तर्कों को देखता है, जब वास्तविक फ़ंक्शन ने परिणाम की गणना की, तो परिणाम में से तानाशाही का पता लगाता है और परिणाम तुरंत वापस करता है।

यहाँ रेमंड हेटिंगर द्वारा "ल्रु_चे" नामक एक यादगार डेकोरेटर के लिए एक नुस्खा है। इसका एक संस्करण अब पायथन 3.2 में फंक्शनलूल मॉड्यूल में मानक है।

http://code.activestate.com/recipes/498245-lru-and-lfu-cache-decorators/

http://docs.python.org/release/3.2/library/functools.html


2

पाइथन में किसी भी चीज की तरह, यदि आप पर्याप्त प्रयास करते हैं, तो आप हिम्मत से काम कर सकते हैं और वास्तव में कुछ बुरा कर सकते हैं। अब, यहाँ एक बुरा हिस्सा है:

def invert_op(self, op):
    raise NotImplementedError

def is_invert_op_implemented(self):
    # Only works in CPython 2.x of course
    return self.invert_op.__code__.co_code == 't\x00\x00\x82\x01\x00d\x00\x00S'

कृपया हमें एक एहसान करो, बस अपने प्रश्न में जो कुछ भी है उसे करते रहो और जब तक आप PyPy टीम में पायथन दुभाषिया में हैकिंग नहीं करते तब तक इसका उपयोग न करें। तुम क्या देखते pythonic, क्या मैं यहाँ है शुद्ध है बुराई


यह सच होगा यदि विधि किसी भी अपवाद को उठाती है। आपको यह देखने के लिए भी जांचना चाहिए कि क्या co_namesयह बराबर है ('NotImplementedError',)। मुझे यकीन नहीं है कि यह इसे कम या ज्यादा बुराई बना देता है।
टाइप करें

1

आप कक्षा में भी जा सकते हैं:

import inspect


def get_methods(cls_):
    methods = inspect.getmembers(cls_, inspect.isfunction)
    return dict(methods)

# Example
class A(object):
    pass

class B(object):
    def foo():
        print('B')


# If you only have an object, you can use `cls_ = obj.__class__`
if 'foo' in get_methods(A):
    print('A has foo')

if 'foo' in get_methods(B):
    print('B has foo')

0

__Dict__ संपत्ति में विशेषताओं की जाँच करते समय वास्तव में तेज़ है, आप इसका उपयोग विधियों के लिए नहीं कर सकते हैं, क्योंकि वे __dict__ हैश में प्रकट नहीं होते हैं। हालाँकि आप अपनी कक्षा में हैकिंग वर्कअराउंड का सहारा ले सकते हैं, यदि प्रदर्शन उतना ही महत्वपूर्ण हो:

class Test():
    def __init__():
        # redefine your method as attribute
        self.custom_method = self.custom_method

    def custom_method(self):
        pass

फिर विधि के लिए जाँच करें:

t = Test()
'custom_method' in t.__dict__

समय की तुलना getattr:

>>%timeit 'custom_method' in t.__dict__
55.9 ns ± 0.626 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

>>%timeit getattr(t, 'custom_method', None)
116 ns ± 0.765 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

ऐसा नहीं है कि मैं इस दृष्टिकोण को प्रोत्साहित कर रहा हूं, लेकिन यह काम करने लगता है।

[संपादित करें] जब दी गई कक्षा में विधि का नाम नहीं होता है, तो प्रदर्शन में वृद्धि अधिक होती है:

>>%timeit 'rubbish' in t.__dict__
65.5 ns ± 11 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

>>%timeit getattr(t, 'rubbish', None)
385 ns ± 12.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

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