isteğe bağlı anahtar kelime bağımsız değişkenleri için adlandırılmış çift ve varsayılan değerler


300

Uzun bir içi boş "veri" sınıfı adlı bir tuple dönüştürmek çalışıyorum. Sınıfım şu anda şöyle görünüyor:

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

Dönüşümden sonra namedtupleşöyle görünür:

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

Ama burada bir sorun var. Orijinal sınıfım yalnızca bir değer iletmeme izin verdi ve adlandırılmış / anahtar kelime bağımsız değişkenleri için varsayılan değerleri kullanarak varsayılan değerle ilgileniyordu. Gibi bir şey:

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

Ancak bu, benim tüm alanları geçmemi beklediğinden, yeniden adlandırılmış tuple'ım durumunda işe yaramıyor. Ben tabii tekrarlarını yerini alabilecek Node(val)kadar Node(val, None, None)ama benim zevk için değil.

Peki, çok fazla kod karmaşıklığı (metaprogramlama) eklemeden yeniden yazmamı başarılı kılabilecek iyi bir hile var mı, yoksa sadece hapı yutmalı ve "ara ve değiştir" ile devam etmeli miyim? :)


2
Bu dönüşümü neden yapmak istiyorsunuz? Orijinal Nodesınıfınızı olduğu gibi seviyorum . Neden adlandırılmış tuple dönüştürülmeli?
steveha

34
Bu dönüşüm yapmak istedim çünkü mevcut Nodeve diğer sınıflar bir grup farklı alanlarla basit veri tutucu değer nesneleri Node(bunlardan sadece biri). Bu sınıf bildirimleri IMHO'nun hat gürültüsünden başka bir şey değildir. Neden gerekli olmayan bir şeyi sürdürmelisiniz? :)
sasuke

Sınıflarınızda hiç yöntem işleviniz yok mu? Örneğin, .debug_print()ağacı yürüyen ve basan bir yönteminiz yok mu?
steveha

2
Tabii ki yapıyorum, ama bu BinaryTreesınıf için. Nodeve diğer veri sahipleri, adlandırılmış tuples'lerin iyi __str__ve __repr__temsili olduğu göz önüne alındığında, bu tür özel yöntemler gerektirmez . :)
sasuke

Tamam, makul görünüyor. Ve sanırım Ignacio Vazquez-Abrams size cevabı verdi: düğümünüz için varsayılan değerleri yapan bir işlev kullanın.
steveha

Yanıtlar:


532

Python 3.7

Defaults parametresini kullanın .

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

Ya da daha iyisi, adlandırılmış gruptan çok daha güzel olan yeni dataclasses kütüphanesini kullanın.

>>> 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)

Python 3.7'den önce

Node.__new__.__defaults__Varsayılan değerlere ayarlayın .

>>> 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)

Python 2.6 öncesi

Node.__new__.func_defaultsVarsayılan değerlere ayarlayın .

>>> 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)

Sipariş

Python'un tüm sürümlerinde, adlandırılmış grupta bulunandan daha az varsayılan değer ayarlarsanız, varsayılanlar en sağdaki parametrelere uygulanır. Bu, bazı bağımsız değişkenleri gereken bağımsız değişkenler olarak saklamanızı sağlar.

>>> 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)

Python 2.6 - 3.6 için sarıcı

İşte sizin için bir sarmalayıcı (varsayılan olarak) varsayılan değerleri başka bir şeye ayarlamanıza bile izin verir None. Bu gerekli bağımsız değişkenleri desteklemez.

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

Misal:

>>> 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
Bakalım ... tek astarınız: a) en kısa / en basit cevaptır, b) alan verimliliğini korur, c) kırılmaz isinstance... tüm profesyoneller, eksileri yok ... çok kötü, biraz geç kaldın Parti. Bu en iyi cevap.
Gerrat

1
Sarıcı sürümü ile ilgili bir sorun: yerleşik collections.namedtuple'ın aksine, def () farklı bir modüle dahil edilmişse bu sürüm seçilebilir / çoklu işlemle serileştirilemez.
Michael Scott Cuthbert

2
Bu cevaba kendim için tercih edildiği için bir oylama verdim. Ne yazık ki benim kendi cevap devam upvoted: |
Justin Fay

3
@ishaaq, sorun şu ki (None)bir demet değil, öyle None. Eğer kullanırsanız (None,)bunun yerine, para cezası çalışmalıdır.
Mark Lodato

2
Mükemmel! Varsayılanların ayarını şu yöntemlerle genelleştirebilirsiniz:Node.__new__.__defaults__= (None,) * len(Node._fields)
ankostis

142

Namedtuple alt sınıf ve __new__yöntem overrode :

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)

Bu, sınıf olarak gizlenmiş bir fabrika işlevinin yaratılmadığı sezgisel bir tür hiyerarşisini korur.


7
Bu, adlandırılmış bir grubun alan verimliliğini korumak için yuva ve alan özelliklerine ihtiyaç duyabilir.
Pepijn

Bazı nedenlerden dolayı kullanıldığında __new__çağrılmaz _replace.

1
Lütfen aşağıdaki IMHO'nun bundan daha iyi bir çözüm olduğu @ marc-lodato yanıtına bir göz atın.
Justin Fay

1
ancak @ marc-lodato'nun yanıtı, bir alt sınıfın farklı varsayılanlara sahip olma yeteneğini sağlamaz
Jason S

1
@JasonS i ihlal etmesi farklı varsayılan için bir alt sınıf için şüpheleniyoruz LSP'yi . Ancak, bir alt sınıf çok daha fazla varsayılana sahip olmak isteyebilir . Her durumda, alt sınıfın justinfay yöntemini kullanması ve temel sınıf Marc'ın yöntemiyle iyi olurdu .
Alexey

94

Bir işleve sarın.

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

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

15
Bu zekidir ve iyi bir seçenek olabilir, ancak kırılarak da sorunlara neden olabilir isinstance(Node('val'), Node): Şimdi True döndürmek yerine bir istisna oluşturacaktır. Biraz daha ayrıntılı olsa da, @ justinfay'in cevabı (aşağıda) tür hiyerarşi bilgilerini düzgün bir şekilde korur, bu nedenle başkaları Düğüm örnekleri ile etkileşime girecekse muhtemelen daha iyi bir yaklaşımdır.
Gabriel Grant

4
Bu cevabın kısalığını seviyorum. Belki de yukarıdaki yorumdaki endişe def make_node(...):, bir sınıf tanımı gibi davranmak yerine fonksiyonun adlandırılmasıyla giderilebilir . Bu şekilde kullanıcılar işlev üzerinde tip polimorfizmini kontrol etmeye cazip gelmez, ancak tuple tanımını kullanır.
user1556435

Yanıltıcı insanları isinstanceyanlış kullanmaktan muzdarip olmayan bir varyasyon için cevabımı görün .
Elliot Cameron

70

İle typing.NamedTuplePython 3.6.1+ Eğer varsayılan bir değer ve bir NamedTuple alanına tür ek açıklaması hem sağlayabilir. typing.AnyYalnızca öncekine ihtiyacınız varsa kullanın :

from typing import Any, NamedTuple


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

Kullanımı:

>>> 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)

Ayrıca, hem varsayılan değerlere hem de isteğe bağlı değiştirilebilirliğe ihtiyacınız varsa, Python 3.7, bazı (birçok?) Durumda adlandırılmış grupların yerini alabilecek veri sınıflarına (PEP 557) sahip olacaktır.


Sidenote: mevcut şartnamenin bir cilvesi ek açıklamalar (sonra ifadeleri :parametreler ve değişkenler için ve sonra ->Python fonksiyonları için) onlar tanımı anda değerlendirilir olmasıdır * . Bu nedenle, "sınıf adları tüm sınıf yürütüldüğünde tanımlandığından", 'Node'yukarıdaki sınıf alanlarına yönelik ek açıklamaların NameError'dan kaçınmak için dizeler olması gerekir.

Bu tür ipuçlarına "ileri başvuru" ( [1] , [2] ) denir ve PEP 563 Python 3.7+ ile __future__ileri referansların kullanılmasına izin veren bir içe aktarma (4.0'da varsayılan olarak etkinleştirilecek) olacaktır tırnak işaretleri olmadan, değerlendirmelerini ertelemek.

* AFAICT yalnızca yerel değişken ek açıklamaları çalışma zamanında değerlendirilmez. (kaynak: PEP 526 )


4
Bu, 3.6.1+ kullanıcılar için en temiz çözüm gibi görünüyor. Bu örneğin, alanlar için tür ipucu olarak (biraz) kafa karıştırıcı olduğunu leftve right(yani Node) tanımlanan sınıfla aynı tür olduğunu ve bu nedenle dize olarak yazılması gerektiğini unutmayın.
101

1
@ 101, teşekkür ederim, cevaba bununla ilgili bir not ekledim.
keşiş zamanı

2
Deyimin analogu nedir my_list: List[T] = None self.my_list = my_list if my_list is not None else []? Bunun gibi varsayılan parametreleri kullanamaz mıyız?
weberc2

@ weberc2 Harika bir soru! Değişken def için bu geçici çözüm olup olmadığından emin değilim. değerleri ile mümkündür typing.NamedTuple. Ancak veri sınıfları ile attr olan nesneleri kullanabilirsiniz . bunun için deyiminizi değiştirmek . Fielddefault_factorymy_list: List[T] = field(default_factory=list)
keşiş zamanı

20

Bu doğrudan dokümanlardan bir örnek :

Varsayılan değerler, bir prototip örneğini özelleştirmek için _replace () kullanılarak uygulanabilir:

>>> 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')

OP'nin örneği şöyle olur:

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

Ancak, burada verilen diğer cevapların bazılarını daha çok seviyorum. Bunu tamlık olarak eklemek istedim.


2
+1. Oldukça kullanışlı görünen bir _şey için (temel olarak özel bir yöntem anlamına gelir) bir yöntemle gitmeye karar vermeleri çok garip replace..
sasuke

@sasuke - Bunu da merak ediyordum. Öğeleri boşluk yerine ayrılmış bir dize ile tanımlamanız zaten biraz garip *args. Bu şeylerin çoğu standartlaştırılmadan önce dile eklenmiş olabilir.
Tim Tisdall

12
Ön _ek, kullanıcı tanımlı grup alanlarının adlarıyla çarpışmaktan kaçınmaktır (ilgili belge alıntısı: "Alt çizgi ile başlayan adlar dışında bir alan adı için geçerli herhangi bir Python tanımlayıcısı kullanılabilir."). Uzay ayrılmış dize gelince, bu sadece birkaç tuş vuruşlarını kaydetmek için düşünüyorum (ve isterseniz dizeleri bir dizi geçirebilirsiniz).
Søren Løvborg

1
Ah, evet, adlandırılmış grubun öğelerine nitelik olarak erişmeni unuttum, bu yüzden _o zaman çok mantıklı geliyor.
Tim Tisdall

2
Çözümünüz basit ve en iyisidir. Gerisi IMHO'yu oldukça çirkin. Sadece küçük bir değişiklik yapardım. IntelliSense ile daha iyi bir deneyim sağladığı için default_node yerine node_default'u tercih ederim. Düğüm yazmaya başlamanız durumunda ihtiyacınız olan her şeyi aldınız :)
Pavel Hanpari

19

Sadece dahili adlandırılmış grupla kolay bir yol olup olmadığından emin değilim. Adlı güzel modülü var RecordType bu işlevselliği vardır:

>>> 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
Ah, üçüncü parti bir paket kullanmak mümkün değil, ancak recordtypegelecekteki çalışmalar için kesinlikle ilginç görünüyor. +1
sasuke

Modül oldukça küçük ve sadece tek bir dosya olduğundan projenize her zaman ekleyebilirsiniz.
jterrace

Oldukça adil, saf bir tuple çözümü için biraz daha bekleyeceğim, ancak bu kabul edilmeden önce orada bir tane var! :)
sasuke

Kabul edilen saf python iyi olurdu, ama bir tane olduğunu sanmıyorum :(
jterrace

3
Sadece recordtypedeğişebilir olmasına namedtuplerağmen değil. Bu, nesnenin yıkanabilir olmasını istiyorsanız (bir sınıf olarak başladığından beri sanmıyorsunuz) önemli olabilir.
bavaza

14

İşte justinfay'ın cevabından ilham alan daha kompakt bir versiyon:

from collections import namedtuple
from functools import partial

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

7
Dikkat edin Node(1, 2)bu tarifi ile işi değil, ama @ justinfay yanıtında çalışır. Aksi takdirde, oldukça şık (+1).
jorgeca

12

Python3.7 + 'da yepyeni bir defaultults = anahtar kelime argümanı vardır.

varsayılan değerler olabilir Noneveya varsayılan değerlerin yinelenebilir değeri olabilir. Varsayılan değeri olan alanların, varsayılanı olmayan alanlardan sonra gelmesi gerektiğinden, varsayılanlar en sağdaki parametrelere uygulanır. Örneğin, alan adları ['x', 'y', 'z']ve varsayılanlar ise (1, 2), xgerekli bir bağımsız değişken olur, yvarsayılan olarak varsayılan olur 1ve zvarsayılan olarak ayarlanır 2.

Örnek kullanım:

$ ./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

Kısa, basit ve insanları isinstanceyanlış kullanmaya yönlendirmiyor :

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

Tüm eksik argümanları şununla başlatmak için biraz genişletilmiş bir örnek 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

Python 3.7: defaultsadlandırılmış üçlü tanımda param tanıtımı .

Belgelerde gösterildiği gibi örnek:

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

Daha fazlasını buradan okuyun .


4

Bunu da kullanabilirsiniz:

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)

Bu temel olarak, varsayılan bir değere sahip herhangi bir adlandırılmış grup oluşturma ve yalnızca ihtiyacınız olan parametreleri geçersiz kılma olanağı sunar, örneğin:

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

@Denis ve @Mark yaklaşımlarının birleştirilmesi:

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) 

Bu, konumsal argümanlarla ve ayrıca karışık vakalarla demet oluşturmayı desteklemelidir. Test senaryoları:

>>> 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)

aynı zamanda TypeError'ı da destekler:

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

3

Bu sürümü okumayı daha kolay buluyorum:

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)

Bu, nesnenin iki kez oluşturulmasını gerektirdiği kadar verimli değildir, ancak modül içindeki varsayılan çiftliği tanımlayarak ve sadece fonksiyonun değiştirme satırını yapmasını sağlayabilirsiniz.


3

namedtupleBir veri sınıfı olarak kullandığınızdan , python @dataclass3.7'nin bu amaç için bir dekoratör sunacağını ve elbette varsayılan değerlere sahip olduğunu bilmelisiniz .

Dokümanlardan bir örnek :

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

Korsandan çok daha temiz, okunabilir ve kullanılabilir namedtuple. namedtuple3.7 kullanımıyla s kullanımının düşeceğini tahmin etmek zor değildir .


2

Esinlenen bu cevabın farklı bir soruya, burada dayanarak benim önerilen çözüm metaclass ve kullanma super(doğru subcalssing sap geleceğe). Justinfay'ın cevabına oldukça benziyor .

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__ = ()

Sonra:

>>> 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

Jterrace'in kayıt tipini kullanmasının cevabı harika, ancak kütüphanenin yazarı , hem mutable ( ) hem de immutable ( ) uygulamalar sağlayan adlandırılmış liste projesini kullanmanızı tavsiye ediyor .namedlistnamedtuple

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

Aşağıda, varsayılan bağımsız değişkenlere sahip adlandırılmış bir grup için güzel bir sözdizimine sahip kısa, basit bir genel yanıt verilmiştir:

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

Kullanımı:

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

Kullanılması NamedTuplebenim dan sınıf Advanced Enum (aenum)kütüphanesi yanı sıra kullanarak classsözdizimi, bu oldukça basittir:

from aenum import NamedTuple

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

Potansiyel bir dezavantaj, __doc__varsayılan değeri olan herhangi bir özellik için bir dize gereksinimidir (basit özellikler için isteğe bağlıdır). Kullanımda şöyle görünür:

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

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

Bunun avantajları 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)

basitlik ve metaclassbunun yerine exectemelli olmaktır .


0

Başka bir çözüm:

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

Kullanımı:

>>> 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

İşte Mark Lodato'nun paketleyicisinin daha az esnek ama daha özlü bir versiyonu: Alanları ve varsayılanları sözlük olarak alıyor.

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

Misal:

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
dictsipariş garantisi yoktur.
Ethan Furman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.