স্লটস__ এর ব্যবহার?


762

__slots__পাইথনের উদ্দেশ্য কী - বিশেষত আমি কখন এটি ব্যবহার করতে চাই এবং কখন নয়?

উত্তর:


1017

পাইথনে, এর উদ্দেশ্য __slots__কী এবং কে এগুলি এড়ানো উচিত?

TLDR:

বিশেষ বৈশিষ্ট্যটি __slots__আপনাকে প্রত্যাশিত ফলাফল সহ আপনার অবজেক্টের দৃষ্টান্তগুলি যেমন প্রত্যাশিত বৈশিষ্ট্যের সাথে প্রত্যাশা করে, সেই উদাহরণটি আপনাকে স্পষ্টভাবে বলতে অনুমতি দেয়:

  1. দ্রুত বৈশিষ্ট্য অ্যাক্সেস।
  2. স্মৃতিতে স্থান সঞ্চয়

স্থান সঞ্চয় থেকে হয়

  1. পরিবর্তে স্লটে মান রেফারেন্স সংরক্ষণ করা __dict__
  2. অস্বীকার করা __dict__এবং __weakref__সৃষ্টি করা যদি পিতামাত্ত শ্রেণিগুলি তাদের অস্বীকার করে এবং আপনি ঘোষণা করেন __slots__

দ্রুত ক্যাভেটস

ছোট সতর্কবাণী, আপনি কেবলমাত্র উত্তরাধিকার গাছে একটি নির্দিষ্ট স্লট একবার ঘোষণা করবেন। উদাহরণ স্বরূপ:

class Base:
    __slots__ = 'foo', 'bar'

class Right(Base):
    __slots__ = 'baz', 

class Wrong(Base):
    __slots__ = 'foo', 'bar', 'baz'        # redundant foo and bar

পাইথন আপত্তি তোলে না যখন আপনি এই ভুলটি পেয়েছেন (এটি সম্ভবত হওয়া উচিত), সমস্যাগুলি অন্যথায় প্রকাশিত নাও হতে পারে, তবে আপনার অবজেক্টগুলি অন্যথায় যা করা উচিত তার চেয়ে বেশি স্থান গ্রহণ করবে। পাইথন ৩.৮:

>>> from sys import getsizeof
>>> getsizeof(Right()), getsizeof(Wrong())
(56, 72)

এটি কারণ বেসের স্লট বর্ণনাকারীর রং এর থেকে পৃথক একটি স্লট রয়েছে। এটি সাধারণত উঠে আসা উচিত নয়, তবে এটি হতে পারে:

>>> w = Wrong()
>>> w.foo = 'foo'
>>> Base.foo.__get__(w)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: foo
>>> Wrong.foo.__get__(w)
'foo'

বৃহত্তম ক্যাভিয়েট একাধিক উত্তরাধিকারের জন্য - একাধিক "Nompty স্লট সহ অভিভাবক ক্লাস" একত্রিত করা যায় না।

এই সীমাবদ্ধতা সামঞ্জস্য করার জন্য, সর্বোত্তম অভ্যাসগুলি অনুসরণ করুন: যথাযথভাবে তাদের কংক্রিট শ্রেণি এবং আপনার নতুন কংক্রিট শ্রেণি সম্মিলিতভাবে উত্তীর্ণ হবে এমন এক বা সমস্ত বাবা-মা'র বিমূর্ততা বাদে ফ্যাক্টর - বিমূর্ততা (গুলি) খালি স্লট প্রদান (ঠিক যেমন অ্যাবস্ট্রাক্ট বেস ক্লাসগুলিতে স্ট্যান্ডার্ড লাইব্রেরি)।

উদাহরণের জন্য নীচে একাধিক উত্তরাধিকারের বিভাগটি দেখুন।

প্রয়োজনীয়তা:

  • এটির __slots__পরিবর্তে স্লটে সংরক্ষণের জন্য নামযুক্ত বৈশিষ্ট্যগুলি থাকতে __dict__, একটি শ্রেণীর অবশ্যই উত্তরাধিকার সূত্রে উত্তরাধিকারী object

  • ক এর সৃষ্টি রোধ করতে __dict__আপনার উত্তরাধিকার হতে হবে objectএবং উত্তরাধিকারের সমস্ত শ্রেণীর অবশ্যই ঘোষণা __slots__করতে হবে এবং তাদের '__dict__'কোনওটির প্রবেশ থাকতে পারে না ।

আপনি পড়া চালিয়ে যেতে ইচ্ছুক হলে অনেকগুলি বিবরণ রয়েছে।

কেন ব্যবহার করুন __slots__: দ্রুত অ্যাট্রিবিউট অ্যাক্সেস।

পাইথনের স্রষ্টা, গিডো ভ্যান রসুম বলেছেন যে তিনি আসলে __slots__দ্রুত অ্যাট্রিবিউট অ্যাক্সেসের জন্য তৈরি করেছিলেন।

এটি পরিমাপযোগ্য তাৎপর্যযুক্ত দ্রুত অ্যাক্সেস প্রদর্শনের জন্য তুচ্ছ

import timeit

class Foo(object): __slots__ = 'foo',

class Bar(object): pass

slotted = Foo()
not_slotted = Bar()

def get_set_delete_fn(obj):
    def get_set_delete():
        obj.foo = 'foo'
        obj.foo
        del obj.foo
    return get_set_delete

এবং

>>> min(timeit.repeat(get_set_delete_fn(slotted)))
0.2846834529991611
>>> min(timeit.repeat(get_set_delete_fn(not_slotted)))
0.3664822799983085

উবুন্টুতে পাইথন 3.5 তে স্লটড অ্যাক্সেস প্রায় 30% দ্রুত।

>>> 0.3664822799983085 / 0.2846834529991611
1.2873325658284342

উইন্ডোজ পাইথন 2 এ আমি এটি প্রায় 15% দ্রুত পরিমাপ করেছি।

কেন ব্যবহার __slots__: মেমরি সঞ্চয়

এর আরেকটি উদ্দেশ্য __slots__হ'ল মেমরির স্থান হ্রাস করা যা প্রতিটি বস্তুর উদাহরণ গ্রহণ করে।

ডকুমেন্টেশনে আমার নিজের অবদানের পেছনের কারণগুলি স্পষ্টভাবে জানিয়েছে :

ব্যবহার করে সংরক্ষণ করা স্থানটি __dict__তাৎপর্যপূর্ণ হতে পারে।

এসকিউএলএলচেমি প্রচুর মেমরি সঞ্চয়কে দায়ী করে __slots__

এটি যাচাই করার জন্য, উবুন্টু লিনাক্সে পাইথন ২.7 এর অ্যানাকোন্ডা বিতরণ ব্যবহার করে guppy.hpy(ওরফে হিপি) এবং sys.getsizeof, __slots__ঘোষিত ছাড়াই শ্রেণীর উদাহরণের আকার এবং অন্য কিছু নয়, 64৪ বাইট। এটি অন্তর্ভুক্ত করে না__dict__ । আবার অলস মূল্যায়নের জন্য পাইথনকে ধন্যবাদ __dict__, রেফারেন্স না দেওয়া পর্যন্ত আপাতদৃষ্টিতে অস্তিত্বের জন্য ডাকা হয় না, তবে ডেটা ছাড়াই ক্লাসগুলি সাধারণত অকেজো হয়। যখন অস্তিত্ব হিসাবে ডাকা হয়, __dict__গুণটি অতিরিক্তভাবে সর্বনিম্ন 280 বাইট হয়।

বিপরীতে, (কোনও ডেটা নেই) হিসাবে __slots__ঘোষিত শ্রেণীর উদাহরণটি ()কেবলমাত্র 16 বাইট এবং স্লটে একটি আইটেম সহ 56 টি বাইট, দুটি সহ।।।

Bit৪ বিট পাইথনের জন্য আমি পাইথন ২.7 এবং ৩.6 এর বাইটে মেমরির খরচটি চিত্রিত করি এবং ডিকটি ৩.6-তে বৃদ্ধি হয় যেখানে (০, ১, এবং ২ টি বৈশিষ্ট্য বাদে) প্রতিটি বিন্দুর জন্য __slots__এবং __dict__(কোনও স্লট সংজ্ঞায়িত হয়নি):

       Python 2.7             Python 3.6
attrs  __slots__  __dict__*   __slots__  __dict__* | *(no slots defined)
none   16         56 + 272   16         56 + 112 | if __dict__ referenced
one    48         56 + 272    48         56 + 112
two    56         56 + 272    56         56 + 112
six    88         56 + 1040   88         56 + 152
11     128        56 + 1040   128        56 + 240
22     216        56 + 3344   216        56 + 408     
43     384        56 + 3344   384        56 + 752

সুতরাং, পাইথন 3-তে ছোট ছোট ডিক্টস থাকা সত্ত্বেও, আমরা দেখতে পেলাম __slots__আমাদের স্মৃতিশক্তি বাঁচানোর জন্য উদাহরণগুলির জন্য কত সুন্দরভাবে স্কেল করা হয়েছে এবং এটিই আপনি ব্যবহার করতে চান এটি একটি প্রধান কারণ __slots__

কেবলমাত্র আমার নোটগুলির সম্পূর্ণতার জন্য, নোট করুন যে ক্লাসের পাইথন 2 এর নেমস্পেসে এক সময়কালীন ব্যয় এবং পাইথন 3-তে 72 বাইট রয়েছে, কারণ স্লটগুলিতে "সদস্য" নামে পরিচিত বৈশিষ্ট্যের মতো ডেটা ডেস্ক্রিপ্টার ব্যবহার করা হয়।

>>> Foo.foo
<member 'foo' of 'Foo' objects>
>>> type(Foo.foo)
<class 'member_descriptor'>
>>> getsizeof(Foo.foo)
72

এর প্রদর্শন __slots__:

একটি তৈরির বিষয়টি অস্বীকার করতে __dict__আপনাকে অবশ্যই সাবক্লাস করতে হবে object:

class Base(object): 
    __slots__ = ()

এখন:

>>> b = Base()
>>> b.a = 'a'
Traceback (most recent call last):
  File "<pyshell#38>", line 1, in <module>
    b.a = 'a'
AttributeError: 'Base' object has no attribute 'a'

বা সংজ্ঞায়িত করে এমন অন্য শ্রেণীর সাবক্লাস __slots__

class Child(Base):
    __slots__ = ('a',)

এবং এখন:

c = Child()
c.a = 'a'

কিন্তু:

>>> c.b = 'b'
Traceback (most recent call last):
  File "<pyshell#42>", line 1, in <module>
    c.b = 'b'
AttributeError: 'Child' object has no attribute 'b'

__dict__স্লটেড অবজেক্টগুলিকে সাবক্লাসিং করার সময় সৃষ্টির অনুমতি দেওয়ার জন্য , কেবলমাত্র এতে যোগ '__dict__'করুন __slots__(স্লটগুলি অর্ডার করা হয়েছে তা নোট করুন এবং ইতিমধ্যে প্যারেন্ট ক্লাসে থাকা স্লটগুলি পুনরাবৃত্তি করা উচিত নয়):

class SlottedWithDict(Child): 
    __slots__ = ('__dict__', 'b')

swd = SlottedWithDict()
swd.a = 'a'
swd.b = 'b'
swd.c = 'c'

এবং

>>> swd.__dict__
{'c': 'c'}

অথবা আপনার এমনকি __slots__আপনার সাবক্লাসে ঘোষণা করার দরকার নেই , এবং আপনি এখনও পিতামাতার কাছ থেকে স্লট ব্যবহার করবেন তবে একটি তৈরির সীমাবদ্ধ করবেন না __dict__:

class NoSlots(Child): pass
ns = NoSlots()
ns.a = 'a'
ns.b = 'b'

এবং:

>>> ns.__dict__
{'b': 'b'}

তবে __slots__একাধিক উত্তরাধিকারের জন্য সমস্যা সৃষ্টি করতে পারে:

class BaseA(object): 
    __slots__ = ('a',)

class BaseB(object): 
    __slots__ = ('b',)

কারণ খালি খালি স্লট উভয়ই পিতামাতার কাছ থেকে শিশু শ্রেণি তৈরি করা ব্যর্থ হয়:

>>> class Child(BaseA, BaseB): __slots__ = ()
Traceback (most recent call last):
  File "<pyshell#68>", line 1, in <module>
    class Child(BaseA, BaseB): __slots__ = ()
TypeError: Error when calling the metaclass bases
    multiple bases have instance lay-out conflict

আপনি এ সমস্যার পাতিত করা, আপনি পারে শুধু অপসারণ __slots__বাবা থেকে, অথবা আপনি বাবা নিয়ন্ত্রণ আছে যদি তাদের বিমূর্ত থেকে স্লট, অথবা refactor খালি করা উচিত:

from abc import ABC

class AbstractA(ABC):
    __slots__ = ()

class BaseA(AbstractA): 
    __slots__ = ('a',)

class AbstractB(ABC):
    __slots__ = ()

class BaseB(AbstractB): 
    __slots__ = ('b',)

class Child(AbstractA, AbstractB): 
    __slots__ = ('a', 'b')

c = Child() # no problem!

যোগ '__dict__'করার জন্য __slots__গতিশীল নিয়োগ পেতে:

class Foo(object):
    __slots__ = 'bar', 'baz', '__dict__'

এবং এখন:

>>> foo = Foo()
>>> foo.boink = 'boink'

সুতরাং '__dict__'স্লটগুলির সাথে আমরা গতিশীল কার্যনির্বাহী হওয়া এবং এখনও আমরা যে নামগুলি প্রত্যাশা করি তার জন্য স্লট থাকার উল্টো দিক দিয়ে কিছু আকারের সুবিধাগুলি হারাব।

যখন আপনি কোনো বস্তু slotted নয় থেকে উত্তরাধিকারী, আপনি শব্দার্থবিদ্যা যখন আপনি ব্যবহার একই সাজানোর পেতে __slots__নাম যে আছে - __slots__, slotted মান বিন্দু যখন অন্য কোন মান উদাহরণস্বরূপ এর রাখা হয় __dict__

__slots__এড়ানোর কারণ আপনি ফ্লাইতে অ্যাট্রিবিউটস যুক্ত করতে সক্ষম হতে চান তা আসলে কোনও ভাল কারণ নয় - এটির প্রয়োজন হলে কেবল "__dict__"আপনার যুক্ত করুন __slots__

আপনার যদি সেই বৈশিষ্ট্যটির প্রয়োজন হয় তবে __weakref__আপনি একইভাবে __slots__স্পষ্টভাবে যুক্ত করতে পারেন।

একটি নেমেডটপল সাবক্লাসিং করার সময় খালি টুপলেতে সেট করুন:

নামকরণকৃত বিল্টিন অপরিবর্তনীয় দৃষ্টান্ত তৈরি করে যা খুব হালকা ওজনের হয় (মূলত: টিপলসের আকার) তবে সুবিধাগুলি পেতে আপনার নিজের প্রয়োজন যদি আপনি সেগুলি সাবক্লাস করেন:

from collections import namedtuple
class MyNT(namedtuple('MyNT', 'bar baz')):
    """MyNT is an immutable and lightweight object"""
    __slots__ = ()

ব্যবহার:

>>> nt = MyNT('bar', 'baz')
>>> nt.bar
'bar'
>>> nt.baz
'baz'

এবং একটি অপ্রত্যাশিত বৈশিষ্ট্য নির্ধারণের চেষ্টা একটি উত্থাপন করে AttributeErrorকারণ আমরা এর সৃষ্টি প্রতিরোধ করেছি __dict__:

>>> nt.quux = 'quux'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyNT' object has no attribute 'quux'

আপনি ছাড়ার মাধ্যমে সৃষ্টির অনুমতি দিতে পারেন , তবে আপনি টিপলের সাব টাইপগুলি সহ খালিটি ব্যবহার করতে পারবেন না ।__dict____slots__ = ()__slots__

বৃহত্তম গুহাত: একাধিক উত্তরাধিকার

এমনকি খালি খালি স্লট একাধিক পিতা-মাতার জন্য একই থাকলেও সেগুলি একসাথে ব্যবহার করা যায় না:

class Foo(object): 
    __slots__ = 'foo', 'bar'
class Bar(object):
    __slots__ = 'foo', 'bar' # alas, would work if empty, i.e. ()

>>> class Baz(Foo, Bar): pass
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    multiple bases have instance lay-out conflict

__slots__পিতামাতার মধ্যে একটি খালি ব্যবহার করা সর্বাধিক নমনীয়তা সরবরাহ করে বলে মনে হয়, বাচ্চাকে বাধা দেওয়ার বা অনুমতি দেওয়ার জন্য বাছাই করতে দেওয়া ( '__dict__'গতিশীল কার্যনির্বাহীকরণ যোগ করে, উপরের অংশটি দেখুন) একটিটির সৃষ্টি__dict__ :

class Foo(object): __slots__ = ()
class Bar(object): __slots__ = ()
class Baz(Foo, Bar): __slots__ = ('foo', 'bar')
b = Baz()
b.foo, b.bar = 'foo', 'bar'

আপনার স্লট থাকতে হবে না - সুতরাং আপনি যদি এগুলি যুক্ত করেন এবং পরে এগুলি সরিয়ে থাকেন তবে এটি কোনও সমস্যা না করে।

এখানে একটি অঙ্গ নিয়ে বেরোন : আপনি যদি মিক্সিনগুলি রচনা করেন বা বিমূর্ত বেস ক্লাসগুলি ব্যবহার করেন , যা ইনস্ট্যান্ট করার উদ্দেশ্যে নয়, তবে __slots__তাদের পিতামাতার একটি ফাঁকা সাবক্ল্যাসারদের জন্য নমনীয়তার দিক থেকে যাওয়ার সেরা উপায় বলে মনে হয়।

প্রদর্শনের জন্য, প্রথমে কোড সহ একটি শ্রেণি তৈরি করি যা আমরা একাধিক উত্তরাধিকারের অধীনে ব্যবহার করতে চাই

class AbstractBase:
    __slots__ = ()
    def __init__(self, a, b):
        self.a = a
        self.b = b
    def __repr__(self):
        return f'{type(self).__name__}({repr(self.a)}, {repr(self.b)})'

প্রত্যাশিত স্লট উত্তরাধিকার সূত্রে এবং ঘোষণা করে আমরা উপরেরগুলি সরাসরি ব্যবহার করতে পারি:

class Foo(AbstractBase):
    __slots__ = 'a', 'b'

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

class AbstractBaseC:
    __slots__ = ()
    @property
    def c(self):
        print('getting c!')
        return self._c
    @c.setter
    def c(self, arg):
        print('setting c!')
        self._c = arg

এখন যদি উভয় ঘাঁটিতে অযৌক্তিক স্লট থাকে তবে আমরা নীচেরটি করতে পারিনি। (প্রকৃতপক্ষে, আমরা যদি চাইতাম তবে আমরা AbstractBaseক্রেডিট স্লট a এবং b দিতে পারতাম এবং সেগুলি নীচের ঘোষণার বাইরে রেখে দিতাম - এগুলিকে ছেড়ে দেওয়া ভুল হত):

class Concretion(AbstractBase, AbstractBaseC):
    __slots__ = 'a b _c'.split()

এবং এখন আমাদের একাধিক উত্তরাধিকারের মাধ্যমে উভয় থেকেই কার্যকারিতা রয়েছে এবং এখনও তা অস্বীকার করতে __dict__এবং __weakref__তাত্ক্ষণিক করতে পারি :

>>> c = Concretion('a', 'b')
>>> c.c = c
setting c!
>>> c.c
getting c!
Concretion('a', 'b')
>>> c.d = 'd'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Concretion' object has no attribute 'd'

স্লট এড়ানোর জন্য অন্যান্য ক্ষেত্রে:

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

আপনি বাকী __slots__ ডকুমেন্টেশন (৩. dev ডিভ ডক্স সর্বাধিক বর্তমান) থেকে আরও গুপ্তচরকে জ্বালাতন করতে সক্ষম হতে পারেন , যার জন্য আমি সাম্প্রতিক অবদান রেখেছি।

অন্যান্য উত্তরের সমালোচনা

বর্তমান শীর্ষ উত্তরগুলি পুরানো তথ্যের উদ্ধৃতি দেয় এবং বেশ হস্ত-avyেউযুক্ত এবং কিছু গুরুত্বপূর্ণ উপায়ে চিহ্নটি মিস করে।

"কেবলমাত্র __slots__প্রচুর অবজেক্ট ইনস্ট্যান্ট করার সময় ব্যবহার করবেন না "

আমি উদ্ধৃতি:

"আপনি __slots__যদি একই শ্রেণীর অনেকগুলি (শত, হাজার) বস্তু ইনস্ট্যান্ট করতে যাচ্ছেন তবে আপনি ব্যবহার করতে চান " "

অ্যাবস্ট্রাক্ট বেস ক্লাস, উদাহরণস্বরূপ, collectionsমডিউল থেকে , তাত্ক্ষণিকভাবে নয়, তবুও __slots__তাদের জন্য ঘোষিত হয়।

কেন?

যদি কোনও ব্যবহারকারী অস্বীকার করতে __dict__বা __weakref__তৈরি করতে চান তবে সেই জিনিসগুলি অবশ্যই পিতামাতার ক্লাসে উপলভ্য নয়।

__slots__ ইন্টারফেস বা মিক্সিন তৈরি করার সময় পুনরায় ব্যবহারযোগ্যতায় অবদান রাখে।

এটি সত্য যে অনেক পাইথন ব্যবহারকারী পুনরায় ব্যবহারযোগ্যতার জন্য লেখেন না, তবে আপনি যখন হন, অপ্রয়োজনীয় স্থান ব্যবহার অস্বীকার করার বিকল্প থাকা মূল্যবান।

__slots__ পিকিং ভাঙে না

একটি স্লটেড বস্তু বাছাই করার সময়, আপনি এটি একটি বিভ্রান্তিকর অভিযোগ করতে পারেন TypeError:

>>> pickle.loads(pickle.dumps(f))
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled

এটি আসলে ভুল। এই বার্তাটি প্রাচীনতম প্রোটোকল থেকে এসেছে, এটি ডিফল্ট। আপনি -1যুক্তি দিয়ে সর্বশেষ প্রোটোকলটি নির্বাচন করতে পারেন । পাইথন ২.7 এ এটি হবে 2(যা ২.৩ সালে প্রবর্তিত হয়েছিল) এবং এটি ৩.6-এ রয়েছে 4

>>> pickle.loads(pickle.dumps(f, -1))
<__main__.Foo object at 0x1129C770>

পাইথন ২.7 এ:

>>> pickle.loads(pickle.dumps(f, 2))
<__main__.Foo object at 0x1129C770>

পাইথন ৩.6

>>> pickle.loads(pickle.dumps(f, 4))
<__main__.Foo object at 0x1129C770>

সুতরাং আমি এটি মনে রাখব, কারণ এটি একটি সমাধান সমস্যা।

(2 শে অক্টোবর, 2016 অবধি) সমালোচনা

প্রথম অনুচ্ছেদটি অর্ধেক সংক্ষিপ্ত ব্যাখ্যা, অর্ধেক ভবিষ্যদ্বাণীমূলক। এখানে একমাত্র অংশ যা আসলে প্রশ্নের উত্তর দেয়

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

দ্বিতীয়ার্ধটি ইচ্ছাকৃত চিন্তাভাবনা, এবং ছাপ ছাড়াই:

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

পাইথন আসলে এর অনুরূপ কিছু করে, __dict__এটি অ্যাক্সেস হওয়ার পরে কেবল তৈরি করে , তবে কোনও ডেটা ছাড়াই প্রচুর অবজেক্ট তৈরি করা মোটামুটি হাস্যকর।

দ্বিতীয় অনুচ্ছেদটি এড়াতে প্রকৃত কারণগুলিকে ছাড়িয়ে যায় এবং মিস করে __slots__। নিচে না একটি আসল কারণ স্লট এড়াতে (জন্য প্রকৃত কারণ উপরে আমার উত্তর বাকি দেখুন।):

তারা নিয়ন্ত্রণের শৌখিনতা এবং স্ট্যাটিক টাইপিং ওয়েইনিজ দ্বারা আপত্তিজনকভাবে ব্যবহার করা যেতে পারে এমনভাবে স্লটযুক্ত বস্তুর আচরণ পরিবর্তন করে।

এরপরে পাইথনের সাথে সেই বিকৃত লক্ষ্য অর্জনের অন্যান্য উপায়গুলি নিয়ে আলোচনা করা যায়, এর সাথে কিছু করার বিষয়ে আলোচনা করা হয় না __slots__

তৃতীয় অনুচ্ছেদটি আরও ইচ্ছুক চিন্তাভাবনা। একসাথে এটি বেশিরভাগ দ্য মার্ক-কন্টেন্ট যা উত্তরদাতা এমনকি লেখকও করেনি এবং সাইটের সমালোচকদের জন্য গোলাবারুদে অবদান রাখে।

মেমরি ব্যবহারের প্রমাণ

কিছু সাধারণ অবজেক্ট এবং স্লটেড অবজেক্ট তৈরি করুন:

>>> class Foo(object): pass
>>> class Bar(object): __slots__ = ()

এর মধ্যে দশ লক্ষ ইনস্ট্যান্ট করুন:

>>> foos = [Foo() for f in xrange(1000000)]
>>> bars = [Bar() for b in xrange(1000000)]

এর সাথে পরিদর্শন করুন guppy.hpy().heap():

>>> guppy.hpy().heap()
Partition of a set of 2028259 objects. Total size = 99763360 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0 1000000  49 64000000  64  64000000  64 __main__.Foo
     1     169   0 16281480  16  80281480  80 list
     2 1000000  49 16000000  16  96281480  97 __main__.Bar
     3   12284   1   987472   1  97268952  97 str
...

নিয়মিত জিনিস এবং তাদের অ্যাক্সেস করুন __dict__এবং আবার পরীক্ষা করুন:

>>> for f in foos:
...     f.__dict__
>>> guppy.hpy().heap()
Partition of a set of 3028258 objects. Total size = 379763480 bytes.
 Index  Count   %      Size    % Cumulative  % Kind (class / dict of class)
     0 1000000  33 280000000  74 280000000  74 dict of __main__.Foo
     1 1000000  33  64000000  17 344000000  91 __main__.Foo
     2     169   0  16281480   4 360281480  95 list
     3 1000000  33  16000000   4 376281480  99 __main__.Bar
     4   12284   0    987472   0 377268952  99 str
...

এটি পাইথনের ইতিহাসের সাথে সামঞ্জস্যপূর্ণ, পাইথন ২.২-এ একীকরণের ধরণ এবং ক্লাসগুলি থেকে

যদি আপনি একটি অন্তর্নির্মিত ধরণের সাবক্লাস করেন তবে অতিরিক্ত স্থান স্বয়ংক্রিয়ভাবে সংস্থান করার জন্য দৃষ্টান্তগুলিতে যুক্ত হবে __dict__এবং __weakrefs__। ( __dict__আপনি এটি ব্যবহার না করা অবধি এটি আরম্ভ করা হয়নি, সুতরাং আপনার তৈরি প্রতিটি উদাহরণের জন্য খালি অভিধান দ্বারা দখল করা স্থান সম্পর্কে আপনার চিন্তা করা উচিত নয়)) আপনার যদি এই অতিরিক্ত স্থানের প্রয়োজন না হয় তবে আপনি " __slots__ = []" বাক্যাংশটি যোগ করতে পারেন তোমার শ্রেণী.


14
বাহ, একটি উত্তরের নরক - ধন্যবাদ! যাইহোক, আমি class Child(BaseA, BaseB): __slots__ = ('a', 'b')খালি-স্লট-পিতামাতার সাথে উদাহরণটি পাইনি। কেন এখানে একটি dictproxyপরিবর্তে একটি উত্থাপন সৃষ্টি AttributeErrorজন্য c?
স্ক্যান্ডিক্স

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

38
এই উত্তরটি সম্পর্কে অফিসিয়াল পাইথন ডকুমেন্টেশনের অংশ হওয়া উচিত __slots__। সিরিয়াসলি! ধন্যবাদ!
নাইটএলফিক

13
@ নাইটএলফিক এটি বিশ্বাস করুন বা করবেন না, আমি __slots__প্রায় এক বছর আগে পাইথন ডক্সে অবদান রেখেছিলাম
অ্যারন হল

কল্পিতভাবে বিস্তারিত উত্তর। আমার একটি প্রশ্ন আছে: যদি কেউ ক্যাভেটগুলির একটির উপর আঘাত না দেয় তবে ডিফল্ট হিসাবে কেউ স্লট ব্যবহার করা উচিত , বা স্লটগুলি বিবেচনা করার মতো কিছু যদি আপনি জানেন যে আপনি গতি / স্মৃতির জন্য লড়াই করতে যাচ্ছেন? এটিকে অন্য উপায়ে বলতে কি, আপনি কি কোনও নবজাতককে তাদের সম্পর্কে জানতে এবং তাদের শুরু থেকেই ব্যবহার করতে উত্সাহিত করবেন?
ফ্রিথবিস

265

জ্যাকব হ্যালেনের উদ্ধৃতি :

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

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

সিপিথনকে ছাড়াই স্থান সাশ্রয় করার জন্য যথেষ্ট স্মার্ট __slots__করা একটি বড় উদ্যোগ গ্রহণ, যার কারণ সম্ভবত এটি পি 3 কে (এখনও) এর পরিবর্তনের তালিকায় নেই।


86
আমি "স্থিতিশীল টাইপিং" / সজ্জা বিন্দু সম্পর্কিত কিছু বিবরণ দেখতে চাই, সান পেজোরেটিভস। অনুপস্থিত তৃতীয় পক্ষের উদ্ধৃতি অসহনীয়। __slots__স্থির টাইপিংয়ের মতো একই সমস্যাগুলিকে সম্বোধন করে না। উদাহরণস্বরূপ, সি ++ এ এটি কোনও সদস্যের ভেরিয়েবলের ঘোষণাকে সীমাবদ্ধ করা হচ্ছে না, এটি সেই ভেরিয়েবলের জন্য একটি অযৌক্তিক ধরণের (এবং সংকলক প্রয়োগ করা) অ্যাসাইনমেন্ট। আমি __slots__কেবল কথোপকথনে আগ্রহী, এর ব্যবহারকে সমর্থন করছি না । ধন্যবাদ!
হাইওয়েলন

126

আপনি __slots__যদি একই শ্রেণীর অনেকগুলি (শত, হাজার) বস্তু ইনস্ট্যান্ট করতে যাচ্ছেন তবে আপনি ব্যবহার করতে চান । __slots__কেবল একটি মেমরি অপ্টিমাইজেশন সরঞ্জাম হিসাবে উপস্থিত।

__slots__এট্রিবিউট তৈরিতে বাধা দেওয়ার জন্য এটি ব্যবহার করতে অত্যন্ত নিরুৎসাহিত করা হয়েছে ।

__slots__ডিফল্ট (প্রাচীনতম) আচার প্রোটোকল দিয়ে কাজ করবে না এমন জিনিসগুলি বাছাই করা ; পরবর্তী সংস্করণ নির্দিষ্ট করা দরকার।

পাইথনের অন্যান্য কিছু অন্তঃসংশোধন বৈশিষ্ট্যগুলিও বিরূপ প্রভাবিত হতে পারে।


10
আমি আমার উত্তরে একটি স্লটেড অবজেক্টকে বাছাই করে দেখিয়েছি এবং আপনার উত্তরের প্রথম অংশটিকেও সম্বোধন করছি।
অ্যারন হল

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

61

প্রতিটি পাইথন অবজেক্টের একটি __dict__অ্যাট্রিবিউট থাকে যা একটি অভিধান যা অন্যান্য সমস্ত বৈশিষ্ট্যযুক্ত। উদাহরণস্বরূপ, আপনি self.attrপাইথন টাইপ করার সময় আসলে কাজ করে self.__dict__['attr']। যেহেতু আপনি কল্পনা করতে পারেন অ্যাট্রিবিউটিকে সঞ্চয় করতে কোনও অভিধান ব্যবহার করার জন্য এটি অ্যাক্সেস করার জন্য কিছু অতিরিক্ত জায়গা এবং সময় লাগে।

তবে, আপনি যখন ব্যবহার করবেন তখন __slots__class শ্রেণীর জন্য তৈরি যে কোনও বস্তুর কোনও __dict__বৈশিষ্ট্য থাকবে না । পরিবর্তে, সমস্ত অ্যাট্রিবিউট অ্যাক্সেস পয়েন্টারগুলির মাধ্যমে সরাসরি করা হয়।

সুতরাং যদি আপনি একটি পূর্ণ বর্গের পরিবর্তে কোনও সি স্টাইলের কাঠামো চান তবে আপনি __slots__অবজেক্টগুলির আকার কমপ্যাক্ট করতে এবং অ্যাট্রিবিউট অ্যাক্সেসের সময় কমাতে ব্যবহার করতে পারেন । একটি ভাল উদাহরণ x ও y বৈশিষ্ট্যযুক্ত একটি পয়েন্ট শ্রেণি। আপনার যদি অনেকগুলি পয়েন্ট থাকে তবে আপনি __slots__কিছু স্মৃতি সংরক্ষণ করতে চেষ্টা করতে পারেন ।


10
না, __slots__সংজ্ঞায়িত সহ শ্রেণীর উদাহরণ সি-স্টাইলের কাঠামোর মতো নয় । সূচকগুলিতে অ্যাট্রিবিউটের নাম ম্যাপিংয়ের জন্য একটি শ্রেণির স্তরের অভিধান রয়েছে, অন্যথায় নিম্নলিখিতগুলি সম্ভব হবে না: class A(object): __slots__= "value",\n\na=A(); setattr(a, 'value', 1)আমি সত্যিই মনে করি এই উত্তরটি পরিষ্কার করা উচিত (আপনি চাইলে আমি এটি করতে পারি)। এছাড়াও, আমি নিশ্চিত না যে এর instance.__hidden_attributes[instance.__class__[attrname]]চেয়ে দ্রুত instance.__dict__[attrname]
tzot

22

অন্যান্য উত্তরগুলির পাশাপাশি, এখানে ব্যবহারের উদাহরণ __slots__:

>>> class Test(object):   #Must be new-style class!
...  __slots__ = ['x', 'y']
... 
>>> pt = Test()
>>> dir(pt)
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__', 
 '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', 
 '__repr__', '__setattr__', '__slots__', '__str__', 'x', 'y']
>>> pt.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: x
>>> pt.x = 1
>>> pt.x
1
>>> pt.z = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute 'z'
>>> pt.__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__dict__'
>>> pt.__slots__
['x', 'y']

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


11

ফাংশন কল করার সময় "নামযুক্ত পদ্ধতি প্রেরণ" মুছে ফেলার জন্য লাইব্রেরি কলগুলির জন্য স্লটগুলি খুব দরকারী। এসডাব্লুআইজি ডকুমেন্টেশনে এটি উল্লেখ করা হয়েছে । স্লট ব্যবহার করে সাধারণত ডাকা ফাংশনগুলির জন্য ফাংশন ওভারহেডকে হ্রাস করতে চায় এমন উচ্চ কার্য সম্পাদনের লাইব্রেরিগুলির জন্য much

এখন এটি সরাসরি ওপিএস প্রশ্নের সাথে সম্পর্কিত নাও হতে পারে। এটি কোনও বস্তুর স্লট সিনট্যাক্স ব্যবহারের চেয়ে এক্সটেনশানগুলি বাড়ানোর সাথে সম্পর্কিত । তবে এটি স্লট এবং তাদের পিছনে কিছু যুক্তির ব্যবহারের জন্য ছবিটি সম্পূর্ণ করতে সহায়তা করে।


7

একটি শ্রেণীর উদাহরণের একটি বৈশিষ্ট্যের 3 টি বৈশিষ্ট্য রয়েছে: উদাহরণ, বৈশিষ্ট্যের নাম এবং বৈশিষ্ট্যের মান the

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

উদাহরণ (বৈশিষ্ট্য) -> মান

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

বৈশিষ্ট্য (উদাহরণ) -> মান

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

বৈশিষ্ট্য (মান) -> উদাহরণ


এটি একটি ভাল ভাগ, এবং ফ্লাইওয়েটগুলিও প্রস্তাব দেয় এমন উত্তরগুলির একটিতে একটি মন্তব্যে ভাল মানাবে না, তবে এটি নিজেই প্রশ্নের সম্পূর্ণ উত্তর নয়। বিশেষত (প্রশ্নের ঠিক প্রসঙ্গে): ফ্লাইওয়েট কেন এবং "কোনটি কে এড়ানো উচিত ..." __slots__?
মার্লিন মরগান-গ্রাহাম

@ মের্লিন মরগান-গ্রাহাম, এটি যা বেছে নেওয়ার ইঙ্গিত হিসাবে কাজ করে: নিয়মিত অ্যাক্সেস, __স্লটস__ বা ফ্লাইওয়েট।
দিমিত্রি রুবানোভিচ

3

__slot__গুণাবলীর খুব সাধারণ উদাহরণ

সমস্যা: ছাড়া __slots__

__slot__আমার ক্লাসে যদি অ্যাট্রিবিউট না থাকে তবে আমি আমার অবজেক্টগুলিতে নতুন অ্যাট্রিবিউট যুক্ত করতে পারি।

class Test:
    pass

obj1=Test()
obj2=Test()

print(obj1.__dict__)  #--> {}
obj1.x=12
print(obj1.__dict__)  # --> {'x': 12}
obj1.y=20
print(obj1.__dict__)  # --> {'x': 12, 'y': 20}

obj2.x=99
print(obj2.__dict__)  # --> {'x': 99}

আপনি যদি উপরের উদাহরণটির দিকে তাকান তবে দেখতে পাবেন যে 1 জ 1 এবং অজ 2 এর নিজস্ব x এবং y বৈশিষ্ট্য রয়েছে এবং পাইথন dictপ্রতিটি বস্তুর জন্য একটি বৈশিষ্ট্যও তৈরি করেছে ( اعتراض 1 এবং অবজেক্ট 2 )।

ধরুন আমার ক্লাস টেস্টে যদি এমন হাজার হাজার বস্তু থাকে? dictপ্রতিটি বস্তুর জন্য অতিরিক্ত বৈশিষ্ট্য তৈরি করা আমার কোডে প্রচুর ওভারহেড (মেমরি, কম্পিউটিং শক্তি ইত্যাদি) তৈরি করবে।

সমাধান: সাথে __slots__

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

class Test:
    __slots__=("x")

obj1=Test()
obj2=Test()
obj1.x=12
print(obj1.x)  # --> 12
obj2.x=99
print(obj2.x)  # --> 99

obj1.y=28
print(obj1.y)  # --> AttributeError: 'Test' object has no attribute 'y'

2

এর অপর কিছুটা অস্পষ্ট ব্যবহার __slots__হ'ল প্রক্সিটাইপস প্যাকেজ থেকে কোনও বস্তুর প্রক্সিটির বৈশিষ্ট্য যুক্ত করা, এটি পিইএকে প্রকল্পের পূর্ববর্তী অংশ। এটি ObjectWrapperআপনাকে অন্য কোনও বস্তুর প্রক্সি দেওয়ার অনুমতি দেয় তবে প্রক্সড অবজেক্টের সাথে সমস্ত মিথস্ক্রিয়াটিকে বিরত রাখে। এটি খুব সাধারণভাবে ব্যবহৃত হয় না (এবং পাইথন 3 সমর্থন নয়) তবে থ্রেডাডো ভিত্তিক একটি অ্যাসিঙ্ক প্রয়োগের চারপাশে থ্রেড-নিরাপদ ব্লকিংয়ের মোড়কে কার্যকর করার জন্য আমরা এটি ব্যবহার করেছি যা থ্রেড-সেফটি ব্যবহার করে আইলোপের মাধ্যমে প্রক্সাইড অবজেক্টের সমস্ত অ্যাক্সেস বাউন্স করে that concurrent.Futureসিঙ্ক্রোনাইজ করার জন্য ফলাফলগুলি এবং ফলাফলগুলি প্রত্যাবর্তন করে।

ডিফল্টরূপে প্রক্সি অবজেক্টে কোনও অ্যাট্রিবিউট অ্যাক্সেস আপনাকে প্রক্সিযুক্ত বস্তু থেকে ফলাফল দেবে। যদি আপনাকে প্রক্সি অবজেক্টে একটি অ্যাট্রিবিউট যুক্ত __slots__করতে হয় তবে ব্যবহার করা যেতে পারে।

from peak.util.proxies import ObjectWrapper

class Original(object):
    def __init__(self):
        self.name = 'The Original'

class ProxyOriginal(ObjectWrapper):

    __slots__ = ['proxy_name']

    def __init__(self, subject, proxy_name):
        # proxy_info attributed added directly to the
        # Original instance, not the ProxyOriginal instance
        self.proxy_info = 'You are proxied by {}'.format(proxy_name)

        # proxy_name added to ProxyOriginal instance, since it is
        # defined in __slots__
        self.proxy_name = proxy_name

        super(ProxyOriginal, self).__init__(subject)

if __name__ == "__main__":
    original = Original()
    proxy = ProxyOriginal(original, 'Proxy Overlord')

    # Both statements print "The Original"
    print "original.name: ", original.name
    print "proxy.name: ", proxy.name

    # Both statements below print 
    # "You are proxied by Proxy Overlord", since the ProxyOriginal
    # __init__ sets it to the original object 
    print "original.proxy_info: ", original.proxy_info
    print "proxy.proxy_info: ", proxy.proxy_info

    # prints "Proxy Overlord"
    print "proxy.proxy_name: ", proxy.proxy_name
    # Raises AttributeError since proxy_name is only set on 
    # the proxy object
    print "original.proxy_name: ", proxy.proxy_name

1

আপনার কাছে - মূলত - কোনও কাজের নয় __slots__

আপনি যখন প্রয়োজন মনে করেন সেই সময়ের জন্য __slots__, আপনি আসলে লাইটওয়েট বা ফ্লাইওয়েট ডিজাইনের নিদর্শনগুলি ব্যবহার করতে চান । এগুলি হ'ল যখন আপনি আর পাইথন অবজেক্টগুলি আর ব্যবহার করতে চান না। পরিবর্তে, আপনি একটি অ্যারের, কাঠামো, বা নমির অ্যারের চারপাশে পাইথন অবজেক্টের মতো মোড়ক চাই।

class Flyweight(object):

    def get(self, theData, index):
        return theData[index]

    def set(self, theData, index, value):
        theData[index]= value

শ্রেণীর মতো মোড়কের কোনও বৈশিষ্ট্য নেই - এটি কেবল এমন পদ্ধতি সরবরাহ করে যা অন্তর্নিহিত ডেটাগুলিতে কাজ করে। পদ্ধতিগুলি ক্লাস পদ্ধতিতে হ্রাস করা যেতে পারে। প্রকৃতপক্ষে, এটি কেবলমাত্র ডেটা অন্তর্নিহিত অ্যারে অপারেটিং ফাংশন হ্রাস করা যেতে পারে।


17
ফ্লাইওয়েটের কী করার আছে __slots__?
oefe

3
@oefe: আমি অবশ্যই আপনার প্রশ্নটি পাই না। আমি আমার উত্তরটি উদ্ধৃত করতে পারি, যদি এটি "যদি আপনি মনে করেন যে আপনার স্লট দরকার হতে পারে , আপনি আসলে ... ফ্লাইওয়েট ডিজাইনের ধরণ" ব্যবহার করতে চান helps স্লটগুলির সাথে ফ্লাইওয়েটের এটিই ছিল । আপনার কি আরও নির্দিষ্ট প্রশ্ন আছে?
এস .লট

21
@oefe: ফ্লাইওয়েট এবং __slots__মেমরি সংরক্ষণের জন্য উভয়ই অনুকূলিতকরণ কৌশল। __slots__আপনার অনেকগুলি অবজেক্টের পাশাপাশি ফ্লাইওয়েট ডিজাইনের ধরণ থাকলে উপকারগুলি দেখায়। দুজনেই একই সমস্যা সমাধান করে।
jfs

7
স্লট ব্যবহার এবং মেমরির ব্যবহার এবং গতি সম্পর্কিত ফ্লাইওয়েট ব্যবহারের মধ্যে কি কোনও তুলনা উপলব্ধ?
কনটুলই

8
যদিও ফ্লাইওয়েট অবশ্যই কিছু প্রসঙ্গে অবশ্যই কার্যকর, বিশ্বাস করুন বা না করুন, "যখন আমি একটি জিলিয়ন অবজেক্ট তৈরি করি তখন পাইথনে আমি কীভাবে মেমরির ব্যবহার হ্রাস করতে পারি" এর উত্তরটি সর্বদা "আপনার জিলিয়ন বস্তুর জন্য পাইথন ব্যবহার করবেন না" always কখনও কখনও __slots__সত্যই উত্তরটি হয় এবং এভগেনি যেমন উল্লেখ করে, এটি একটি সাধারণ চিন্তাভাবনা হিসাবে যুক্ত করা যেতে পারে (যেমন আপনি প্রথমে যথার্থতার দিকে মনোনিবেশ করতে পারেন, এবং তারপরে পারফরম্যান্স যুক্ত করতে পারেন)।
প্যাট্রিক মউপিন

0

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

এখানে মিলিয়ন এন্ট্রি সহ স্লট ব্যবহার করে এবং স্লট ছাড়াই অবজেক্ট ট্রি তৈরির তুলনা করা হয়েছে। রেফারেন্স হিসাবে গাছগুলির জন্য প্লেইন ডিক্টস ব্যবহার করার সময় কার্য সম্পাদন (ওএসএক্সে পাই 2.7.10):

********** RUN 1 **********
1.96036410332 <class 'css_tree_select.element.Element'>
3.02922606468 <class 'css_tree_select.element.ElementNoSlots'>
2.90828204155 dict
********** RUN 2 **********
1.77050495148 <class 'css_tree_select.element.Element'>
3.10655999184 <class 'css_tree_select.element.ElementNoSlots'>
2.84120798111 dict
********** RUN 3 **********
1.84069895744 <class 'css_tree_select.element.Element'>
3.21540498734 <class 'css_tree_select.element.ElementNoSlots'>
2.59615707397 dict
********** RUN 4 **********
1.75041103363 <class 'css_tree_select.element.Element'>
3.17366290092 <class 'css_tree_select.element.ElementNoSlots'>
2.70941114426 dict

পরীক্ষার ক্লাস (পরিচয়, স্লট থেকে সংযোজন):

class Element(object):
    __slots__ = ['_typ', 'id', 'parent', 'childs']
    def __init__(self, typ, id, parent=None):
        self._typ = typ
        self.id = id
        self.childs = []
        if parent:
            self.parent = parent
            parent.childs.append(self)

class ElementNoSlots(object): (same, w/o slots)

টেস্টকোড, ভার্বোজ মোড:

na, nb, nc = 100, 100, 100
for i in (1, 2, 3, 4):
    print '*' * 10, 'RUN', i, '*' * 10
    # tree with slot and no slot:
    for cls in Element, ElementNoSlots:
        t1 = time.time()
        root = cls('root', 'root')
        for i in xrange(na):
            ela = cls(typ='a', id=i, parent=root)
            for j in xrange(nb):
                elb = cls(typ='b', id=(i, j), parent=ela)
                for k in xrange(nc):
                    elc = cls(typ='c', id=(i, j, k), parent=elb)
        to =  time.time() - t1
        print to, cls
        del root

    # ref: tree with dicts only:
    t1 = time.time()
    droot = {'childs': []}
    for i in xrange(na):
        ela =  {'typ': 'a', id: i, 'childs': []}
        droot['childs'].append(ela)
        for j in xrange(nb):
            elb =  {'typ': 'b', id: (i, j), 'childs': []}
            ela['childs'].append(elb)
            for k in xrange(nc):
                elc =  {'typ': 'c', id: (i, j, k), 'childs': []}
                elb['childs'].append(elc)
    td = time.time() - t1
    print td, 'dict'
    del droot
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.