নেস্টেডরা কি অজগরের ব্লকগুলি বাদ দিয়ে চেষ্টা করার জন্য একটি ভাল প্রোগ্রামিং অনুশীলন রয়েছে?


200

আমি আমার নিজের ধারকটি লিখছি, যার জন্য অ্যাট্রিবিউট কলগুলির মাধ্যমে একটি অভিধানে অ্যাক্সেস দেওয়া দরকার। ধারকটির সাধারণ ব্যবহারটি এরকম হবে:

dict_container = DictContainer()
dict_container['foo'] = bar
...
print dict_container.foo

আমি জানি যে এটির মতো কিছু লেখার জন্য এটি বোকামি হতে পারে তবে এটি আমার দেওয়া কার্যকারিতা provide আমি নিম্নলিখিত পদ্ধতিতে এটি বাস্তবায়নের বিষয়ে ভাবছিলাম:

def __getattribute__(self, item):
    try:
        return object.__getattribute__(item)
    except AttributeError:
        try:
            return self.dict[item]
        except KeyError:
            print "The object doesn't have such attribute"

আমি নিশ্চিত না যে নেস্টেড চেষ্টা করা / ব্লক ব্যতীত একটি ভাল অনুশীলন যাতে অন্য উপায়টি ব্যবহার করা যায় hasattr()এবং has_key():

def __getattribute__(self, item):
        if hasattr(self, item):
            return object.__getattribute__(item)
        else:
            if self.dict.has_key(item):
                return self.dict[item]
            else:
                raise AttributeError("some customised error")

বা তাদের মধ্যে একটি ব্যবহার করতে এবং এর জন্য একটির মতো ব্লক ধরার চেষ্টা করুন:

def __getattribute__(self, item):
    if hasattr(self, item):
        return object.__getattribute__(item)
    else:
        try:
            return self.dict[item]
        except KeyError:
            raise AttributeError("some customised error")

কোন বিকল্পটি সর্বাধিক পাইথোনিক এবং মার্জিত?


পাইথন দেবতাদের প্রদান প্রশংসা করবে if 'foo' in dict_container:। আমেন।
গিসিটল

উত্তর:


180

আপনার প্রথম উদাহরণ পুরোপুরি ঠিক আছে। এমনকি সরকারী পাইথন ডক্সও এই স্টাইলটি ইএএফপি হিসাবে পরিচিত বলে প্রস্তাব দেয় ।

ব্যক্তিগতভাবে, আমি বাসা বাঁধার এড়ানো পছন্দ করি না যখন এটি প্রয়োজন হয় না:

def __getattribute__(self, item):
    try:
        return object.__getattribute__(item)
    except AttributeError:
        pass  # fallback to dict
    try:
        return self.dict[item]
    except KeyError:
        raise AttributeError("The object doesn't have such attribute") from None

পুনশ্চ. has_key()পাইথন ২ এ দীর্ঘ সময়ের জন্য অবহেলা করা হয়েছে item in self.dictinstead পরিবর্তে ব্যবহার করুন।


2
return object.__getattribute__(item)ভুল এবং একটি উত্পাদন করবে TypeErrorকারণ ভুল সংখ্যক তর্ক যুক্ত করা হচ্ছে। এটি পরিবর্তে হওয়া উচিত return object.__getattribute__(self, item)
মার্টিনিউ

13
পিইপি 20: ফ্ল্যাট নীড়যুক্ত থেকে ভাল।
আয়নানস ফিলিপিসিস

7
from Noneশেষ লাইনে কী বোঝায়?
নিকলাস

2
@ এনিক্লাস এটি ব্যতিক্রম প্রসঙ্গটি মূলত দমন করে ("এই ব্যতিক্রম পরিচালনা করার সময় আরও একটি ব্যতিক্রম ঘটেছিল" - বার্তা বার্তা)। এখানে
Kade

পাইথন ডক্স বাসা বেঁধে দেওয়ার চেষ্টা করার পরামর্শ দেয় এটা একধরনের উন্মাদনা। এটি অবশ্যই ভয়ঙ্কর স্টাইল। ক্রিয়াকলাপগুলি পরিচালনা করার সঠিক উপায় যেখানে জিনিসগুলি যেমন ব্যর্থ হতে পারে সেগুলি একরকম একজাতীয় নির্মাণ ব্যবহার করবে, যা পাইথন সমর্থন করে না।
হেনরি হেনরিসন

19

জাভাতে প্রবাহ নিয়ন্ত্রণের জন্য ব্যতিক্রমগুলি ব্যবহার করার পক্ষে এটি সত্যই খারাপ অভ্যাস ছিল (মূলত ব্যতিক্রমগুলি jvm কে সম্পদ সংগ্রহ করতে বাধ্য করে ( আরও এখানে )), পাইথনে আপনার কাছে দুটি গুরুত্বপূর্ণ নীতি রয়েছে: হাঁসের টাইপিং এবং ইএএফপি । মূলত এর অর্থ হ'ল আপনাকে কোনও জিনিসটি যেভাবে এটি কাজ করবে বলে ব্যবহার করার চেষ্টা করতে উত্সাহিত করা হবে এবং যখন জিনিসগুলি এর মতো না হয় তখন পরিচালনা করতে হবে।

সংক্ষেপে একমাত্র সমস্যাটি হ'ল আপনার কোডটি খুব বেশি ইন্টেন্ট করা। যদি আপনি এটির মতো অনুভব করেন তবে কিছু কিছু নেস্টিং যেমন lqc এর প্রস্তাবিত হয়েছে তেমন সরল করার চেষ্টা করুন


10

কেবল সতর্কতা অবলম্বন করুন - finallyএক্ষেত্রে প্রথমে ছোঁয়া গেলেও এড়িয়ে যায়।

def a(z):
    try:
        100/z
    except ZeroDivisionError:
        try:
            print('x')
        finally:
            return 42
    finally:
        return 1


In [1]: a(0)
x
Out[1]: 1

বাহ এটা আমার মনকে ফুঁকিয়েছে ... আপনি কি আমাকে এই আচরণের ব্যাখ্যা দিয়ে কিছু ডকুমেন্টেশন খণ্ডগুলিতে নির্দেশ করতে পারেন?
মিশাল

1
@ মিশল: ফাই: উভয় finallyব্লকের জন্য মৃত্যুদন্ড কার্যকর করা হয়েছে a(0), তবে কেবল পিতামাতাকেই finally-returnফেরত দেওয়া হয়েছে।
সাওওমির লেনার্ট

9

আপনার নির্দিষ্ট উদাহরণের জন্য, আপনাকে আসলে এগুলি বাসা বাঁধার দরকার নেই। যদি tryব্লকের অভিব্যক্তিটি সফল হয় তবে ফাংশনটি ফিরে আসবে, তাই ব্লক বাদে পুরো চেষ্টা করার পরে / কোনও কোড কেবল তখনই চালিত হবে যখন প্রথম প্রচেষ্টা ব্যর্থ হয়। সুতরাং আপনি ঠিক করতে পারেন:

def __getattribute__(self, item):
    try:
        return object.__getattribute__(item)
    except AttributeError:
        pass
    # execution only reaches here when try block raised AttributeError
    try:
        return self.dict[item]
    except KeyError:
        print "The object doesn't have such attribute"

এগুলিকে বাসা বাঁধাই খারাপ নয়, তবে আমার মনে হয় এটিকে সমতল রেখে দেওয়াকে কাঠামো আরও স্পষ্ট করা হয়েছে: আপনি ধারাবাহিকভাবে কয়েকটি সিরিজ চেষ্টা করছেন এবং প্রথম কাজ করে যা কাজ করে returning

ঘটনাচক্রে, আপনি সত্যিই ব্যবহার করতে চান কিনা তা নিয়ে আপনি ভাবতে চাইতে পারেন __getattribute____getattr__ এখানে পরিবর্তে । ব্যবহার করা __getattr__জিনিসগুলিকে সরলীকরণ করবে কারণ আপনি জানবেন যে সাধারণ বৈশিষ্ট্য অনুসন্ধান প্রক্রিয়া ইতিমধ্যে ব্যর্থ হয়েছে।


7

আমার মতে এটি হ্যান্ডেল করার জন্য এটি সর্বাধিক পাইথোনিক উপায় হবে, যদিও এবং কারণ এটি আপনার প্রশ্নকে মূল পরিবর্তন করে। মনে রাখবেন __getattr__()পরিবর্তে এটি সংজ্ঞায়িত করে __getattribute__()কারণ এটি করার অর্থ এটি কেবল অভ্যন্তরীণ অভিধানে থাকা "বিশেষ" বৈশিষ্ট্যগুলিকেই মোকাবেলা করতে হবে।

def __getattr__(self, name):
    """only called when an attribute lookup in the usual places has failed"""
    try:
        return self.my_dict[name]
    except KeyError:
        raise AttributeError("some customized error message")

2
নোট করুন যে কোনও exceptব্লকে ব্যতিক্রম উত্থাপন পাইথন 3 এ বিভ্রান্তিকর ফলাফল দিতে পারে That's কারণ কারণ (পিইপি 3134 প্রতি) পাইথন 3 প্রথম ব্যতিক্রমটিকে (টি KeyError) দ্বিতীয় ব্যতিক্রমের (কনটেক্সট) হিসাবে চিহ্নিত করে AttributeErrorএবং যদি এটি পৌঁছে যায় শীর্ষ স্তর, এটি উভয় ব্যতিক্রম অন্তর্ভুক্ত একটি ট্রেসব্যাক মুদ্রণ করবে। এটি যখন দ্বিতীয় ব্যতিক্রম প্রত্যাশিত ছিল না তখন এটি সহায়ক হতে পারে তবে আপনি যদি ইচ্ছাকৃতভাবে দ্বিতীয় ব্যতিক্রমটি উত্থাপন করেন তবে এটি অনাকাঙ্ক্ষিত। পাইথন ৩.৩-এর জন্য, পিইপি 415 ব্যবহার করে প্রসঙ্গটি দমন করার ক্ষমতা যুক্ত করেছে raise AttributeError("whatever") from None
ব্ল্যাকঙ্কহট

3
@ ব্ল্যাককিংহিট: একটি ট্রেসব্যাক মুদ্রণ করা যাতে উভয় ব্যতিক্রমই যুক্ত থাকে তবে এক্ষেত্রে ঠিক হবে। অন্য কথায়, আমি মনে করি না যে আপনার কম্বল বিবৃতিটি সর্বদা অনাকাঙ্ক্ষিত সত্য। এখানে ব্যবহারের ক্ষেত্রে এটি একটি KeyErrorরূপান্তরিত হচ্ছে AttributeErrorএবং এটি দেখানো হচ্ছে যে ট্রেসব্যাকে যা ঘটেছিল তা দরকারী এবং উপযুক্ত হবে।
মার্টিনো

আরও জটিল পরিস্থিতিতে আপনি সঠিক হতে পারেন, তবে আমি মনে করি যে আপনি যখন ব্যতিক্রম প্রকারের মধ্যে রূপান্তর করছেন তখন আপনি প্রায়শই জানেন যে প্রথম ব্যতিক্রমের বিবরণ বাইরের ব্যবহারকারীর কাছে গুরুত্বপূর্ণ নয়। এটি হ'ল, যদি __getattr__ব্যতিক্রম উত্থাপন করা হয় তবে বাগটি সম্ভবত বৈশিষ্ট্য অ্যাক্সেসের একটি টাইপো, বর্তমান বর্গের কোডে কোনও বাস্তবায়ন বাগ নয়। প্রসঙ্গ হিসাবে পূর্বের ব্যতিক্রম দেখানো তাতে বিড়বিড় হতে পারে। এমনকি আপনি যখন প্রসঙ্গটি দমন করেন raise Whatever from None, তখনও আপনি প্রয়োজনের মাধ্যমে পূর্বের ব্যতিক্রমটি পেতে পারেন ex.__context__
ব্ল্যাককিংহাট

1
নেস্টেড ট্রাই / ক্যাচ ব্লক ব্যবহার করা ভাল অভ্যাস কিনা তা আমি আরও কৌতূহলযুক্ত প্রশ্নে আমি আপনার উত্তরটি গ্রহণ করতে চেয়েছিলাম। অন্যদিকে এটি সর্বাধিক মার্জিত সমাধান এবং আমি এটি আমার কোডে ব্যবহার করতে যাচ্ছি। অনেক ধন্যবাদ মার্টিন।
মিশাল

মিশাল: আপনাকে স্বাগতম! এটি ব্যবহারের চেয়েও দ্রুত __getattribute__()
মার্টিনো

4

পাইথনে অনুমতি চেয়ে ক্ষমা চাওয়া আরও সহজ। নেস্টেড ব্যতিক্রম হ্যান্ডলিং ঘামবেন না।

(তদ্ব্যতীত, has*প্রায় সবসময় যাহাই হউক না কেন অন্তর্ভুক্ত ব্যতিক্রমগুলি ব্যবহার করে)


4

ডকুমেন্টেশন অনুসারে , টিপলসের মাধ্যমে বা এর মতো একাধিক ব্যতিক্রম পরিচালনা করা ভাল:

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as e:
    print "I/O error({0}): {1}".format(e.errno, e.strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise

2
এই উত্তরটি আসলে আসল প্রশ্নটির দিকে নজর দেয় না তবে যে কেউ এটি পড়বে তার শেষে "খালি" নোটটি পড়ুন এটি একটি ভয়ানক ধারণা (সাধারণত) কারণ এটি যেমন নেমরর এবং কী-বোর্ড-অন্তর্ভুক্ত সহ সব কিছু ধরবে - যা সাধারণত আপনি বোঝাতে চেয়েছিলেন না!
হারিয়েছে

প্রদত্ত কোডটি মুদ্রণ বিবরণের ঠিক ঠিক পরে একই ব্যতিক্রম উত্থাপিত হয়েছে, এটি কি সত্যিই বড় ব্যাপার। এই ক্ষেত্রে এটি আড়াল না করে ব্যতিক্রম সম্পর্কিত আরও প্রসঙ্গ সরবরাহ করতে পারে। যদি এটি পুনরায় উত্থাপিত না হয় তবে আমি সম্পূর্ণরূপে একমত হব, তবে আমি মনে করি না যে কোনও ব্যতিক্রম যেটি আপনি চান না তা গোপন করার ঝুঁকি আছে।
নিম্বসস্কেল

4

নেস্টেড চেষ্টার জন্য / বাদ দিয়ে একটি ভাল এবং সাধারণ উদাহরণ নিম্নলিখিত হতে পারে:

import numpy as np

def divide(x, y):
    try:
        out = x/y
    except:
        try:
            out = np.inf * x / abs(x)
        except:
            out = np.nan
    finally:
        return out

এখন বিভিন্ন সমন্বয় চেষ্টা করুন এবং আপনি সঠিক ফলাফল পাবেন:

divide(15, 3)
# 5.0

divide(15, 0)
# inf

divide(-15, 0)
# -inf

divide(0, 0)
# nan

[অবশ্যই আমাদের অসাড় আছে তাই আমাদের এই ফাংশনটি তৈরি করার দরকার নেই]


2

আমি যে জিনিসটি এড়াতে পছন্দ করি তা হ'ল পুরানোটিকে পরিচালনা করার সময় একটি নতুন ব্যতিক্রম বাড়ানো। এটি ত্রুটি বার্তাগুলি পড়তে বিভ্রান্ত করে তোলে।

উদাহরণস্বরূপ, আমার কোডে, আমি মূলত লিখেছি

try:
    return tuple.__getitem__(self, i)(key)
except IndexError:
    raise KeyError(key)

এবং আমি এই বার্তা পেয়েছি।

>>> During handling of above exception, another exception occurred.

আমি যা চেয়েছিলাম তা হ'ল:

try:
    return tuple.__getitem__(self, i)(key)
except IndexError:
    pass
raise KeyError(key)

এটি ব্যতিক্রমগুলি কীভাবে পরিচালনা করা হয় তা প্রভাবিত করে না। উভয় ব্লকের কোডেই, একটি কীআরর ধরা পড়ত। এটি কেবল স্টাইল পয়েন্ট পাওয়ার বিষয়।


from Noneআরও বেশি স্টাইল পয়েন্টের জন্য গ্রহণযোগ্য উত্তরের উত্থানের ব্যবহার দেখুন । :)
পিয়ানোসৌরাস

1

যদি চেষ্টা-বাদে-অবশেষে অবশেষে ব্লকের ভিতরে বাসা বেঁধে দেওয়া হয়, অবশেষে "শিশু" থেকে প্রাপ্ত ফলাফল সংরক্ষণ করা হয়। আমি এখনও অফিশিয়াল এক্সপেনশন খুঁজে পাইনি, তবে নিম্নলিখিত কোড স্নিপেট পাইথন ৩.6 এ এই আচরণটি দেখায়।

def f2():
    try:
        a = 4
        raise SyntaxError
    except SyntaxError as se:
        print('log SE')
        raise se from None
    finally:
        try:
            raise ValueError
        except ValueError as ve:
            a = 5
            print('log VE')
            raise ve from None
        finally:
            return 6       
        return a

In [1]: f2()
log SE
log VE
Out[2]: 6

অবশেষে ব্লক ব্যতীত ভিতরে বাসা বাঁধলে @ সাওমির লেনার্টের দেওয়া উদাহরণ থেকে এই আচরণটি আলাদা।
গুয়ানঘুয়া শু

0

আমি মনে করি না যে এটি অজগর বা মার্জিত হওয়ার বিষয়। এটি যতটা সম্ভব ব্যতিক্রম প্রতিরোধের বিষয়। ব্যতিক্রমগুলি কোড বা ইভেন্টগুলিতে আপনার নিয়ন্ত্রণ না থাকা ইভেন্টগুলিতে ঘটতে পারে এমন ত্রুটিগুলি পরিচালনা করতে বোঝায়। এই ক্ষেত্রে কোনও আইটেমটি কোনও গুণবাচক বা অভিধানে আছে কিনা তা পরীক্ষা করার সময় আপনার সম্পূর্ণ নিয়ন্ত্রণ থাকে, তাই নেস্টেড ব্যতিক্রমগুলি এড়িয়ে চলুন এবং আপনার দ্বিতীয় প্রচেষ্টাটি ধরে রাখুন।


দস্তাবেজগুলি থেকে: বহু-থ্রেডযুক্ত পরিবেশে, এলবিওয়াইএল (আপনি আগে লাফ দেওয়ার আগে দেখুন) পদ্ধতিটি "চেহারা" এবং "লাফানো" এর মধ্যে একটি দৌড় শর্ত প্রবর্তনের ঝুঁকিপূর্ণ হতে পারে। উদাহরণস্বরূপ, কোডটি, ম্যাপিংয়ে কী থাকলে: রিটার্ন ম্যাপিং [কী] ব্যর্থ হতে পারে যদি অন্য থ্রেড পরীক্ষার পরে ম্যাপিং থেকে কী সরিয়ে দেয় তবে দেখার আগে। এই সমস্যাটি লক দিয়ে বা ইএএফপি (অনুমতি চেয়ে ক্ষমা চাওয়ার পক্ষে সহজ) পদ্ধতির
নুনো আন্দ্রে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.