เริ่มต้นตัวแปรอินสแตนซ์โดยอัตโนมัติหรือไม่


90

ฉันมีคลาส python ที่มีลักษณะดังนี้:

class Process:
    def __init__(self, PID, PPID, cmd, FDs, reachable, user):

ติดตามโดย:

        self.PID=PID
        self.PPID=PPID
        self.cmd=cmd
        ...

มีวิธีใดในการเริ่มต้นตัวแปรอินสแตนซ์เหล่านี้โดยอัตโนมัติเช่นรายการเริ่มต้นของ C ++ หรือไม่ มันจะสำรองรหัสซ้ำซ้อนจำนวนมาก


1
ดูการอภิปรายเกี่ยวกับautoassignสูตรอาหารที่autoargsใช้งานอยู่และการใช้งานทางเลือกได้ที่: วิธีใดดีที่สุดในการกำหนดแอตทริบิวต์อัตโนมัติใน Python และเป็นความคิดที่ดีหรือไม่? - Stack Overflow
nealmcb

คำตอบ:


104

คุณสามารถใช้มัณฑนากร:

from functools import wraps
import inspect

def initializer(func):
    """
    Automatically assigns the parameters.

    >>> class process:
    ...     @initializer
    ...     def __init__(self, cmd, reachable=False, user='root'):
    ...         pass
    >>> p = process('halt', True)
    >>> p.cmd, p.reachable, p.user
    ('halt', True, 'root')
    """
    names, varargs, keywords, defaults = inspect.getargspec(func)

    @wraps(func)
    def wrapper(self, *args, **kargs):
        for name, arg in list(zip(names[1:], args)) + list(kargs.items()):
            setattr(self, name, arg)

        for name, default in zip(reversed(names), reversed(defaults)):
            if not hasattr(self, name):
                setattr(self, name, default)

        func(self, *args, **kargs)

    return wrapper

ใช้ตกแต่ง__init__วิธีการ:

class process:
    @initializer
    def __init__(self, PID, PPID, cmd, FDs, reachable, user):
        pass

เอาท์พุต:

>>> c = process(1, 2, 3, 4, 5, 6)
>>> c.PID
1
>>> dir(c)
['FDs', 'PID', 'PPID', '__doc__', '__init__', '__module__', 'cmd', 'reachable', 'user'

5
สิ่งนี้ได้ผลและตอบคำถามดังนั้นฉันจึงโหวต แต่ฉันยังคงตอบ Ferdidand Beyer: "Explicit is better than implicit"
Lucas Gabriel Sánchez

14
+1 สำหรับคำตอบที่ดีที่ช่วยแก้ปัญหาของฉัน แต่มันไม่ควรเป็นฟังก์ชันหลักของภาษาหรือไม่? คุณคิดว่าการเขียน PEP นั้นคุ้มค่าหรือไม่?
Adam Matan

3
นี่เป็นคำตอบที่ดีมากซึ่งตรงไปที่กล่องเครื่องมือของฉัน
Michael van der Westhuizen

3
@NadiaAlramli ฉันคิดว่ามีข้อผิดพลาดเล็ก ๆ ในโค้ด ดูที่นี่gist.github.com/pmav99/137dbf4681be9a58de74 (original.py)
pmav99

2
ตัวอย่างปัจจุบันมีข้อบกพร่องและจะไม่ทำงานหากลายเซ็นไม่มีอาร์กิวเมนต์เริ่มต้น คุณต้องรวมเช็คเพื่อให้แน่ใจว่าชื่อและค่าเริ่มต้นไม่ใช่ไม่มี เช่นถ้าชื่อและค่าเริ่มต้น:

36

หากคุณใช้ Python 2.6 หรือสูงกว่าคุณสามารถใช้collections.namedtuple :

>>> from collections import namedtuple
>>> Process = namedtuple('Process', 'PID PPID cmd')
>>> proc = Process(1, 2, 3)
>>> proc.PID
1
>>> proc.PPID
2

นี่เป็นสิ่งที่เหมาะสมโดยเฉพาะอย่างยิ่งเมื่อชั้นเรียนของคุณเป็นเพียงค่านิยมก้อนโต


2
"นี่เป็นสิ่งที่เหมาะสมโดยเฉพาะอย่างยิ่งเมื่อชั้นเรียนของคุณเป็นเพียงค่านิยมขนาดใหญ่" ในสถานการณ์เช่นนี้คุณสามารถทำได้: https://docs.python.org/3.3/tutorial/classes.html#odds-and-ends
Big Sharpie

35

สำหรับ Python 3.7+ คุณสามารถใช้Data Classซึ่งเป็นวิธีที่ไพ ธ อนิกและบำรุงรักษาได้มากในการทำสิ่งที่คุณต้องการ

ช่วยให้คุณกำหนดฟิลด์สำหรับคลาสของคุณซึ่งเป็นตัวแปรอินสแตนซ์ที่เริ่มต้นโดยอัตโนมัติ

มันจะมีลักษณะดังนี้:

@dataclass
class Process:
    PID: int
    PPID: int
    cmd: str
    ...

__init__วิธีแล้วจะอยู่ในชั้นเรียนของคุณ

โปรดทราบว่าที่นี่จำเป็นต้องใช้คำใบ้ประเภทนั่นคือเหตุผลที่ฉันใช้intและstrในตัวอย่าง หากคุณไม่ทราบชนิดของข้อมูลของคุณคุณสามารถใช้ใด ๆ จากtypingโมดูล

Data Class มีข้อดีมากมายเมื่อเทียบกับโซลูชันที่นำเสนอ:

  • เป็นเรื่องที่ชัดเจน : ทุกช่องสามารถมองเห็นได้ซึ่งเคารพ Zen of Python และทำให้สามารถอ่านและบำรุงรักษาได้ เปรียบเทียบกับการใช้**kwargs.
  • ก็สามารถมีวิธีการ เช่นเดียวกับคลาสอื่น ๆ
  • ช่วยให้คุณก้าวไปไกลกว่าอัตโนมัติโดย__init__ใช้__post_init__วิธีนี้

แก้ไข: เหตุผลที่ควรหลีกเลี่ยงการใช้ NamedTuples

บางคนแนะนำให้ใช้namedtupleสำหรับกรณีนี้ แต่ nametuples มีพฤติกรรมบางอย่างที่แตกต่างจากคลาส Python ซึ่งไม่ปรากฏชัดในตอนแรกและควรเป็นที่รู้จักกันดี:

1. NamedTuples ไม่เปลี่ยนรูป

ความไม่เปลี่ยนรูปอาจมีประโยชน์ แต่อาจไม่ใช่สิ่งที่คุณต้องการสำหรับอินสแตนซ์ของคุณ DataClasses สามารถไม่เปลี่ยนรูปได้เช่นกันหากคุณใช้อาร์กิวเมนต์frozen=Trueใน@dataclassมัณฑนากร

2. NamedTuples __eq__ทำงานเหมือน Tuple's

ใน Python SomeNamedTuple(a=1, b=2) == AnotherNamedTuple(c=1, d=2)คือTrue! __eq__การทำงานของ NamedTuple ใช้ในการเปรียบเทียบจะพิจารณาเฉพาะค่าและตำแหน่งของค่าเหล่านั้นในกรณีเทียบไม่ได้เรียนหรือชื่อสาขาของพวกเขา


ควรใช้หากจุดประสงค์ของคลาสคือการจัดเก็บข้อมูลเท่านั้น
JC Rocamonde

หรือเพื่อพัฒนาเกี่ยวกับการจัดเก็บข้อมูล
JC Rocamonde

3
คุณช่วยอธิบายได้ไหมว่าทำไมจึงควรใช้ dataclass เฉพาะกับคลาสที่เก็บข้อมูลแทนที่จะมีพฤติกรรมอื่น ๆ ด้วย ฉันอาจสร้างโพสต์ SO ใหม่สำหรับสิ่งนี้ทั้งหมดเพื่อทำความเข้าใจกรณีการใช้งานที่เหมาะสมให้ดีขึ้น ขอบคุณ.
Vahid Pazirandeh

Data Classes can be thought of as "mutable namedtuples with defaults". - PEP557
aafulei

26

อ้างเซนของงูใหญ่ ,

Explicit ดีกว่าโดยปริยาย


10
การประกาศรายการเริ่มต้นจะไม่ชัดเจนเพียงพอหรือไม่?
Adam Matan

ฉันคิดว่า. แต่ฉันไม่เห็นเหตุผลในการเพิ่มภาษาแบบนั้น ฉันชอบข้อความที่ได้รับมอบหมายหลายอย่างมากกว่าการใช้เวทมนตร์ของมัณฑนากรเบื้องหลัง
Ferdinand Beyer

30
@ เฟอร์ดินานด์ฉันยอมรับว่ามันจะโง่มากที่มีบางอย่างในภาษาที่สามารถอยู่ใน stdlib ได้อย่างสมบูรณ์แบบ แต่มันควรจะอยู่ใน stdlib เพราะ "สวยดีกว่าน่าเกลียด" มีความสำคัญมากกว่าและการมอบหมายซ้ำ ๆ หลาย ๆ อย่างก็น่าเกลียด (เช่นเดียวกับการทำซ้ำทุกรูปแบบ)
Alex Martelli

เพื่อตอบโต้: DWIM> DWIS
Terrence Brannon

ฉันยอมรับว่ามัณฑนากรสวยกว่ารายการที่ได้รับมอบหมาย แต่ PyCharm ทำให้มันน่าเกลียดโดยไม่เข้าใจมัน :-(
user110954

23

อีกอย่างที่คุณทำได้:

class X(object):
    def __init__(self, a,b,c,d):
        vars = locals() # dict of local names
        self.__dict__.update(vars) # __dict__ holds and object's attributes
        del self.__dict__["self"] # don't need `self`

แต่ทางออกเดียวที่ฉันอยากแนะนำนอกเหนือจากการสะกดคำคือ "สร้างมาโครในโปรแกรมแก้ไขของคุณ" ;-p


1
จับใจความได้ดีในการลบ 'ตัวเอง'
michael

15

คุณสามารถทำได้อย่างง่ายดายด้วยอาร์กิวเมนต์คำหลักเช่นนี้:

>>> class D:
    def __init__(self, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)

>>> D(test='d').test
'd'

การใช้งานที่คล้ายกันสำหรับอาร์กิวเมนต์ตำแหน่งจะเป็น:

>> class C:
    def __init__(self, *args):
        self.t, self.d = args


>>> C('abc', 'def').t
'abc'
>>> C('abc', 'def').d
'def'

ซึ่งสำหรับฉันดูเหมือนจะไม่สามารถแก้ปัญหาของคุณได้


3
อีกรูปแบบหนึ่งที่ชอบคือself.__dict__.update( **kwargs )
ล็อตต์

อาจใช้ local () และใส่อาร์กิวเมนต์ปกติ
mk12

7

วิธีแก้ปัญหาของ Nadia นั้นดีกว่าและมีประสิทธิภาพมากกว่า แต่ฉันคิดว่านี่ก็น่าสนใจเช่นกัน:

def constructor(*arg_names):
  def __init__(self, *args):
    for name, val in zip(arg_names, args):
      self.__setattr__(name, val)
  return __init__


class MyClass(object):
  __init__ = constructor("var1", "var2", "var3")


>>> c = MyClass("fish", "cheese", "beans")
>>> c.var2
"cheese"

5

ฉันต้องการบางอย่างเพื่อจุดประสงค์เดียวกัน แต่ไม่มีคำตอบใดที่มีอยู่ครอบคลุมทุกกรณีที่ฉันทดสอบ คำตอบของนาเดียนั้นใกล้เคียงที่สุดกับสิ่งที่ฉันกำลังมองหาดังนั้นฉันจึงเริ่มต้นด้วยรหัสของเธอเป็นฐาน

มัณฑนากรด้านล่างทำงานร่วมกับอาร์กิวเมนต์ที่ถูกต้องทั้งหมด:

Positional                                          __init__(self, a, b                )
Keyword                                             __init__(self, a=None, b=None      )
Positional + Keyword                                __init__(self, a, b, c=None, d=None)
Variable Positional                                 __init__(self, *a                  )
Variable Positional + Keyword                       __init__(self, *a, b=None          )
Variable Positional + Variable Keyword              __init__(self, *a, **kwargs        )
Positional + Variable Positional + Keyword          __init__(self, a, *b, c=None       )
Positional + Variable Positional + Variable Keyword __init__(self, a, *b, **kwargs     )
Keyword Only                                        __init__(self, *, a=None           )
Positional + Keyword Only                           __init__(self, a, *, b=None        )

นอกจากนี้ยังใช้หลักการ_-prefix มาตรฐานเพื่ออนุญาตให้__init__ตัวแปร -private ที่จะไม่ถูกกำหนดให้กับอินสแตนซ์คลาส


###  StdLib  ###
from functools import wraps
import inspect


###########################################################################################################################
#//////|   Decorator   |//////////////////////////////////////////////////////////////////////////////////////////////////#
###########################################################################################################################

def auto_assign_arguments(function):

  @wraps(function)
  def wrapped(self, *args, **kwargs):
    _assign_args(self, list(args), kwargs, function)
    function(self, *args, **kwargs)

  return wrapped


###########################################################################################################################
#//////|   Utils   |//////////////////////////////////////////////////////////////////////////////////////////////////////#
###########################################################################################################################

def _assign_args(instance, args, kwargs, function):

  def set_attribute(instance, parameter, default_arg):
    if not(parameter.startswith("_")):
      setattr(instance, parameter, default_arg)

  def assign_keyword_defaults(parameters, defaults):
    for parameter, default_arg in zip(reversed(parameters), reversed(defaults)):
      set_attribute(instance, parameter, default_arg)

  def assign_positional_args(parameters, args):
    for parameter, arg in zip(parameters, args.copy()):
      set_attribute(instance, parameter, arg)
      args.remove(arg)

  def assign_keyword_args(kwargs):
    for parameter, arg in kwargs.items():
      set_attribute(instance, parameter, arg)
  def assign_keyword_only_defaults(defaults):
    return assign_keyword_args(defaults)

  def assign_variable_args(parameter, args):
    set_attribute(instance, parameter, args)

  POSITIONAL_PARAMS, VARIABLE_PARAM, _, KEYWORD_DEFAULTS, _, KEYWORD_ONLY_DEFAULTS, _ = inspect.getfullargspec(function)
  POSITIONAL_PARAMS = POSITIONAL_PARAMS[1:] # remove 'self'

  if(KEYWORD_DEFAULTS     ): assign_keyword_defaults     (parameters=POSITIONAL_PARAMS,  defaults=KEYWORD_DEFAULTS)
  if(KEYWORD_ONLY_DEFAULTS): assign_keyword_only_defaults(defaults=KEYWORD_ONLY_DEFAULTS                          )
  if(args                 ): assign_positional_args      (parameters=POSITIONAL_PARAMS,  args=args                )
  if(kwargs               ): assign_keyword_args         (kwargs=kwargs                                           )
  if(VARIABLE_PARAM       ): assign_variable_args        (parameter=VARIABLE_PARAM,      args=args                )


###########################################################################################################################$#//////|   Tests   |//////////////////////////////////////////////////////////////////////////////////////////////////////#$###########################################################################################################################$$if __name__ == "__main__":$$#######|   Positional   |##################################################################################################$$  class T:$    @auto_assign_arguments$    def __init__(self, a, b):$      pass$$  t = T(1, 2)$  assert (t.a == 1) and (t.b == 2)$$#######|   Keyword   |#####################################################################################################$$  class T:$    @auto_assign_arguments$    def __init__(self, a="KW_DEFAULT_1", b="KW_DEFAULT_2"):$      pass$$  t = T(a="kw_arg_1", b="kw_arg_2")$  assert (t.a == "kw_arg_1") and (t.b == "kw_arg_2")$$#######|   Positional + Keyword   |########################################################################################$$  class T:$    @auto_assign_arguments$    def __init__(self, a, b, c="KW_DEFAULT_1", d="KW_DEFAULT_2"):$      pass$$  t = T(1, 2)$  assert (t.a == 1) and (t.b == 2) and (t.c == "KW_DEFAULT_1") and (t.d == "KW_DEFAULT_2")$$  t = T(1, 2, c="kw_arg_1")$  assert (t.a == 1) and (t.b == 2) and (t.c == "kw_arg_1") and (t.d == "KW_DEFAULT_2")$$  t = T(1, 2, d="kw_arg_2")$  assert (t.a == 1) and (t.b == 2) and (t.c == "KW_DEFAULT_1") and (t.d == "kw_arg_2")$$#######|   Variable Positional   |#########################################################################################$$  class T:$    @auto_assign_arguments$    def __init__(self, *a):$      pass$$  t = T(1, 2, 3)$  assert (t.a == [1, 2, 3])$$#######|   Variable Positional + Keyword   |###############################################################################$$  class T:$    @auto_assign_arguments$    def __init__(self, *a, b="KW_DEFAULT_1"):$      pass$$  t = T(1, 2, 3)$  assert (t.a == [1, 2, 3]) and (t.b == "KW_DEFAULT_1")$$  t = T(1, 2, 3, b="kw_arg_1")$  assert (t.a == [1, 2, 3]) and (t.b == "kw_arg_1")$$#######|   Variable Positional + Variable Keyword   |######################################################################$$  class T:$    @auto_assign_arguments$    def __init__(self, *a, **kwargs):$      pass$$  t = T(1, 2, 3, b="kw_arg_1", c="kw_arg_2")$  assert (t.a == [1, 2, 3]) and (t.b == "kw_arg_1") and (t.c == "kw_arg_2")$$#######|   Positional + Variable Positional + Keyword   |##################################################################$$  class T:$    @auto_assign_arguments$    def __init__(self, a, *b, c="KW_DEFAULT_1"):$      pass$$  t = T(1, 2, 3, c="kw_arg_1")$  assert (t.a == 1) and (t.b == [2, 3]) and (t.c == "kw_arg_1")$$#######|   Positional + Variable Positional + Variable Keyword   |#########################################################$$  class T:$    @auto_assign_arguments$    def __init__(self, a, *b, **kwargs):$      pass$$  t = T(1, 2, 3, c="kw_arg_1", d="kw_arg_2")$  assert (t.a == 1) and (t.b == [2, 3]) and (t.c == "kw_arg_1") and (t.d == "kw_arg_2")$$#######|   Keyword Only   |################################################################################################$$  class T:$    @auto_assign_arguments$    def __init__(self, *, a="KW_DEFAULT_1"):$      pass$$  t = T(a="kw_arg_1")$  assert (t.a == "kw_arg_1")$$#######|   Positional + Keyword Only   |###################################################################################$$  class T:$    @auto_assign_arguments$    def __init__(self, a, *, b="KW_DEFAULT_1"):$      pass$$  t = T(1)$  assert (t.a == 1) and (t.b == "KW_DEFAULT_1")$$  t = T(1, b="kw_arg_1")$  assert (t.a == 1) and (t.b == "kw_arg_1")$$#######|   Private __init__ Variables (underscored)   |####################################################################$$  class T:$    @auto_assign_arguments$    def __init__(self, a, b, _c):$      pass$$  t = T(1, 2, 3)$  assert hasattr(t, "a") and hasattr(t, "b") and not(hasattr(t, "_c"))

บันทึก:

ฉันรวมการทดสอบ แต่ยุบไว้ในบรรทัดสุดท้าย ( 58 ) เพื่อความกระชับ คุณสามารถขยายการทดสอบซึ่งให้รายละเอียดของกรณีการใช้งานที่เป็นไปได้find/replaceทั้งหมด$โดยให้อักขระทั้งหมดขึ้นบรรทัดใหม่


3

อาจไม่จำเป็นต้องเริ่มต้นตัวแปรเนื่องจาก local () มีค่าอยู่แล้ว!

คลาส Dummy (วัตถุ):

def __init__(self, a, b, default='Fred'):
    self.params = {k:v for k,v in locals().items() if k != 'self'}

d = หุ่น (2, 3)

d พารามิเตอร์

{'a': 2, 'b': 3, 'default': 'Fred'}

d.params ['b']

3

แน่นอนว่าภายในคลาสหนึ่งสามารถใช้ self.params ได้


เป็นแนวทางที่ดีและเป็นต้นฉบับ แต่d['b']เขียนด้วยภาษากลางของ Python ในขณะที่d.params['b']จะทำให้เกิดความสับสนสำหรับผู้อ่านโค้ด
Adam Matan

3

ทันทีที่getargspecเลิกใช้งานตั้งแต่ Python 3.5 นี่คือวิธีแก้ปัญหาโดยใช้inspect.signature:

from inspect import signature, Parameter
import functools


def auto_assign(func):
    # Signature:
    sig = signature(func)
    for name, param in sig.parameters.items():
        if param.kind in (Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD):
            raise RuntimeError('Unable to auto assign if *args or **kwargs in signature.')
    # Wrapper:
    @functools.wraps(func)
    def wrapper(self, *args, **kwargs):
        for i, (name, param) in enumerate(sig.parameters.items()):
            # Skip 'self' param:
            if i == 0: continue
            # Search value in args, kwargs or defaults:
            if i - 1 < len(args):
                val = args[i - 1]
            elif name in kwargs:
                val = kwargs[name]
            else:
                val = param.default
            setattr(self, name, val)
        func(self, *args, **kwargs)
    return wrapper

ตรวจสอบว่าใช้งานได้หรือไม่:

class Foo(object):
    @auto_assign
    def __init__(self, a, b, c=None, d=None, e=3):
        pass

f = Foo(1, 2, d="a")
assert f.a == 1
assert f.b == 2
assert f.c is None
assert f.d == "a"
assert f.e == 3

print("Ok")

2

สำหรับ Python 3.3+:

from functools import wraps
from inspect import Parameter, signature


def instance_variables(f):
    sig = signature(f)
    @wraps(f)
    def wrapper(self, *args, **kwargs):
        values = sig.bind(self, *args, **kwargs)
        for k, p in sig.parameters.items():
            if k != 'self':
                if k in values.arguments:
                    val = values.arguments[k]
                    if p.kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY):
                        setattr(self, k, val)
                    elif p.kind == Parameter.VAR_KEYWORD:
                        for k, v in values.arguments[k].items():
                            setattr(self, k, v) 
                else:
                    setattr(self, k, p.default) 
    return wrapper

class Point(object):
    @instance_variables 
    def __init__(self, x, y, z=1, *, m='meh', **kwargs):
        pass

การสาธิต:

>>> p = Point('foo', 'bar', r=100, u=200)
>>> p.x, p.y, p.z, p.m, p.r, p.u
('foo', 'bar', 1, 'meh', 100, 200)

แนวทางที่ไม่ใช่มัณฑนากรสำหรับทั้ง Python 2 และ 3 โดยใช้เฟรม:

import inspect


def populate_self(self):
    frame = inspect.getouterframes(inspect.currentframe())[1][0]
    for k, v in frame.f_locals.items():
        if k != 'self':
            setattr(self, k, v)


class Point(object):
    def __init__(self, x, y):
        populate_self(self)

การสาธิต:

>>> p = Point('foo', 'bar')
>>> p.x
'foo'
>>> p.y
'bar'

1

nu11ptrได้สร้างโมดูลขนาดเล็กPyInstanceVarsซึ่งรวมถึงฟังก์ชันนี้ในฐานะมัณฑนากรฟังก์ชัน ใน README ของโมดูลระบุว่าประสิทธิภาพ " [... ] ตอนนี้แย่กว่าการเริ่มต้นอย่างชัดเจนภายใต้ CPython เพียง 30-40% เท่านั้น "

ตัวอย่างการใช้งานยกมาจากเอกสารของโมดูลโดยตรง:

>>> from instancevars import *
>>> class TestMe(object):
...     @instancevars(omit=['arg2_'])
...     def __init__(self, _arg1, arg2_, arg3='test'):
...             self.arg2 = arg2_ + 1
...
>>> testme = TestMe(1, 2)
>>> testme._arg1
1
>>> testme.arg2_
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'TestMe' object has no attribute 'arg2_'
>>> testme.arg2
3
>>> testme.arg3
'test'

0

บางทีนี่อาจเป็นคำถามปิด แต่ฉันต้องการเสนอวิธีแก้ปัญหาของฉันเพื่อที่จะได้รู้ว่าคุณคิดอย่างไรกับมัน ฉันใช้ metaclass ซึ่งใช้มัณฑนากรกับวิธีการเริ่มต้น

import inspect

class AutoInit(type):
    def __new__(meta, classname, supers, classdict):
        classdict['__init__'] = wrapper(classdict['__init__'])
        return type.__new__(meta, classname, supers, classdict)

def wrapper(old_init):
    def autoinit(*args):
        formals = inspect.getfullargspec(old_init).args
        for name, value in zip(formals[1:], args[1:]):
            setattr(args[0], name, value)
    return autoinit


0

ในตอนท้ายของฟังก์ชันinit :

for var in list(locals().keys()):
    setattr(self,var,locals()[var])

สำหรับข้อมูลเพิ่มเติมsetattr()โปรดดูที่นี่


0

มีฟังก์ชั่นผู้ช่วยที่จะทำเช่นนี้ใน fastcore lib เป็นhttps://fastcore.fast.ai/utils.html#store_attr

from fastcore.utils import store_attr

class Process:
    def __init__(self, PID, PPID, cmd, FDs, reachable, user):
        store_attr() # this will do the same as self.PID = PID etc.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.