จะรับตัวแปรอินสแตนซ์ใน Python ได้อย่างไร


120

มีวิธีการในตัวใน Python เพื่อรับอาร์เรย์ของตัวแปรอินสแตนซ์คลาสทั้งหมดหรือไม่ ตัวอย่างเช่นหากฉันมีรหัสนี้:

class hi:
  def __init__(self):
    self.ii = "foo"
    self.kk = "bar"

มีวิธีให้ฉันทำไหม:

>>> mystery_method(hi)
["ii", "kk"]

แก้ไข: เดิมทีฉันขอตัวแปรคลาสผิดพลาด


ตัวอย่างของคุณแสดง "ตัวแปรอินสแตนซ์" ตัวแปรคลาสเป็นอีกสิ่งหนึ่ง
ล็อต

คำตอบ:


143

ทุกออบเจ็กต์มี__dict__ตัวแปรที่มีตัวแปรและค่าทั้งหมดอยู่ในนั้น

ลองทำตามนี้

>>> hi_obj = hi()
>>> hi_obj.__dict__.keys()

7
FWIW การตรวจสอบโมดูลจะช่วยให้คุณวิธีการที่เชื่อถือมากกว่าการพึ่งพาDictซึ่งไม่ได้มีทุกกรณี
Thomas Wouters

1
สิ่งที่ชนิดของอินสแตนซ์ไม่ได้มีDict ? ฉันไม่เคยเจอมาก่อน
Carl Meyer

3
บางประเภทในตัวเช่น int ลองพูดว่า "x = 5" แล้ว "x .__ dict__" และคุณจะได้รับ AttributeError
Eli Courtwright

6
นอกจากนี้สิ่งที่ใช้ช่อง
Thomas Wouters

2
ทำไมคุณถึงต้องการลองและรับตัวแปรอินสแตนซ์คลาสของ int? มันไม่ใช่ชั้นเรียน (แม้ว่าฉันจะคิดผิดก็ตาม)
Martin Sherburn

103

ใช้ vars ()

class Foo(object):
    def __init__(self):
        self.a = 1
        self.b = 2

vars(Foo()) #==> {'a': 1, 'b': 2}
vars(Foo()).keys() #==> ['a', 'b']

6
+1 โดยส่วนตัวแล้วฉันคิดว่าไวยากรณ์นี้สะอาดกว่าการใช้dictเนื่องจากแอตทริบิวต์ที่มีขีดล่างคู่ควรเป็น "ส่วนตัว" ในไวยากรณ์ Python
Martin W

3
@Martin: __methodเป็นวิธีการส่วนตัว__method__เป็นวิธีพิเศษไม่จำเป็นต้องเป็นส่วนตัว ฉันอยากจะบอกว่าวิธีการพิเศษกำหนดความสามารถของวัตถุมากกว่าวิธีการ
u0b34a0f6ae

2
__method__ค่อนข้างน่าเกลียดและฉันคิดว่าพวกเขาได้รับการตั้งชื่อแบบนั้นเพื่อพยายามยับยั้งไม่ให้ผู้คนใช้พวกเขาเว้นแต่จำเป็นจริงๆ ในกรณีนี้เรามีทางเลือก vars ()
Martin Sherburn

ในกรณีของฉันฉันพยายามเรียก vars (ObjName) และมันจะกลับ dict_proxy กับพจนานุกรมที่มีคีย์เป็นวิธีการที่ได้รับชั้น / วัตถุ แต่สัญญาณของการไม่มีinitองค์ประกอบ เดาว่าทำไม?
user228137

ตัวแปรคู่เน้น__str__, __method__มีการใช้ภาษาของตัวเองตามปกติ จะเกิดอะไรขึ้นเมื่อคุณstr(something)?
Zizouz212

15

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

ข้อยกเว้นคือถ้าคลาสของคุณใช้สล็อตซึ่งเป็นรายการคงที่ของแอ็ตทริบิวต์ที่คลาสอนุญาตให้มีอินสแตนซ์ มีคำอธิบายเกี่ยวกับสล็อตในhttp://www.python.org/2.2.3/descrintro.htmlแต่มีข้อผิดพลาดหลายประการเกี่ยวกับสล็อต พวกมันมีผลต่อเลย์เอาต์หน่วยความจำดังนั้นการสืบทอดหลายรายการอาจเป็นปัญหาและการสืบทอดโดยทั่วไปต้องคำนึงถึงสล็อตด้วย


การลงคะแนนเนื่องจาก "คุณไม่สามารถรับรายการแอตทริบิวต์อินสแตนซ์" นั้นผิดเพียง: ทั้ง vars () และdictให้ข้อมูลตรงกัน
Carl Meyer

2
ฉันถือว่าเขาหมายถึง "คุณไม่สามารถรับรายการแอตทริบิวต์อินสแตนซ์ที่เป็นไปได้ทั้งหมด" ตัวอย่างเช่นฉันมักใช้ lazy generation และ @property มัณฑนากรเพื่อเพิ่มตัวแปรอินสแตนซ์ในครั้งแรกที่ขอ การใช้dictจะบอกคุณเกี่ยวกับตัวแปรนี้เมื่อมีอยู่แล้ว แต่ไม่ใช่ก่อนหน้านี้
Eli Courtwright

5
ฉันไม่ได้ลงคะแนนและโปรดสังเกตสิ่งที่ฉันพูดจริง: คุณไม่สามารถรับรายการแอตทริบิวต์อินสแตนซ์ที่กำหนดให้เพียงคลาสซึ่งเป็นสิ่งที่โค้ดที่มาพร้อมกับคำถามพยายามทำ
Thomas Wouters

2
@ คาร์ล: โปรดศึกษาตัวเองก่อนที่จะเขียนความคิดเห็นที่ผิดพลาดและลงคะแนนตามการขาดความรู้ของคุณ
nikow

14

ทั้ง Vars () และวิธีการ dict จะใช้ได้กับตัวอย่างที่ OP โพสต์ แต่จะใช้ไม่ได้กับอ็อบเจ็กต์ที่กำหนดแบบ "หลวม ๆ " เช่น:

class foo:
  a = 'foo'
  b = 'bar'

ในการพิมพ์แอตทริบิวต์ที่เรียกไม่ได้ทั้งหมดคุณสามารถใช้ฟังก์ชันต่อไปนี้:

def printVars(object):
    for i in [v for v in dir(object) if not callable(getattr(object,v))]:
        print '\n%s:' % i
        exec('print object.%s\n\n') % i

5
exec('print object.%s\n\n') % iควรเขียนเป็นprint getattr(object, i)
user102008

11

คุณยังสามารถทดสอบว่าวัตถุมีตัวแปรเฉพาะหรือไม่โดยใช้:

>>> hi_obj = hi()
>>> hasattr(hi_obj, "some attribute")

6

ตัวอย่างของคุณแสดง "ตัวแปรอินสแตนซ์" ไม่ใช่ตัวแปรคลาสจริงๆ

มองหาhi_obj.__class__.__dict__.items()ตัวแปรคลาสพร้อมกับสมาชิกคลาสอื่น ๆ เช่นฟังก์ชันสมาชิกและโมดูลที่มี

class Hi( object ):
    class_var = ( 23, 'skidoo' ) # class variable
    def __init__( self ):
        self.ii = "foo" # instance variable
        self.jj = "bar"

ตัวแปรคลาสจะแชร์โดยอินสแตนซ์ทั้งหมดของคลาส


6

แนะนำ

>>> print vars.__doc__
vars([object]) -> dictionary

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.

ในคำอื่น ๆ มันเป็นหลักเพียงแค่ตัด __dict__


5

แม้ว่าจะไม่ใช่คำตอบสำหรับคำถาม OP โดยตรง แต่ก็มีวิธีที่ดีในการค้นหาว่าตัวแปรใดอยู่ในขอบเขตของฟังก์ชัน ดูรหัสนี้:

>>> def f(x, y):
    z = x**2 + y**2
    sqrt_z = z**.5
    return sqrt_z

>>> f.func_code.co_varnames
('x', 'y', 'z', 'sqrt_z')
>>> 

แอตทริบิวต์ func_code มีสิ่งที่น่าสนใจทุกประเภทอยู่ในนั้น ช่วยให้คุณทำสิ่งดีๆได้ นี่คือตัวอย่างของวิธีที่ฉันใช้สิ่งนี้:

def exec_command(self, cmd, msg, sig):

    def message(msg):
        a = self.link.process(self.link.recieved_message(msg))
        self.exec_command(*a)

    def error(msg):
        self.printer.printInfo(msg)

    def set_usrlist(msg):
        self.client.connected_users = msg

    def chatmessage(msg):
        self.printer.printInfo(msg)

    if not locals().has_key(cmd): return
    cmd = locals()[cmd]

    try:
        if 'sig' in cmd.func_code.co_varnames and \
                       'msg' in cmd.func_code.co_varnames: 
            cmd(msg, sig)
        elif 'msg' in cmd.func_code.co_varnames: 
            cmd(msg)
        else:
            cmd()
    except Exception, e:
        print '\n-----------ERROR-----------'
        print 'error: ', e
        print 'Error proccessing: ', cmd.__name__
        print 'Message: ', msg
        print 'Sig: ', sig
        print '-----------ERROR-----------\n'

2

สร้างขึ้นจากคำตอบของ dmark เพื่อรับสิ่งต่อไปนี้ซึ่งมีประโยชน์หากคุณต้องการความเท่าเทียมกันของ sprintf และหวังว่าจะช่วยใครสักคน ...

def sprint(object):
    result = ''
    for i in [v for v in dir(object) if not callable(getattr(object, v)) and v[0] != '_']:
        result += '\n%s:' % i + str(getattr(object, i, ''))
    return result

0

บางครั้งคุณต้องการกรองรายการตามตัวแทนสาธารณะ / ส่วนตัว เช่น

def pub_vars(self):
    """Gives the variable names of our instance we want to expose
    """
    return [k for k in vars(self) if not k.startswith('_')]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.