জাভা ক্লাস.ফরনাম () এর সমকক্ষ পাইথনের কি আছে?


95

আমার কাছে স্ট্রিং আর্গুমেন্ট নেওয়ার দরকার আছে এবং পাইথনের সেই স্ট্রিংটিতে নামযুক্ত শ্রেণীর একটি অবজেক্ট তৈরি করা উচিত। জাভাতে, আমি ব্যবহার করব Class.forName().newInstance()। পাইথনের সমতুল্য কি আছে?


প্রতিক্রিয়া জন্য ধন্যবাদ। আমি কী করছি জানতে চাইলে তাদের উত্তর দিতে: আমি একটি কমান্ড লাইন যুক্তিটি শ্রেণীর নাম হিসাবে ব্যবহার করতে এবং তা ইনস্ট্যান্ট করতে চাই। আমি আসলে জাইথনে প্রোগ্রামিং করছি এবং জাভা ক্লাস ইনস্ট্যান্ট করছি, সুতরাং জাভা-নিশ প্রশ্নটি। getattr()দুর্দান্ত কাজ করে অনেক ধন্যবাদ.


ব্যবহারের উদাহরণের জন্য stackoverflow.com/a/10675081/116891 দেখুন importlib.import, যা অজগর 3 থেকে 2.7 থেকে ব্যাকপোর্ট করা হয়েছিল ( docs.python.org/2/library/importlib.html )
প্যাট

উত্তর:


170

জাতির চেয়ে পাইথনের প্রতিচ্ছবি অনেক সহজ এবং অনেক বেশি নমনীয়।

আমি এই টিউটোরিয়ালটি পড়ার পরামর্শ দিচ্ছি

কোনও প্রত্যক্ষ ক্রিয়াকলাপ নেই (যা আমি জানি) যা পুরোপুরি যোগ্যতাসম্পন্ন শ্রেণীর নাম নেয় এবং ক্লাসটি ফিরিয়ে দেয়, তবে এটি তৈরি করার জন্য আপনার প্রয়োজনীয় সমস্ত টুকরা রয়েছে এবং আপনি সেগুলি একসাথে সংযুক্ত করতে পারেন।

যদিও এক বিট পরামর্শ: আপনি যখন অজগরে থাকবেন তখন জাভা স্টাইলে প্রোগ্রাম করার চেষ্টা করবেন না।

আপনি যদি এটি করার চেষ্টা করছেন তা যদি আপনি ব্যাখ্যা করতে পারেন তবে সম্ভবত আমরা আপনাকে এটি করার আরও অজগর উপায় খুঁজে পেতে সহায়তা করতে পারি।

এখানে একটি ফাংশন যা আপনি যা চান তা করে:

def get_class( kls ):
    parts = kls.split('.')
    module = ".".join(parts[:-1])
    m = __import__( module )
    for comp in parts[1:]:
        m = getattr(m, comp)            
    return m

আপনি এই ফাংশনটির রিটার্ন মানটি ব্যবহার করতে পারেন যেমন এটি বর্গ নিজেই।

এখানে একটি ব্যবহার উদাহরণ:

>>> D = get_class("datetime.datetime")
>>> D
<type 'datetime.datetime'>
>>> D.now()
datetime.datetime(2009, 1, 17, 2, 15, 58, 883000)
>>> a = D( 2010, 4, 22 )
>>> a
datetime.datetime(2010, 4, 22, 0, 0)
>>> 

ওটা কিভাবে কাজ করে?

আমরা __import__ক্লাসটি ধারণ করে এমন মডিউলটি আমদানি করতে ব্যবহার করছি , যার জন্য প্রয়োজন ছিল আমরা প্রথমে সম্পূর্ণরূপে যোগ্যতাসম্পন্ন নাম থেকে মডিউলটির নাম বের করব। তারপরে আমরা মডিউলটি আমদানি করব:

m = __import__( module )

এই ক্ষেত্রে, mকেবলমাত্র শীর্ষ স্তরের মডিউলটি উল্লেখ করা হবে,

উদাহরণস্বরূপ, যদি আপনার শ্রেণি foo.bazমডিউলে বাস করে mতবে মডিউলটি foo
আমরা সহজেই foo.bazব্যবহারের জন্য একটি রেফারেন্স পেতে পারি obtaingetattr( m, 'baz' )

শীর্ষ স্তরের মডিউল থেকে ক্লাসে পেতে, gettatrক্লাস নামের অংশগুলিতে পুনরাবৃত্তভাবে ব্যবহার করতে হবে

উদাহরণস্বরূপ বলুন, যদি আপনার শ্রেণির নাম হয় foo.baz.bar.Modelতবে আমরা এটি করি:

m = __import__( "foo.baz.bar" ) #m is package foo
m = getattr( m, "baz" ) #m is package baz
m = getattr( m, "bar" ) #m is module bar
m = getattr( m, "Model" ) #m is class Model

এই লুপে যা ঘটছে তা হচ্ছে:

for comp in parts[1:]:
    m = getattr(m, comp)    

লুপ শেষে mক্লাসে একটি রেফারেন্স হবে। এর অর্থ mহ'ল এটি আসলে শ্রেণীর নিজের স্তর, উদাহরণস্বরূপ আপনি এটি করতে পারেন:

a = m() #instantiate a new instance of the class    
b = m( arg1, arg2 ) # pass arguments to the constructor

6
এক্সেক অত্যন্ত বিপজ্জনক। আপনার স্কোপের নামগুলি গতিশীলভাবে ওভারথাইট করে পাদদেশে নিজেকে গুলি করা সহজ এবং রোড আইল্যান্ডের আকারের সুরক্ষা ত্রুটি খোলার পক্ষে সহজ।
সেরাফিনা ব্রোসিয়াস

4
এক্সিকিউটটি এখানে নিরাপত্তাহীন হওয়ার কারণ আপনি একটি ';' শ্রেণীর নাম থেকে আমদানি ভেঙে যায়। এটি সহজেই নির্বিচারে কোড প্রয়োগের অনুমতি দিতে পারে। এটি আপনার কোডকে ক্ষতিগ্রস্থ করার কারণটি হ'ল এক্সেক সংঘর্ষের নামগুলি ওভাররাইট করে দেবে, এতে বাগ এবং / অথবা সুরক্ষা ত্রুটি দেখা দেয়।
সেরিফিনা ব্রোসিয়াস

8
হ্যাঁ, এটিই যা __import__বিদ্যমান। জ্যাঙ্গোর মতো প্রকল্পগুলি যা মডিউল-লোডিং-যাদু করে সর্বদা এটি ব্যবহার করে। চমৎকার উত্তর.
সিডলারি

5
get_class = lambda name: reduce(getattr, name.split('.')[1:], __import__(name.partition('.')[0]))। যদিও 'অবজেক্ট.ফর্ম_নাম' এর চেয়ে আরও ভাল নাম হতে পারে। উদাহরণ: get_class ('দশমিক। দশমিক'), get_class (মডিউল_নাম)।
jfs

4
এটি কেবল একটি সাত লাইন ফাংশন সংজ্ঞায়িত করতে লেগেছে। একটি বাস্তব স্বাচ্ছন্দ্য।
পাভেল ভ্লাসভ

27

ক্লাসটি ধরে নেওয়া আপনার সুযোগের মধ্যে রয়েছে:

globals()['classname'](args, to, constructor)

অন্যথায়:

getattr(someModule, 'classname')(args, to, constructor)

সম্পাদনা: দ্রষ্টব্য, আপনি getattr এ 'foo.bar' এর মতো নাম দিতে পারবেন না। আপনি এটি দ্বারা বিভক্ত করা প্রয়োজন। এবং প্রতিটি টুকরোতে বাম-থেকে-ডানদিকে getattr () কল করুন। এটি এটি পরিচালনা করবে:

module, rest = 'foo.bar.baz'.split('.', 1)
fooBar = reduce(lambda a, b: getattr(a, b), rest.split('.'), globals()[module])
someVar = fooBar(args, to, constructor)

এটি গ্লোবাল () ['শ্রেণীর নাম'] হওয়া উচিত নয়?
orip

আপনি সত্যিই সঠিক। আমি গ্লোবালগুলি ভুলে গেছি () প্রকৃত বিশ্বব্যাপী সুযোগটি ফিরিয়ে দেয় না, এটির একটি ম্যাপিং। যেমন সম্পাদনা - ধন্যবাদ!
সেরাফিনা ব্রোসিয়াস

এটি জাভা এর Class.forName এর সমতুল্য নয়, জাভাতে, কী আমদানি করা হয় এবং কী না তা নিয়ে কোনও অনুমান করা হয় না
হেসেন

4
attrs = 'foo.bar.baz'.split('.'); fooBar = reduce(getattr, attrs[1:], __import__(attrs[0]))
jfs

4
বাmodule, _, attrs = 'foo.bar.baz'.partition('.'); fooBar = reduce(getattr, attrs, __import__(module))
jfs

16
def import_class_from_string(path):
    from importlib import import_module
    module_path, _, class_name = path.rpartition('.')
    mod = import_module(module_path)
    klass = getattr(mod, class_name)
    return klass

ব্যবহার

In [59]: raise import_class_from_string('google.appengine.runtime.apiproxy_errors.DeadlineExceededError')()
---------------------------------------------------------------------------
DeadlineExceededError                     Traceback (most recent call last)
<ipython-input-59-b4e59d809b2f> in <module>()
----> 1 raise import_class_from_string('google.appengine.runtime.apiproxy_errors.DeadlineExceededError')()

DeadlineExceededError: 

4
+1 ইমপোর্টলিব ব্যবহার করার জন্য এটি এটির জন্য ক্লাসটি পুনরাবৃত্তভাবে খুঁজে নেওয়ার প্রয়োজনকে (যে আমদানির কারণ ঘটায়) বাধা দেয় । গ্রহণযোগ্য উত্তরের চেয়ে সহজ এবং ক্লিনার (যদিও কম ভাল নথিভুক্ত)।
সেজে 88

4

তবুও আরেকটি বাস্তবায়ন।

def import_class(class_string):
    """Returns class object specified by a string.

    Args:
        class_string: The string representing a class.

    Raises:
        ValueError if module part of the class is not specified.
    """
    module_name, _, class_name = class_string.rpartition('.')
    if module_name == '':
        raise ValueError('Class name must contain module part.')
    return getattr(
        __import__(module_name, globals(), locals(), [class_name], -1),
        class_name)

if module_nameLBYL, বেশ redudant যেহেতু ত্রুটি যদি আপনি কেবল যারা লাইন মুছে ফেলতে আপনি পেতে হল: ValueError: Empty module name
বুকজোর

3

দেখে মনে হচ্ছে আপনি এটি শুরুতে পরিবর্তে মাঝখানে থেকে এসেছেন। আপনি সত্যিই কি করতে চেষ্টা করছেন? প্রদত্ত স্ট্রিংয়ের সাথে সম্পর্কিত ক্লাস সন্ধান করা একটি শেষের উপায়।

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

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

>>> class A(object):
...   def __init__(self, v):
...     self.v = v
...   def __reduce__(self):
...     return (self.__class__, (self.v,))
>>> a = A("example")
>>> import pickle
>>> b = pickle.loads(pickle.dumps(a))
>>> a.v, b.v
('example', 'example')
>>> a is b
False

4
এটি খুব আকর্ষণীয়, তবে প্রশ্নের চেয়ে কিছুটা আলাদা
নিক

1

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

def get_object(name):
    """Retrieve a python object, given its dotted.name."""
    parts = name.split('.')
    parts_copy = parts[:]
    while parts_copy:
        try:
            module = __import__('.'.join(parts_copy))
            break
        except ImportError:
            del parts_copy[-1]
            if not parts_copy: raise
    parts = parts[1:]

    obj = module
    for part in parts:
        parent, obj = obj, getattr(obj, part)

    return obj

0

আমার সমস্ত বিদ্যমান ক্লাসে অবজেক্ট পাওয়ার দরকার ছিল my_package। তাই আমি সব প্রয়োজনীয় শ্রেণীর আমদানি my_packageএর __init__.py

সুতরাং আমার ডিরেক্টরি কাঠামো এর মত:

/my_package
    - __init__.py
    - module1.py
    - module2.py
    - module3.py

এবং আমার __init__.pyচেহারা এই মত:

from .module1 import ClassA
from .module2 import ClassB

তারপরে আমি এই জাতীয় একটি ফাংশন তৈরি করব:

def get_classes_from_module_name(module_name):
    return [_cls() for _, _cls in inspect.getmembers(__import__(module_name), inspect.isclass)]

কোথায় module_name = 'my_package'

দস্তাবেজটি পরিদর্শন করুন: https://docs.python.org/3/library/inspect.html#inspect.getmebers

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.