tচ্ছিক কীওয়ার্ড আর্গুমেন্টের জন্য নামডটপল এবং ডিফল্ট মান


300

আমি দীর্ঘতর ফাঁকা "ডেটা" শ্রেণিকে নামকরণিত টিপলে রূপান্তর করার চেষ্টা করছি। আমার ক্লাসটি বর্তমানে এর মতো দেখাচ্ছে:

class Node(object):
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

namedtupleএটি রূপান্তরিত হওয়ার পরে দেখে মনে হচ্ছে:

from collections import namedtuple
Node = namedtuple('Node', 'val left right')

তবে এখানে একটি সমস্যা আছে। আমার মূল ক্লাসটি আমাকে কেবল একটি মান দিয়ে যেতে দেয় এবং নাম / কীওয়ার্ড আর্গুমেন্টের জন্য ডিফল্ট মান ব্যবহার করে ডিফল্টটির যত্ন নেয়। কিছুটা এইরকম:

class BinaryTree(object):
    def __init__(self, val):
        self.root = Node(val)

তবে এটি আমার রিফ্যাক্টরযুক্ত নামের টুপলের ক্ষেত্রে কাজ করে না কারণ এটি আমার সমস্ত ক্ষেত্রটি পাস করার প্রত্যাশা করে। আমি অবশ্যই এর ঘটনাগুলি প্রতিস্থাপন Node(val)করতে পারি Node(val, None, None)তবে এটি আমার পছন্দ নয়।

তাহলে কি এমন কোনও ভাল কৌশল আছে যা প্রচুর কোড জটিলতা (রূপক) যুক্ত না করে আমার পুনর্লিখনকে সফল করে তুলতে পারে বা আমার কি কেবল বড়িটি গ্রাস করে "অনুসন্ধান এবং প্রতিস্থাপন" দিয়ে এগিয়ে যাওয়া উচিত? :)


2
আপনি কেন এই রূপান্তর করতে চান? আমি আপনার মূল Nodeক্লাসটি ঠিক তেমন পছন্দ করি। নামকরণ tuple রূপান্তর কেন?
স্টিভাহ

34
আমি এই রূপান্তরটি তৈরি করতে চেয়েছিলাম কারণ বর্তমান Nodeএবং অন্যান্য শ্রেণিগুলি বিভিন্ন ক্ষেত্রের একগুচ্ছ সহ সাধারণ ডেটা ধারক মান বস্তু ( Nodeকেবলমাত্র এটির মধ্যে একটি )। এই শ্রেণীর ঘোষণাগুলি আইএমএইচও লাইন শোরগোলের চেয়ে বেশি কিছুই নয় তাই এগুলি ছাঁটাই করতে চেয়েছিল। প্রয়োজনীয় কিছু না কেন এমন রক্ষণাবেক্ষণ করবেন? :)
সাসুক

আপনার ক্লাসে কোনও পদ্ধতি ফাংশন নেই? উদাহরণস্বরূপ, আপনার কাছে এমন কোনও .debug_print()পদ্ধতি নেই যা গাছটি হাঁটে এবং মুদ্রণ করে?
স্টিভাহ

2
অবশ্যই আমি করি, তবে এটি BinaryTreeক্লাসের জন্য। Nodeএবং অন্যান্য ডেটা হোল্ডারদের যেমন বিশেষ পদ্ধতিগুলির প্রয়োজন হয় না যেমন দেওয়া tuples একটি শালীন __str__এবং __repr__প্রতিনিধিত্ব আছে given :)
সাসুক

ঠিক আছে, যুক্তিসঙ্গত বলে মনে হচ্ছে। এবং আমি মনে করি Ignacio Vazquez-Abrams আপনাকে উত্তর দিয়েছে: আপনার নোডের জন্য একটি ফাংশন ব্যবহার করুন যা ডিফল্ট মানগুলি করে।
স্টিভাহ

উত্তর:


532

পাইথন 3.7

ডিফল্ট প্যারামিটার ব্যবহার করুন ।

>>> from collections import namedtuple
>>> fields = ('val', 'left', 'right')
>>> Node = namedtuple('Node', fields, defaults=(None,) * len(fields))
>>> Node()
Node(val=None, left=None, right=None)

বা আরও ভাল, নতুন ডেটাচ্লাস লাইব্রেরিটি ব্যবহার করুন , যা নামকরণের তুলনায় অনেক সুন্দর।

>>> from dataclasses import dataclass
>>> from typing import Any
>>> @dataclass
... class Node:
...     val: Any = None
...     left: 'Node' = None
...     right: 'Node' = None
>>> Node()
Node(val=None, left=None, right=None)

পাইথন এর আগে ৩. 3.

Node.__new__.__defaults__ডিফল্ট মানগুলিতে সেট করুন ।

>>> from collections import namedtuple
>>> Node = namedtuple('Node', 'val left right')
>>> Node.__new__.__defaults__ = (None,) * len(Node._fields)
>>> Node()
Node(val=None, left=None, right=None)

পাইথন এর আগে 2.6

Node.__new__.func_defaultsডিফল্ট মানগুলিতে সেট করুন ।

>>> from collections import namedtuple
>>> Node = namedtuple('Node', 'val left right')
>>> Node.__new__.func_defaults = (None,) * len(Node._fields)
>>> Node()
Node(val=None, left=None, right=None)

ক্রম

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

>>> Node.__new__.__defaults__ = (1,2)
>>> Node()
Traceback (most recent call last):
  ...
TypeError: __new__() missing 1 required positional argument: 'val'
>>> Node(3)
Node(val=3, left=1, right=2)

পাইথনের 2.6 থেকে 3.6 এর জন্য রেপার

আপনার জন্য এখানে একটি মোড়ক দেওয়া রয়েছে, এটি আপনাকে (বিকল্পভাবে) ব্যতীত অন্য কোনও ক্ষেত্রে ডিফল্ট মান সেট করতে দেয় None। এটি প্রয়োজনীয় যুক্তি সমর্থন করে না।

import collections
def namedtuple_with_defaults(typename, field_names, default_values=()):
    T = collections.namedtuple(typename, field_names)
    T.__new__.__defaults__ = (None,) * len(T._fields)
    if isinstance(default_values, collections.Mapping):
        prototype = T(**default_values)
    else:
        prototype = T(*default_values)
    T.__new__.__defaults__ = tuple(prototype)
    return T

উদাহরণ:

>>> Node = namedtuple_with_defaults('Node', 'val left right')
>>> Node()
Node(val=None, left=None, right=None)
>>> Node = namedtuple_with_defaults('Node', 'val left right', [1, 2, 3])
>>> Node()
Node(val=1, left=2, right=3)
>>> Node = namedtuple_with_defaults('Node', 'val left right', {'right':7})
>>> Node()
Node(val=None, left=None, right=7)
>>> Node(4)
Node(val=4, left=None, right=7)

22
আসুন দেখুন ... আপনার ওয়ান-লাইনার: ক) সবচেয়ে সংক্ষিপ্ত / সহজ উত্তর, খ) স্থান দক্ষতা সংরক্ষণ করে, গ) ভাঙবে না isinstance... সমস্ত উপকার নেই, কোন ক্ষতি নেই ... খুব খারাপ আপনি কিছুটা দেরিতে ছিলেন অনুষ্ঠান. এটি সেরা উত্তর।
জেরাত

1
মোড়কের সংস্করণে একটি সমস্যা: বিল্টিন কালেকশনস.নামটুপের মতো নয়, ডিফ () আলাদা মডিউলে অন্তর্ভুক্ত করা থাকলে এই সংস্করণটি পিকলেবল / মাল্টিপ্রসেস সিরিয়ালযোগ্য নয়।
মাইকেল স্কট কুথবার্ট

2
এটি আমার নিজের থেকে পছন্দনীয় হওয়ায় আমি এই উত্তরটিকে একটি উত্সাহ দিয়েছি। এটি অত্যন্ত দুঃখের বিষয় যে আমার নিজের উত্তরটি আপাতদৃষ্টিতে বাড়তে থাকে: |
জাস্টিন ফে

3
@ ইশাক, সমস্যাটি হ'ল (None)টিপল নয়, এটি None। আপনি যদি এর (None,)পরিবর্তে ব্যবহার করেন তবে এটি ঠিকঠাক কাজ করা উচিত।
মার্ক লোডাটো

2
অসাধারণ! আপনি Node.__new__.__defaults__= (None,) * len(Node._fields)
ডিফল্টস

142

আমি নেমটুপলটি সাবক্লাস করেছি এবং __new__পদ্ধতিটি ওভাররড করেছি :

from collections import namedtuple

class Node(namedtuple('Node', ['value', 'left', 'right'])):
    __slots__ = ()
    def __new__(cls, value, left=None, right=None):
        return super(Node, cls).__new__(cls, value, left, right)

এটি একটি স্বজ্ঞাত প্রকারের স্তরক্রম সংরক্ষণ করে, যা কোনও শ্রেণি হিসাবে ছদ্মবেশযুক্ত কোনও ফ্যাক্টরি ফাংশন তৈরি করে না।


7
নামযুক্ত টিউপলের স্থান দক্ষতা বজায় রাখার জন্য এটির জন্য স্লট এবং ক্ষেত্রের বৈশিষ্ট্যগুলির প্রয়োজন হতে পারে।
পেপিজন

কোনও কারণে, __new__কখন _replaceব্যবহৃত হবে তা বলা হচ্ছে না ।

1
দয়া করে নীচে @ মার্ক-লডাটো উত্তরটি দেখুন যা আইএমএইচও এর চেয়ে ভাল সমাধান।
জাস্টিন ফে

1
তবে @ মার্ক-লোডাটো এর উত্তর সাবক্লাসের জন্য আলাদা ডিফল্ট থাকার ক্ষমতা সরবরাহ করে না
জেসন এস

1
@ জেসনস, আমি সন্দেহ করি যে সাবক্লাসের জন্য আলাদা আলাদা ডিফল্ট থাকা এলএসপি লঙ্ঘন করতে পারে । তবে একটি সাবক্লাস খুব ভালভাবে আরও ডিফল্ট থাকতে চায় । যাই হোক না কেন, সাবক্লাসের পক্ষে জাস্টিনফয়ের পদ্ধতিটি ব্যবহার করা উচিত এবং মার্কের পদ্ধতির সাথে বেস ক্লাসটি ভাল ছিল ।
আলেক্সি

94

এটি একটি ফাংশন মোড়ানো।

NodeT = namedtuple('Node', 'val left right')

def Node(val, left=None, right=None):
  return NodeT(val, left, right)

15
এটি চালাক, এবং একটি ভাল বিকল্প হতে পারে, তবে isinstance(Node('val'), Node)এটি ভেঙে সমস্যা তৈরি করতে পারে : এটি এখন সত্য ফেরানোর পরিবর্তে একটি ব্যতিক্রম বাড়িয়ে তুলবে। কিছুটা আরও ভার্বোজ থাকাকালীন, @ জাস্টিনফয়ের উত্তর (নীচে) ধরণের শ্রেণিবিন্যাসের তথ্য সঠিকভাবে সংরক্ষণ করে, অন্যরা নোডের সাথে ইন্টারঅ্যাক্ট করতে চলেছে তবে সম্ভবত এটি আরও ভাল উপায়।
গ্যাব্রিয়েল গ্রান্ট

4
আমি এই উত্তরের ব্রুটি পছন্দ করি। সম্ভবত উপরের মন্তব্যে উদ্বেগটিকে def make_node(...):শ্রেনীর সংজ্ঞা হিসাবে ভান করার পরিবর্তে ফাংশনটির নাম দিয়ে সমাধান করা যেতে পারে । সেই পদ্ধতিতে ব্যবহারকারীরা ফাংশনটিতে টাইপ পলিমারফিজম পরীক্ষা করতে প্রলুব্ধ হন না তবে টিউপল সংজ্ঞা নিজেই ব্যবহার করেন।
ব্যবহারকারী 1556435

এর ভিন্নতার জন্য আমার উত্তর দেখুন যা লোকেদের isinstanceভুলভাবে ব্যবহার করতে বিভ্রান্ত করে না ।
ইলিয়ট ক্যামেরন

70

সঙ্গে typing.NamedTupleপাইথন মধ্যে 3.6.1+ আপনি উভয় ডিফল্ট মান এবং একটি NamedTuple মাঠে একটি টাইপ টীকা প্রদান করতে পারেন। আপনার typing.Anyযদি কেবলমাত্র পূর্বের প্রয়োজন হয় তা ব্যবহার করুন :

from typing import Any, NamedTuple


class Node(NamedTuple):
    val: Any
    left: 'Node' = None
    right: 'Node' = None

ব্যবহার:

>>> Node(1)
Node(val=1, left=None, right=None)
>>> n = Node(1)
>>> Node(2, left=n)
Node(val=2, left=Node(val=1, left=None, right=None), right=None)

এছাড়াও, আপনার যদি উভয় ডিফল্ট মান এবং mutচ্ছিক পরিবর্তনের প্রয়োজন হয়, পাইথন 3.7-তে ডেটা ক্লাস (পিইপি 557) চলছে যা কিছু (অনেক?) কেস নেমেডটপলগুলি প্রতিস্থাপন করতে পারে।


সিডিনোট: পাইথনে টীকাগুলির বর্তমান স্পেসিফিকেশনটির একগুণের ( :প্যারামিটার এবং ভেরিয়েবলগুলির জন্য এবং ->ক্রিয়াকলাপের পরে এক্সপ্রেশন ) হ'ল এগুলি সংজ্ঞা সময়ে মূল্যায়ন করা হয় * । সুতরাং, যেহেতু "ক্লাসের পুরো শরীরটি কার্যকর হয়ে যাওয়ার পরে শ্রেণীর নামগুলি সংজ্ঞায়িত হয়ে যায়", তাই 'Node'উপরের শ্রেণীর ক্ষেত্রগুলির জন্য টীকাগুলি নেমরর এড়ানোর জন্য স্ট্রিং হওয়া আবশ্যক।

এই জাতীয় ধরণের ইঙ্গিতগুলিকে "ফরোয়ার্ড রেফারেন্স" ( [1] , [2] ) বলা হয় এবং পিইপি 563 পাইথন ৩.7++ এর সাথে একটি __future__আমদানি হতে চলেছে (৪.০ এ ডিফল্টরূপে সক্ষম করা হবে) যা সামনের রেফারেন্স ব্যবহার করতে দেয় উদ্ধৃতি ছাড়াই, তাদের মূল্যায়ন স্থগিত করে।

* এএএএএফসিটি কেবলমাত্র স্থানীয় পরিবর্তনশীল টীকা রানটাইমের সময় মূল্যায়ন করা হয় না। (উত্স: পিইপি 526 )


4
এটি 3.6.1+ ব্যবহারকারীদের জন্য সবচেয়ে পরিষ্কার সমাধান বলে মনে হচ্ছে। দ্রষ্টব্য যে এই ক্ষেত্রগুলির জন্য টাইপ ইঙ্গিত হিসাবে এই উদাহরণটি (কিছুটা) বিভ্রান্তিকর leftএবং right(যেমন Node) শ্রেণীর সংজ্ঞায়িত হওয়ার মতো একই ধরণের এবং তাই স্ট্রিং হিসাবে অবশ্যই লিখতে হবে।
101

1
@ 101, আপনাকে ধন্যবাদ, আমি উত্তরে এই সম্পর্কে একটি নোট যুক্ত করেছি।
সন্ন্যাস-সময়

2
আইডিয়ামের জন্য অ্যানালগ কী my_list: List[T] = None self.my_list = my_list if my_list is not None else []? আমরা কি এই জাতীয় ডিফল্ট প্যারামিটার ব্যবহার করতে পারি না?
weberc2

@ ওয়েবারসি 2 দুর্দান্ত প্রশ্ন! আমি নিশ্চিত নই যে এই পরিবর্তনীয় ডিফের জন্য কাজ করা হবে। মান সঙ্গে সম্ভব typing.NamedTuple। তবে ডেটা ক্লাসের সাহায্যে আপনি অ্যাট্রি Fieldদিয়ে অবজেক্ট ব্যবহার করতে পারেনdefault_factory । এর জন্য, আপনার প্রতিচ্ছবিটি প্রতিস্থাপন করে my_list: List[T] = field(default_factory=list)
সন্ন্যাস-সময়

20

ডক্স থেকে সরাসরি এটি একটি উদাহরণ :

প্রোটোটাইপ উদাহরণটি কাস্টমাইজ করতে _ স্থান () ব্যবহার করে ডিফল্ট মানগুলি প্রয়োগ করা যেতে পারে:

>>> Account = namedtuple('Account', 'owner balance transaction_count')
>>> default_account = Account('<owner name>', 0.0, 0)
>>> johns_account = default_account._replace(owner='John')
>>> janes_account = default_account._replace(owner='Jane')

সুতরাং, ওপির উদাহরণটি হ'ল:

from collections import namedtuple
Node = namedtuple('Node', 'val left right')
default_node = Node(None, None, None)
example = default_node._replace(val="whut")

তবে আমি এখানে দেওয়া আরও কিছু উত্তর ভাল পছন্দ করি। আমি কেবল সম্পূর্ণতার জন্য এটি যুক্ত করতে চেয়েছিলাম।


2
+1 টি। এটা খুব আশ্চর্যের বিষয় যে তারা কোনও _পদ্ধতির সাথে যাওয়ার সিদ্ধান্ত নিয়েছে (যার মূলত একটি প্রাইভেট অর্থ) replaceযা বেশ কার্যকর মনে হয় ..
সাসুক

@ সাসুক - আমিও তা ভাবছিলাম। এটি ইতিমধ্যে কিছুটা অদ্ভুত যে আপনি পরিবর্তে একটি পৃথক স্থানের স্ট্রিং সহ উপাদানগুলি সংজ্ঞায়িত করেন *args। এটি কেবলমাত্র এমন হতে পারে যে সেগুলিকে প্রচুর পরিমাণে মানক করার আগে এটি ভাষাতে যুক্ত করা হয়েছিল।
টিম টিসডাল

12
_উপসর্গ ব্যবহারকারী সংজ্ঞায়িত tuple ক্ষেত্র নাম সঙ্গে colliding এড়াতে হবে (প্রাসঙ্গিক ডক উদ্ধৃতি: "কোন বৈধ পাইথন শনাক্তকারী একটি আন্ডারস্কোর দিয়ে শুরু নমাগুলি ছাড়া একটি FIELDNAME জন্য ব্যবহার করা যেতে পারে।")। স্থান পৃথক স্ট্রিংয়ের জন্য, আমি মনে করি এটি কেবল কয়েকটি কীস্ট্রোক সংরক্ষণ করার জন্য (এবং আপনি যদি পছন্দ করেন তবে আপনি স্ট্রিংগুলির একটি ক্রম পাশ করতে পারেন)।
সেরেন লভবর্গ 18

1
হ্যাঁ, হ্যাঁ, আপনি ভুলে গিয়েছেন নামযুক্ত টিপলের উপাদানগুলিকে অ্যাট্রিবিউট হিসাবে অ্যাক্সেস করতে, সুতরাং তখন _প্রচুর পরিমাণে বোঝা যায়।
টিম টিসডাল

2
আপনার সমাধানটি সহজ এবং সর্বোত্তম। বাকিগুলি আইএমএইচও বরং কুরুচিপূর্ণ। আমি কেবল একটি ছোট পরিবর্তন করব। ডিফল্ট_নোডের পরিবর্তে আমি নোড_ডিফল্ট পছন্দ করব কারণ এটি ইন্টেলিজেন্সের সাথে আরও ভাল অভিজ্ঞতা তৈরি করে। আপনি যদি নোড টাইপ করা শুরু করেন তবে আপনার প্রয়োজনীয় সমস্ত জিনিস পেয়েছেন :)
পাভেল হানপরি

19

আমি নিশ্চিত না যে কেবল অন্তর্নির্মিত নেমটুপল সহ কোনও সহজ উপায় আছে। রেকর্ডটাইপ নামে একটি দুর্দান্ত মডিউল রয়েছে যার এই কার্যকারিতা রয়েছে:

>>> from recordtype import recordtype
>>> Node = recordtype('Node', [('val', None), ('left', None), ('right', None)])
>>> Node(3)
Node(val=3, left=None, right=None)
>>> Node(3, 'L')
Node(val=3, left=L, right=None)

2
আহ, তৃতীয় পক্ষের প্যাকেজ ব্যবহার করা সম্ভব নয় যদিও recordtypeভবিষ্যতের কাজের জন্য অবশ্যই তা আকর্ষণীয় দেখায়। +1
সাসুক

মডিউলটি বেশ ছোট এবং কেবল একটি একক ফাইল যাতে আপনি এটি সর্বদা আপনার প্রকল্পে যুক্ত করতে পারেন।
জেটেরেস

যথেষ্ট ভাল, যদিও আমি খাঁটি নামযুক্ত টিপল সলিউশনের জন্য আরও কিছু সময়ের জন্য অপেক্ষা করব এটি গ্রহণযোগ্য হিসাবে চিহ্নিত করার আগে সেখানে একটি আছে! :)
সাসুক

খাঁটি পাইথন
অজগরটি

3
কেবল এটি লক্ষণীয় যে recordtypeপরিবর্তিত হয় যদিও namedtupleনেই। আপনি যদি বস্তুটি হ্যাশযোগ্য হতে চান (তবে এটি অনুমান করা যায় না যেহেতু এটি ক্লাস হিসাবে শুরু হয়েছিল) এটির জন্য এটি গুরুত্বপূর্ণ।
বাভাজা

14

জাস্টিনফয়ের উত্তরে অনুপ্রাণিত এখানে আরও একটি কমপ্যাক্ট সংস্করণ রয়েছে:

from collections import namedtuple
from functools import partial

Node = namedtuple('Node', ('val left right'))
Node.__new__ = partial(Node.__new__, left=None, right=None)

7
সাবধান হন যে Node(1, 2)এই রেসিপিটি দিয়ে কাজ করে না, তবে @ জাস্টিনফয়ের উত্তরে কাজ করে। অন্যথায়, এটি বেশ নিফটি (+1)।
জর্জেকা

12

পাইথন ৩..7 + তে একটি নতুন ডিফল্ট = কীওয়ার্ড যুক্তি রয়েছে।

ডিফল্টগুলিNone ডিফল্ট মানগুলির একটি পুনরাবৃত্ত হতে পারে । যেহেতু ডিফল্ট মানযুক্ত ক্ষেত্রগুলি অবশ্যই কোনও ডিফল্ট ছাড়াই যে কোনও ক্ষেত্রের পরে আসতে হবে, তাই ডিফল্টগুলি ডানদিকের পরামিতিগুলিতে প্রয়োগ করা হয়। উদাহরণস্বরূপ, যদি ক্ষেত্রের নামগুলি হয় ['x', 'y', 'z']এবং ডিফল্ট হয় (1, 2), তবে xএটি একটি প্রয়োজনীয় যুক্তি yহবে, ডিফল্ট হবে 1এবং zডিফল্ট হবে 2

ব্যবহারের উদাহরণ:

$ ./python
Python 3.7.0b1+ (heads/3.7:4d65430, Feb  1 2018, 09:28:35) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from collections import namedtuple
>>> nt = namedtuple('nt', ('a', 'b', 'c'), defaults=(1, 2))
>>> nt(0)
nt(a=0, b=1, c=2)
>>> nt(0, 3)  
nt(a=0, b=3, c=2)
>>> nt(0, c=3)
nt(a=0, b=1, c=3)

7

সংক্ষিপ্ত, সরল এবং লোকেদের isinstanceযথাযথভাবে ব্যবহার করতে নেতৃত্ব দেয় না :

class Node(namedtuple('Node', ('val', 'left', 'right'))):
    @classmethod
    def make(cls, val, left=None, right=None):
        return cls(val, left, right)

# Example
x = Node.make(3)
x._replace(right=Node.make(4))

5

এর সাথে সমস্ত নিখোঁজ যুক্তিগুলির সূচনা করার জন্য কিছুটা বর্ধিত উদাহরণ None:

from collections import namedtuple

class Node(namedtuple('Node', ['value', 'left', 'right'])):
    __slots__ = ()
    def __new__(cls, *args, **kwargs):
        # initialize missing kwargs with None
        all_kwargs = {key: kwargs.get(key) for key in cls._fields}
        return super(Node, cls).__new__(cls, *args, **all_kwargs)

5

পাইথন ৩.7: defaultsনামডটপল সংজ্ঞাতে পরমের পরিচয় ।

নথিতে প্রদর্শিত উদাহরণ:

>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
>>> Account._fields_defaults
{'balance': 0}
>>> Account('premium')
Account(type='premium', balance=0)

এখানে আরও পড়ুন ।


4

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

import inspect

def namedtuple_with_defaults(type, default_value=None, **kwargs):
    args_list = inspect.getargspec(type.__new__).args[1:]
    params = dict([(x, default_value) for x in args_list])
    params.update(kwargs)

    return type(**params)

এটি মূলত আপনাকে কোনও নামকৃত টিপলটি একটি ডিফল্ট মান দিয়ে তৈরি করার এবং আপনার প্রয়োজনীয় প্যারামিটারগুলিকে ওভাররাইড করার সম্ভাবনা দেয়, উদাহরণস্বরূপ:

import collections

Point = collections.namedtuple("Point", ["x", "y"])
namedtuple_with_defaults(Point)
>>> Point(x=None, y=None)

namedtuple_with_defaults(Point, x=1)
>>> Point(x=1, y=None)

4

@ ডেনিস এবং @ মার্কের পদ্ধতির সমন্বয়:

from collections import namedtuple
import inspect

class Node(namedtuple('Node', 'left right val')):
    __slots__ = ()
    def __new__(cls, *args, **kwargs):
        args_list = inspect.getargspec(super(Node, cls).__new__).args[len(args)+1:]
        params = {key: kwargs.get(key) for key in args_list + kwargs.keys()}
        return super(Node, cls).__new__(cls, *args, **params) 

এটি অবস্থানগত আর্গুমেন্ট এবং মিশ্র কেসগুলির সাথে টিপল তৈরি করতে সহায়তা করবে। পরীক্ষার কেস:

>>> print Node()
Node(left=None, right=None, val=None)

>>> print Node(1,2,3)
Node(left=1, right=2, val=3)

>>> print Node(1, right=2)
Node(left=1, right=2, val=None)

>>> print Node(1, right=2, val=100)
Node(left=1, right=2, val=100)

>>> print Node(left=1, right=2, val=100)
Node(left=1, right=2, val=100)

>>> print Node(left=1, right=2)
Node(left=1, right=2, val=None)

তবে টাইপ এরিরও সমর্থন করে:

>>> Node(1, left=2)
TypeError: __new__() got multiple values for keyword argument 'left'

3

আমি এই সংস্করণটি পড়তে সহজ বলে মনে করি:

from collections import namedtuple

def my_tuple(**kwargs):
    defaults = {
        'a': 2.0,
        'b': True,
        'c': "hello",
    }
    default_tuple = namedtuple('MY_TUPLE', ' '.join(defaults.keys()))(*defaults.values())
    return default_tuple._replace(**kwargs)

এটি এতটা দক্ষ নয় যেহেতু এটিতে দু'বার অবজেক্ট তৈরি করা দরকার তবে আপনি মডিউলটির অভ্যন্তরে ডিফল্ট দ্বৈতকে সংজ্ঞায়িত করে এবং কেবল ফাংশনটি প্রতিস্থাপনের লাইনের মাধ্যমে এটি পরিবর্তন করতে পারেন।


3

যেহেতু আপনি namedtupleএকটি ডেটা ক্লাস হিসাবে ব্যবহার করছেন , আপনার সচেতন হওয়া উচিত যে অজগর 3.7 খুব সহজেই @dataclassএই উদ্দেশ্যে একটি সজ্জনকারীকে পরিচয় করিয়ে দেবে - এবং অবশ্যই এটির ডিফল্ট মান রয়েছে।

দস্তাবেজের একটি উদাহরণ :

@dataclass
class C:
    a: int       # 'a' has no default value
    b: int = 0   # assign a default value for 'b'

হ্যাকিংয়ের চেয়ে অনেক বেশি ক্লিনার, পঠনযোগ্য এবং ব্যবহারযোগ্য namedtuple। এটি অনুমান করা কঠিন নয় যে namedtuple3.7 গ্রহণের সাথে এর ব্যবহার হ্রাস পাবে।


2

একটি পৃথক প্রশ্নের এই উত্তরে অনুপ্রাণিত হয়ে , এখানে একটি প্রস্তাবিত সমাধানটি একটি মেটাক্লাসের উপর ভিত্তি করে এবং ব্যবহার করে super(ভবিষ্যতে সাবক্ল্যাসিং সঠিকভাবে পরিচালনা করতে) using এটি জাস্টিনফয়ের উত্তরের সাথে বেশ মিল ।

from collections import namedtuple

NodeTuple = namedtuple("NodeTuple", ("val", "left", "right"))

class NodeMeta(type):
    def __call__(cls, val, left=None, right=None):
        return super(NodeMeta, cls).__call__(val, left, right)

class Node(NodeTuple, metaclass=NodeMeta):
    __slots__ = ()

তারপর:

>>> Node(1, Node(2, Node(4)),(Node(3, None, Node(5))))
Node(val=1, left=Node(val=2, left=Node(val=4, left=None, right=None), right=None), right=Node(val=3, left=None, right=Node(val=5, left=None, right=None)))

2

রেকর্ডটাইপ ব্যবহার করার জন্য জেটেরাসের উত্তরটি দুর্দান্ত, তবে গ্রন্থাগারের লেখক তার নাম তালিকাভুক্ত প্রকল্পটি ব্যবহার করার পরামর্শ দিয়েছেন , যা উভয় পরিবর্তনীয় ( namedlist) এবং পরিবর্তনীয় ( namedtuple) বাস্তবায়ন সরবরাহ করে।

from namedlist import namedtuple
>>> Node = namedtuple('Node', ['val', ('left', None), ('right', None)])
>>> Node(3)
Node(val=3, left=None, right=None)
>>> Node(3, 'L')
Node(val=3, left=L, right=None)

1

এখানে একটি সংক্ষিপ্ত, সাধারণ জেনেরিক উত্তরটি একটি ডিফল্ট যুক্তিযুক্ত নামযুক্ত টিপলের জন্য একটি সুন্দর সিনট্যাক্স সহ:

import collections

def dnamedtuple(typename, field_names, **defaults):
    fields = sorted(field_names.split(), key=lambda x: x in defaults)
    T = collections.namedtuple(typename, ' '.join(fields))
    T.__new__.__defaults__ = tuple(defaults[field] for field in fields[-len(defaults):])
    return T

ব্যবহার:

Test = dnamedtuple('Test', 'one two three', two=2)
Test(1, 3)  # Test(one=1, three=3, two=2)

minified:

def dnamedtuple(tp, fs, **df):
    fs = sorted(fs.split(), key=df.__contains__)
    T = collections.namedtuple(tp, ' '.join(fs))
    T.__new__.__defaults__ = tuple(df[i] for i in fs[-len(df):])
    return T

0

NamedTupleআমার Advanced Enum (aenum)গ্রন্থাগার থেকে ক্লাসটি ব্যবহার করে , এবং classবাক্য গঠনটি ব্যবহার করে , এটি বেশ সহজ:

from aenum import NamedTuple

class Node(NamedTuple):
    val = 0
    left = 1, 'previous Node', None
    right = 2, 'next Node', None

একটি সম্ভাব্য ত্রুটি হ'ল __doc__কোনও ডিফল্ট মান সহ কোনও বৈশিষ্ট্যের জন্য স্ট্রিংয়ের প্রয়োজনীয়তা (এটি সাধারণ বৈশিষ্ট্যের জন্য alচ্ছিক)। ব্যবহারে এটি দেখে মনে হচ্ছে:

>>> Node()
Traceback (most recent call last):
  ...
TypeError: values not provided for field(s): val

>>> Node(3)
Node(val=3, left=None, right=None)

এর সুবিধাগুলি শেষ হয়েছে justinfay's answer:

from collections import namedtuple

class Node(namedtuple('Node', ['value', 'left', 'right'])):
    __slots__ = ()
    def __new__(cls, value, left=None, right=None):
        return super(Node, cls).__new__(cls, value, left, right)

সরলতা, সেইসাথে হচ্ছে metaclassপরিবর্তে ভিত্তিক execভিত্তি করে।


0

আরেকটি সমাধান:

import collections


def defaultargs(func, defaults):
    def wrapper(*args, **kwargs):
        for key, value in (x for x in defaults[len(args):] if len(x) == 2):
            kwargs.setdefault(key, value)
        return func(*args, **kwargs)
    return wrapper


def namedtuple(name, fields):
    NamedTuple = collections.namedtuple(name, [x[0] for x in fields])
    NamedTuple.__new__ = defaultargs(NamedTuple.__new__, [(NamedTuple,)] + fields)
    return NamedTuple

ব্যবহার:

>>> Node = namedtuple('Node', [
...     ('val',),
...     ('left', None),
...     ('right', None),
... ])
__main__.Node

>>> Node(1)
Node(val=1, left=None, right=None)

>>> Node(1, 2, right=3)
Node(val=1, left=2, right=3)

-1

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

import collections
def namedtuple_with_defaults(typename, fields_dict):
    T = collections.namedtuple(typename, ' '.join(fields_dict.keys()))
    T.__new__.__defaults__ = tuple(fields_dict.values())
    return T

উদাহরণ:

In[1]: fields = {'val': 1, 'left': 2, 'right':3}

In[2]: Node = namedtuple_with_defaults('Node', fields)

In[3]: Node()
Out[3]: Node(val=1, left=2, right=3)

In[4]: Node(4,5,6)
Out[4]: Node(val=4, left=5, right=6)

In[5]: Node(val=10)
Out[5]: Node(val=10, left=2, right=3)

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