snake - python software



পাইথন ক্লাস বস্তুর স্ট্রিং রূপান্তর? (7)

সতর্কতা : eval() নির্বিচারে পাইথন কোড কার্যকর করতে ব্যবহার করা যেতে পারে। আপনি অবিশ্বস্ত স্ট্রিং সঙ্গে eval() ব্যবহার করা উচিত নয় । ( অবিশ্বাস্য স্ট্রিংগুলিতে পাইথন এর eval () সুরক্ষা দেখুন ? )

এই সহজ মনে হয়।

>>> class Foo(object):
...     pass
... 
>>> eval("Foo")
<class '__main__.Foo'>

একটি পাইথন ফাংশনে ব্যবহারকারী ইনপুট হিসাবে একটি স্ট্রিং দেওয়া হলে, বর্তমানে নির্ধারিত নামস্থানতে নামের সাথে একটি শ্রেণি আছে যদি আমি এটির থেকে একটি ক্লাস অবজেক্ট পেতে চাই। মূলত, আমি একটি ফাংশন জন্য বাস্তবায়ন চান যা এই ধরনের ফলাফল উত্পাদন করবে:

class Foo:
    pass

str_to_class("Foo")
==> <class __main__.Foo at 0x69ba0>

এই, সব সম্ভব?


Answer #1

আপনি ক্লাস Baz , যা মডিউল foo.bar মডিউলে থাকে। পাইথন 2.7 দিয়ে, আপনি importlib.import_module() ব্যবহার করতে চান, কারণ এটি পাইথন 3 এ রূপান্তরিত করবে:

import importlib

def class_for_name(module_name, class_name):
    # load the module, will raise ImportError if module cannot be loaded
    m = importlib.import_module(module_name)
    # get the class, will raise AttributeError if class cannot be found
    c = getattr(m, class_name)
    return c

পাইথন <2.7:

def class_for_name(module_name, class_name):
    # load the module, will raise ImportError if module cannot be loaded
    m = __import__(module_name, globals(), locals(), class_name)
    # get the class, will raise AttributeError if class cannot be found
    c = getattr(m, class_name)
    return c

ব্যবহার করুন:

loaded_class = class_for_name('foo.bar', 'Baz')

Answer #2

আমি দেখেছি কিভাবে django এই পরিচালনা করে

django.utils.module_loading এই আছে

def import_string(dotted_path):
    """
    Import a dotted module path and return the attribute/class designated by the
    last name in the path. Raise ImportError if the import failed.
    """
    try:
        module_path, class_name = dotted_path.rsplit('.', 1)
    except ValueError:
        msg = "%s doesn't look like a module path" % dotted_path
        six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])

    module = import_module(module_path)

    try:
        return getattr(module, class_name)
    except AttributeError:
        msg = 'Module "%s" does not define a "%s" attribute/class' % (
            module_path, class_name)
        six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])

আপনি এটি import_string("module_path.to.all.the.way.to.your_class") মত ব্যবহার করতে পারেন import_string("module_path.to.all.the.way.to.your_class")


Answer #3

ইচ্ছাকৃতভাবে কোড কার্যকরকরণ বা অযাচিত ব্যবহারকারীর নামগুলি পাস করে, আপনার কাছে গ্রহণযোগ্য ফাংশন / বর্গের নামগুলির তালিকা থাকতে পারে এবং যদি ইনপুট তালিকায় একটিকে মেলে তবে এটি eval'd হয়।

PS: আমি জানি .... দেরী .... কিন্তু এটা অন্য কারো জন্য যারা ভবিষ্যতে এটিকে দমন করে।


Answer #4

যদি আপনি সত্যিই স্ট্রিং দিয়ে তৈরি ক্লাসগুলি পুনরুদ্ধার করতে চান তবে আপনাকে অভিধানে (অথবা সঠিকভাবে শব্দযুক্ত, রেফারেন্স ) সংরক্ষণ করতে হবে। সব পরে, এটি একটি উচ্চ স্তরের আপনার ক্লাসের নাম এবং অবাঞ্ছিত ক্লাস প্রকাশ করা এড়াতে পারবেন।

উদাহরণস্বরূপ, একটি গেম থেকে যেখানে অভিনেতা ক্লাসগুলি পাইথনে সংজ্ঞায়িত করা হয়েছে এবং আপনি অন্যান্য সাধারণ ক্লাসগুলি ব্যবহারকারী ইনপুট দ্বারা পৌঁছাতে চান।

আরেকটি পদ্ধতির (নীচের উদাহরণের মত) উপরের একটি dict ধরে রাখে এমন একটি সম্পূর্ণ নতুন ক্লাস তৈরি করতে হবে। এই হবে:

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

উদাহরণ:

class ClassHolder(object):
    def __init__(self):
        self.classes = {}

    def add_class(self, c):
        self.classes[c.__name__] = c

    def __getitem__(self, n):
        return self.classes[n]

class Foo(object):
    def __init__(self):
        self.a = 0

    def bar(self):
        return self.a + 1

class Spam(Foo):
    def __init__(self):
        self.a = 2

    def bar(self):
        return self.a + 4

class SomethingDifferent(object):
    def __init__(self):
        self.a = "Hello"

    def add_world(self):
        self.a += " World"

    def add_word(self, w):
        self.a += " " + w

    def finish(self):
        self.a += "!"
        return self.a

aclasses = ClassHolder()
dclasses = ClassHolder()
aclasses.add_class(Foo)
aclasses.add_class(Spam)
dclasses.add_class(SomethingDifferent)

print aclasses
print dclasses

print "======="
print "o"
print aclasses["Foo"]
print aclasses["Spam"]
print "o"
print dclasses["SomethingDifferent"]

print "======="
g = dclasses["SomethingDifferent"]()
g.add_world()
print g.finish()

print "======="
s = []
s.append(aclasses["Foo"]())
s.append(aclasses["Spam"]())

for a in s:
    print a.a
    print a.bar()
    print "--"

print "Done experiment!"

এটা আমাকে ফেরত দেয়:

<__main__.ClassHolder object at 0x02D9EEF0>
<__main__.ClassHolder object at 0x02D9EF30>
=======
o
<class '__main__.Foo'>
<class '__main__.Spam'>
o
<class '__main__.SomethingDifferent'>
=======
Hello World!
=======
0
1
--
2
6
--
Done experiment!

তাদের সাথে আরও একটি মজার পরীক্ষা হল এমন একটি পদ্ধতি যোগ করা যা ClassHolder যাতে আপনি যে সমস্ত ক্লাসগুলি করেছেন তা হারাবেন না: ^)


Answer #5

হ্যাঁ, আপনি এটা করতে পারেন। আপনার ক্লাসগুলিকে গ্লোবাল নেমস্পেসে বিদ্যমান বলে মনে হচ্ছে, এরকম কিছু এটি করবে:

import types

class Foo:
    pass

def str_to_class(s):
    if s in globals() and isinstance(globals()[s], types.ClassType):
            return globals()[s]
    return None

str_to_class('Foo')

==> <class __main__.Foo at 0x340808cc>

Answer #6
import sys
import types

def str_to_class(field):
    try:
        identifier = getattr(sys.modules[__name__], field)
    except AttributeError:
        raise NameError("%s doesn't exist." % field)
    if isinstance(identifier, (types.ClassType, types.TypeType)):
        return identifier
    raise TypeError("%s is not a class." % field)

এই সঠিকভাবে পুরানো শৈলী এবং নতুন শৈলী উভয় ক্লাস পরিচালনা করে।





python