কোনও ক্রিয়াকলাপটি কীওয়ার্ড আর্গুমেন্টগুলি আপনি তালিকাভুক্ত করতে পারেন?


104

আমার একটি ডিক আছে, যা আমার কী / মানগুলি কীওয়ার্ড আর্গুমেন্ট হিসাবে পাস করতে হবে .. উদাহরণস্বরূপ ..

d_args = {'kw1': 'value1', 'kw2': 'value2'}
example(**d_args)

এটি সূক্ষ্মভাবে কাজ করে, তবে d_args ডিকের মধ্যে যদি মানগুলি থাকে যা exampleফাংশন দ্বারা স্বীকৃত হয় না তবে এটি স্পষ্টতই মারা যায় .. বলুন, উদাহরণ ফাংশন হিসাবে যদি সংজ্ঞায়িত করা হয়def example(kw2):

এটি সমস্যা যেহেতু আমি উভয়ই প্রজন্মের d_args, বা exampleফাংশনটি নিয়ন্ত্রণ করি না .. এগুলি উভয়ই বাহ্যিক মডিউল থেকে আসে এবং exampleডিক থেকে কেবল কিছু কীওয়ার্ড-যুক্তিই গ্রহণ করে ..

আদর্শভাবে আমি ঠিক করতাম

parsed_kwargs = feedparser.parse(the_url)
valid_kwargs = get_valid_kwargs(parsed_kwargs, valid_for = PyRSS2Gen.RSS2)
PyRSS2Gen.RSS2(**valid_kwargs)

আমি সম্ভবত বৈধ কী-ওয়ার্ড-আর্গুমেন্টের একটি তালিকা থেকে ডিকটি কেবল ফিল্টার করব, তবে আমি ভাবছিলাম: কোনও নির্দিষ্ট ফাংশনটি কীওয়ার্ড আর্গুমেন্টগুলিকে অগ্রগতিগতভাবে তালিকাভুক্ত করার কোনও উপায় আছে?

উত্তর:


150

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

>>> import inspect
>>> def func(a,b,c=42, *args, **kwargs): pass
>>> inspect.getargspec(func)
(['a', 'b', 'c'], 'args', 'kwargs', (42,))

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

def getRequiredArgs(func):
    args, varargs, varkw, defaults = inspect.getargspec(func)
    if defaults:
        args = args[:-len(defaults)]
    return args   # *args and **kwargs are not required, so ignore them.

তারপরে আপনার নির্দিষ্ট ডিক থেকে আপনি কী অনুপস্থিত তা জানানোর জন্য একটি ফাংশন:

def missingArgs(func, argdict):
    return set(getRequiredArgs(func)).difference(argdict)

একইভাবে, অবৈধ আরোগুলি পরীক্ষা করতে, ব্যবহার করুন:

def invalidArgs(func, argdict):
    args, varargs, varkw, defaults = inspect.getargspec(func)
    if varkw: return set()  # All accepted
    return set(argdict) - set(args)

এবং তাই যদি এটি কল হয় তবে একটি সম্পূর্ণ পরীক্ষা হ'ল:

def isCallableWithArgs(func, argdict):
    return not missingArgs(func, argdict) and not invalidArgs(func, argdict)

(পাইথনের আর্গ পার্সিংয়ের ক্ষেত্রে এটি কেবল ভাল k কোয়ার্গসে অবৈধ মানগুলির জন্য কোনও রানটাইম চেক অবশ্যই সনাক্ত করা যায় না))


নিস! আমি এই ফাংশন জানি না!
ডিজিনএক্স

1
কোড অবজেক্ট ব্যবহার করার পদ্ধতিটি কমবেশি অভিন্ন বলে দেওয়া হচ্ছে, আরও একটি মডিউল আমদানি করার কি কোনও সুবিধা আছে ...?
jmetz

@ জ্যামেটস - অবশ্যই - নিজের রোল করার চেয়ে লাইব্রেরি মডিউল ব্যবহার করা কার্যত সর্বদা ভাল। এছাড়াও, কোড বস্তুর উপর বৈশিষ্ট্যাবলী আরো অভ্যন্তরীণ হয়, এবং পরিবর্তনের জন্য (যেমন। উল্লেখ্য যে, এই সরানো আপ কোড pyhon3 মধ্যে)। মডিউলটি ইন্টারফেস হিসাবে ভবিষ্যতপ্রতিক্রিয়া হিসাবে ব্যবহার করে যদি এর অভ্যন্তরীণগুলির মধ্যে কিছু পরিবর্তিত হয়। এটি এমন জিনিসগুলিও করবে যা আপনি না ভাবেনও করতে পারেন, যেমন আপনি পরিদর্শন করতে পারবেন না এমন ফাংশনগুলিতে একটি উপযুক্ত ধরণের ত্রুটি ছুঁড়ে দেওয়া (যেমন সি সি ফাংশন)।
ব্রায়ান

13
inspect.getargspec(f)পাইথন ৩.০ থেকে অবহেলিত; আধুনিক পদ্ধতি হয় inspect.signature(f)
জারিট

এফওয়াইআই, আপনি যদি সিথন এবং পাইথন সমর্থন করতে চান তবে এই পদ্ধতিটি সাইথনের কোনও কার্যক্রমে কাজ করে না। co_varnamesবিকল্প, অন্য দিকে, উভয় কাজ করে।
পার্টফথিং

32

এটি সমস্ত প্রবেশযোগ্য আর্গুমেন্ট, কীওয়ার্ড এবং অ-কীওয়ার্ডগুলির নাম মুদ্রণ করবে:

def func(one, two="value"):
    y = one, two
    return y
print func.func_code.co_varnames[:func.func_code.co_argcount]

এটি কারণ co_varnamesসর্বদা সর্বদা পরামিতি হয় (পরবর্তী স্থানীয় উদাহরণগুলির মতো স্থানীয় ভেরিয়েবলগুলি হয় y)।

সুতরাং এখন আপনি একটি ফাংশন থাকতে পারে:

def getValidArgs(func, argsDict):
    '''Return dictionary without invalid function arguments.'''
    validArgs = func.func_code.co_varnames[:func.func_code.co_argcount]
    return dict((key, value) for key, value in argsDict.iteritems() 
                if key in validArgs)

যা আপনি এর পরে ব্যবহার করতে পারেন:

>>> func(**getValidArgs(func, args))

সম্পাদনা : একটি ছোট সংযোজন: আপনার যদি সত্যিই কোনও ক্রিয়াকলাপের কীওয়ার্ড আর্গুমেন্টগুলির প্রয়োজন হয় তবে আপনি func_defaultsএগুলিটি বের করতে বৈশিষ্ট্যটি ব্যবহার করতে পারেন :

def getValidKwargs(func, argsDict):
    validArgs = func.func_code.co_varnames[:func.func_code.co_argcount]
    kwargsLen = len(func.func_defaults) # number of keyword arguments
    validKwargs = validArgs[-kwargsLen:] # because kwargs are last
    return dict((key, value) for key, value in argsDict.iteritems() 
                if key in validKwargs)

আপনি এখন পরিচিত ফর্মগুলি দিয়ে আপনার ফাংশনটিতে কল করতে পারেন, তবে উত্তোলিত কাওয়ার্গগুলি, যেমন:

func(param1, param2, **getValidKwargs(func, kwargsDict))

এটি ধরে নিয়েছে যে এর স্বাক্ষরে funcকোনও *argsবা **kwargsযাদু ব্যবহার করে না ।


আমি যদি কেবল "কীওয়ার্ড" আর্গুমেন্ট "কী" মুদ্রণ করতে চাই তবে কী হবে?
জিয়া

7

পাইথন 3.0 এ:

>>> import inspect
>>> import fileinput
>>> print(inspect.getfullargspec(fileinput.input))
FullArgSpec(args=['files', 'inplace', 'backup', 'bufsize', 'mode', 'openhook'],
varargs=None, varkw=None, defaults=(None, 0, '', 0, 'r', None), kwonlyargs=[], 
kwdefaults=None, annotations={})

7

পাইথন 3 সমাধানের জন্য, আপনি যে ধরণের পরামিতি সম্পর্কে জানতে চান সে inspect.signatureঅনুযায়ী আপনি ব্যবহার করতে এবং ফিল্টার করতে পারেন ।

অবস্থানগত বা কীওয়ার্ড, কীওয়ার্ড-কেবল, ভের পজিশনাল এবং ভের কীওয়ার্ড প্যারামিটার সহ একটি নমুনা ফাংশন গ্রহণ:

def spam(a, b=1, *args, c=2, **kwargs):
    print(a, b, args, c, kwargs)

আপনি এটির জন্য একটি স্বাক্ষর বস্তু তৈরি করতে পারেন:

from inspect import signature
sig =  signature(spam)

এবং তারপরে আপনার প্রয়োজনীয় বিশদটি সন্ধান করতে একটি তালিকা বোধগম্য দিয়ে ফিল্টার করুন:

>>> # positional or keyword
>>> [p.name for p in sig.parameters.values() if p.kind == p.POSITIONAL_OR_KEYWORD]
['a', 'b']
>>> # keyword only
>>> [p.name for p in sig.parameters.values() if p.kind == p.KEYWORD_ONLY]
['c']

এবং, একইভাবে, ভেরি পজিশনের জন্য p.VAR_POSITIONALএবং এর সাথে কী কীওয়ার্ড ব্যবহার করে VAR_KEYWORD

এছাড়াও, ডিফল্ট মান p.defaultসমান কিনা তা পরীক্ষা করে ডিফল্ট মান বিদ্যমান কিনা তা পরীক্ষা করতে আপনি যদি একটি ক্লজ যুক্ত করতে পারেন p.empty


3

ডিজনেক্সের উত্তর বাড়ানো:

argnames = example.func_code.co_varnames[:func.func_code.co_argcount]
args = dict((key, val) for key,val in d_args.iteritems() if key in argnames)
example(**args)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.