python - সহজ - পাইথন মধ্যে সি মত কাঠামো




সহজ ভাষায় পাইথন ৩ pdf (14)

ডিএফঃ এটা বেশ ভালো ... আমি জানি না যে আমি ক্লাস ব্যবহার করে ক্লাসে ক্ষেত্রগুলি অ্যাক্সেস করতে পারি।

চিহ্নিত করুন: আমার যে পরিস্থিতিগুলি আমি চাই তা ঠিক ছিল যখন আমি একটি টুপি চাই কিন্তু অভিধান হিসাবে "ভারী" হিসাবে কিছুই না।

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

... যা আপনার দ্বিতীয় মন্তব্য আমাদের বাড়ে। পাইথন ডিক্টগুলি "ভারী" একটি অত্যন্ত অ-পাইথনবাদী ধারণা। এবং যেমন মন্তব্য পড়া আমার পাইথন জেন হত্যা। এটা ভালো না.

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

Python এ সি-মত গঠন সুবিধামত সংজ্ঞায়িত করার কোন উপায় আছে কি? আমি স্টাফ লেখার ক্লান্ত নই:

class MyStruct():
    def __init__(self, field1, field2, field3):
        self.field1 = field1
        self.field2 = field2
        self.field3 = field3

আপডেট : ডাটা ক্লাস

পাইথন 3.7ডেটা ক্লাস প্রবর্তনের সাথে আমরা খুব ঘনিষ্ঠ হয়ে যাই।

নিচের উদাহরণটি নীচের নামযুক্ত উদাহরণের অনুরূপ, কিন্তু ফলস্বরূপ বস্তু পরিবর্তনযোগ্য এবং এটি ডিফল্ট মানগুলির জন্য অনুমতি দেয়।

from dataclasses import dataclass

@dataclass
class Point:
    x: float
    y: float
    z: float = 0.0

p = Point(1.5, 2.5)

print(p)  # Point(x=1.5, y=2.5, z=0.0)

আপনি যদি আরো নির্দিষ্ট টাইপ এনটাইটেশন ব্যবহার করতে চান তবে এটি নতুন typing মডিউল দিয়ে চমত্কারভাবে খেলা করে।

আমি এই জন্য কঠোরভাবে অপেক্ষা করা হয়েছে! যদি আপনি আমাকে জিজ্ঞাসা করেন, ডেটা ক্লাসস এবং নতুন নামযুক্ত টুপি ঘোষণা, টাইপিং মডিউল দিয়ে মিলিত হয়, তাহলে একটি দেবতা!

উন্নত NamedTuple ঘোষণা

পাইথন 3.6 থেকে এটি খুব সহজ এবং সুন্দর (আইএমএইচও) হয়ে উঠেছে, যতক্ষণ আপনি অপরিবর্তনীয়তার সাথে বসবাস করতে পারেন।

নামযুক্ত টুপি ঘোষণা করার একটি নতুন উপায় চালু করা হয়েছে, যা typing এনটাইটেশনগুলির জন্যও অনুমতি দেয়:

from typing import NamedTuple

class MyStruct(NamedTuple):
    foo: str
    bar: int
    baz: list
    qux: User

my_item = MyStruct('foo', 0, ['baz'], User('peter'))

print(my_item) # MyStruct(foo='foo', bar=0, baz=['baz'], qux=User(name='peter'))

আপনি অনেকগুলি জিনিসের জন্য টিপেল ব্যবহার করতে পারেন যেখানে আপনি C তে একটি struct ব্যবহার করবেন (উদাহরণস্বরূপ x, y কোঅর্ডিনেটস বা RGB রংগুলির মত কিছু)।

অন্য সবকিছুর জন্য আপনি অভিধান বা একটি ইউটিলিটি ক্লাস ব্যবহার করতে পারেন:

>>> class Bunch:
...     def __init__(self, **kwds):
...         self.__dict__.update(kwds)
...
>>> mystruct = Bunch(field1=value1, field2=value2)

আমি পাইথন কুকবুকের প্রকাশিত সংস্করণে "definitive" আলোচনা here দেখছি।


আপনি অবস্থান দ্বারা ইনস্ট্যান্স ভেরিয়েবলগুলিতে init পরামিতি পাশ করতে পারেন

# Abstract struct class       
class Struct:
    def __init__ (self, *argv, **argd):
        if len(argd):
            # Update by dictionary
            self.__dict__.update (argd)
        else:
            # Update by position
            attrs = filter (lambda x: x[0:2] != "__", dir(self))
            for n in range(len(argv)):
                setattr(self, attrs[n], argv[n])

# Specific class
class Point3dStruct (Struct):
    x = 0
    y = 0
    z = 0

pt1 = Point3dStruct()
pt1.x = 10

print pt1.x
print "-"*10

pt2 = Point3dStruct(5, 6)

print pt2.x, pt2.y
print "-"*10

pt3 = Point3dStruct (x=1, y=2, z=3)
print pt3.x, pt3.y, pt3.z
print "-"*10

আপনি স্ট্যান্ডার্ড লাইব্রেরীতে উপলব্ধ সি গঠন সাবclass করতে পারেন। ctypes মডিউল একটি গঠন ক্লাস উপলব্ধ করা হয়। ডক্স থেকে উদাহরণ:

>>> from ctypes import *
>>> class POINT(Structure):
...     _fields_ = [("x", c_int),
...                 ("y", c_int)]
...
>>> point = POINT(10, 20)
>>> print point.x, point.y
10 20
>>> point = POINT(y=5)
>>> print point.x, point.y
0 5
>>> POINT(1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ValueError: too many initializers
>>>
>>> class RECT(Structure):
...     _fields_ = [("upperleft", POINT),
...                 ("lowerright", POINT)]
...
>>> rc = RECT(point)
>>> print rc.upperleft.x, rc.upperleft.y
0 5
>>> print rc.lowerright.x, rc.lowerright.y
0 0
>>>

আমি slots ব্যবহার করে এমন একটি সমাধান যুক্ত করতে চাই।

class Point:
    __slots__ = ["x", "y"]
    def __init__(self, x, y):
        self.x = x
        self.y = y

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

শ্রেণির উদাহরণগুলিতে বৈশিষ্ট্য যোগ করার উদাহরণ (এইভাবে স্লটগুলি ব্যবহার করে না):

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

p1 = Point(3,5)
p1.z = 8
print(p1.z)

আউটপুট: 8

স্লট ব্যবহার করা হয় যেখানে ক্লাস উদাহরণে গুণাবলী যোগ করার চেষ্টা করার উদাহরণ:

class Point:
    __slots__ = ["x", "y"]
    def __init__(self, x, y):
        self.x = x
        self.y = y

p1 = Point(3,5)
p1.z = 8

আউটপুট: উপাদানের ত্রুটি: 'পয়েন্ট' বস্তুর কোন বৈশিষ্ট্য নেই 'z'

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


আমি এমন কোনও সাজসজ্জার লেখক লিখেছি যা আপনি এটি করার জন্য যে কোনও পদ্ধতিতে ব্যবহার করতে পারেন যাতে সমস্ত আর্গুমেন্ট পাস করা হয়, বা কোনও ডিফল্ট, উদাহরণ হিসাবে বরাদ্দ করা হয়।

def argumentsToAttributes(method):
    argumentNames = method.func_code.co_varnames[1:]

    # Generate a dictionary of default values:
    defaultsDict = {}
    defaults = method.func_defaults if method.func_defaults else ()
    for i, default in enumerate(defaults, start = len(argumentNames) - len(defaults)):
        defaultsDict[argumentNames[i]] = default

    def newMethod(self, *args, **kwargs):
        # Use the positional arguments.
        for name, value in zip(argumentNames, args):
            setattr(self, name, value)

        # Add the key word arguments. If anything is missing, use the default.
        for name in argumentNames[len(args):]:
            setattr(self, name, kwargs.get(name, defaultsDict[name]))

        # Run whatever else the method needs to do.
        method(self, *args, **kwargs)

    return newMethod

একটি দ্রুত বিক্ষোভ। মনে রাখবেন যে আমি একটি অবস্থানগত যুক্তি ব্যবহার করি, b জন্য ডিফল্ট মান ব্যবহার করি এবং একটি নামযুক্ত যুক্তি c । আমি তারপর সমস্ত 3 রেফারেন্সিং self মুদ্রণ, দেখানোর জন্য যে তারা সঠিকভাবে পদ্ধতি প্রবেশ করা হয়েছে আগে নির্ধারিত হয়েছে।

class A(object):
    @argumentsToAttributes
    def __init__(self, a, b = 'Invisible', c = 'Hello'):
        print(self.a)
        print(self.b)
        print(self.c)

A('Why', c = 'Nothing')

মনে রাখবেন যে আমার সজ্জাকারীকে কোনও পদ্ধতিতে কাজ করতে হবে, কেবল __init__


আমি পাইথন গঠন অভিধান এই প্রয়োজন জন্য উপযুক্ত মনে হয়।

d = dict{}
d[field1] = field1
d[field2] = field2
d[field2] = field3

একটি নামযুক্ত Tuple ব্যবহার করুন, যা Python 2.6-র মধ্যে স্ট্যান্ডার্ড লাইব্রেরিতে সংগ্রহ মডিউল যোগ করা হয়েছিল। Python 2.4 সমর্থন করার জন্য রেমন্ড হিটিংয়ের নামযুক্ত টিপল রেসিপি ব্যবহার করাও সম্ভব।

এটি আপনার মৌলিক উদাহরণের জন্য চমৎকার, তবে সেই প্রান্তের মামলাগুলির একটি গুচ্ছও জুড়ে দেয় যা আপনি পরেও অনুসরণ করতে পারেন। উপরে আপনার টুকরা হিসাবে লেখা হবে:

from collections import namedtuple
MyStruct = namedtuple("MyStruct", "field1 field2 field3")

নতুন তৈরি করা এই ধরনের ব্যবহার করা যেতে পারে:

m = MyStruct("foo", "bar", "baz")

আপনি নামযুক্ত আর্গুমেন্ট ব্যবহার করতে পারেন:

m = MyStruct(field1="foo", field2="bar", field3="baz")

একটি struct নিম্নলিখিত সমাধান নামকরণের বাস্তবায়ন এবং পূর্ববর্তী উত্তর কিছু দ্বারা অনুপ্রাণিত হয়। যাইহোক, নামকরণের বিপরীতে এটি পরিবর্তনযোগ্য, এটির মানগুলির মধ্যে, তবে সি-স্টাইল গঠনটির নাম / গুণাবলীগুলিতে অযোগ্য, যা একটি স্বাভাবিক শ্রেণী বা স্বর নয়।

_class_template = """\
class {typename}:
def __init__(self, *args, **kwargs):
    fields = {field_names!r}

    for x in fields:
        setattr(self, x, None)            

    for name, value in zip(fields, args):
        setattr(self, name, value)

    for name, value in kwargs.items():
        setattr(self, name, value)            

def __repr__(self):
    return str(vars(self))

def __setattr__(self, name, value):
    if name not in {field_names!r}:
        raise KeyError("invalid name: %s" % name)
    object.__setattr__(self, name, value)            
"""

def struct(typename, field_names):

    class_definition = _class_template.format(
        typename = typename,
        field_names = field_names)

    namespace = dict(__name__='struct_%s' % typename)
    exec(class_definition, namespace)
    result = namespace[typename]
    result._source = class_definition

    return result

ব্যবহার:

Person = struct('Person', ['firstname','lastname'])
generic = Person()
michael = Person('Michael')
jones = Person(lastname = 'Jones')


In [168]: michael.middlename = 'ben'
Traceback (most recent call last):

  File "<ipython-input-168-b31c393c0d67>", line 1, in <module>
michael.middlename = 'ben'

  File "<string>", line 19, in __setattr__

KeyError: 'invalid name: middlename'

এটি কিছুক্ষন বিলম্বিত হতে পারে তবে আমি পাইথন মেটা-ক্লাসগুলি (খুব নীচের সজ্জা সংস্করণ) ব্যবহার করে সমাধান তৈরি করেছি।

যখন __init__ রান সময় চলাকালীন বলা হয়, এটি প্রতিটি আর্গুমেন্ট এবং তাদের মান ধরে এবং আপনার ক্লাসে ইনস্ট্যান্স ভেরিয়েবল হিসাবে তাদের বরাদ্দ করে। এই ভাবে আপনি একটি ম্যানুয়ালি মান হিসাবে বরাদ্দ ছাড়া একটি struct-like ক্লাস করতে পারেন।

আমার উদাহরণে কোনও ত্রুটি পরীক্ষা নেই যাতে এটি অনুসরণ করা সহজ।

class MyStruct(type):
    def __call__(cls, *args, **kwargs):
        names = cls.__init__.func_code.co_varnames[1:]

        self = type.__call__(cls, *args, **kwargs)

        for name, value in zip(names, args):
            setattr(self , name, value)

        for name, value in kwargs.iteritems():
            setattr(self , name, value)
        return self 

এখানে এটি কর্ম হয়।

>>> class MyClass(object):
    __metaclass__ = MyStruct
    def __init__(self, a, b, c):
        pass


>>> my_instance = MyClass(1, 2, 3)
>>> my_instance.a
1
>>> 

আমি এটি reddit পোস্ট এবং /u/matchu একটি শোভাকর সংস্করণ পোস্ট যা ক্লিনার। আপনি মেটাল্লাস সংস্করণ প্রসারিত না হওয়া পর্যন্ত আমি এটি ব্যবহার করার জন্য উত্সাহিত করব।

>>> def init_all_args(fn):
    @wraps(fn)
    def wrapped_init(self, *args, **kwargs):
        names = fn.func_code.co_varnames[1:]

        for name, value in zip(names, args):
            setattr(self, name, value)

        for name, value in kwargs.iteritems():
            setattr(self, name, value)

    return wrapped_init

>>> class Test(object):
    @init_all_args
    def __init__(self, a, b):
        pass


>>> a = Test(1, 2)
>>> a.a
1
>>> 

কিভাবে একটি অভিধান সম্পর্কে?

এটার মতো কিছু:

myStruct = {'field1': 'some val', 'field2': 'some val'}

তারপরে আপনি মানগুলি ম্যানিপুলেট করতে এটি ব্যবহার করতে পারেন:

print myStruct['field1']
myStruct['field2'] = 'some other values'

এবং মান স্ট্রিং হতে হবে না। তারা বেশিরভাগ অন্য কোন বস্তু হতে পারে।


যখনই আমাকে একটি "তাত্ক্ষণিক ডেটা অবজেক্টের দরকার হয় যা অভিধানের মত আচরণ করে" (আমি সি structs মনে করি না !), আমি এই চতুর হ্যাক সম্পর্কে চিন্তা করি:

class Map(dict):
    def __init__(self, **kwargs):
        super(Map, self).__init__(**kwargs)
        self.__dict__ = self

এখন আপনি শুধু বলতে পারেন:

struct = Map(field1='foo', field2='bar', field3=42)

self.assertEquals('bar', struct.field2)
self.assertEquals(42, struct['field3'])

যখন আপনি একটি "ব্যাগ না যে ডাটা ব্যাগ" দরকার হয় তখন পুরোপুরি সহজেই সেগুলি ব্যবহার করুন, এবং যখন nametuples অচেনা হয় ...


সম্ভবত আপনি নির্মাতারা ছাড়া রেখাচিত্রমালা খুঁজছেন:

class Sample:
  name = ''
  average = 0.0
  values = None # list cannot be initialized here!


s1 = Sample()
s1.name = "sample 1"
s1.values = []
s1.values.append(1)
s1.values.append(2)
s1.values.append(3)

s2 = Sample()
s2.name = "sample 2"
s2.values = []
s2.values.append(4)

for v in s1.values:   # prints 1,2,3 --> OK.
  print v
print "***"
for v in s2.values:   # prints 4 --> OK.
  print v






struct