วิธีที่ง่ายกว่าในการสร้างพจนานุกรมของตัวแปรที่แยกกัน?


220

ฉันต้องการรับชื่อตัวแปรเป็นสตริง แต่ฉันไม่รู้ว่า Python มีความสามารถในการวิปัสสนามากขนาดนั้นหรือไม่ สิ่งที่ต้องการ:

>>> print(my_var.__name__)
'my_var'

ฉันต้องการทำเช่นนั้นเพราะฉันมีตัวแปรมากมายที่ฉันต้องการเปลี่ยนเป็นพจนานุกรมเช่น:

bar = True
foo = False
>>> my_dict = dict(bar=bar, foo=foo)
>>> print my_dict 
{'foo': False, 'bar': True}

แต่ฉันต้องการบางสิ่งที่เป็นอัตโนมัติมากกว่านั้น

Python มีlocals()และvars()ดังนั้นฉันเดาว่ามีวิธี


31
เนื่องจากผู้คนดูเหมือนจะสับสนเกี่ยวกับสิ่งที่ขอฉันจะพูดซ้ำที่นี่เพราะมันเป็นคำถามที่น่าสนใจ ให้อาร์เรย์ [foo, bar, baz] คุณต้องการพจนานุกรมเช่น {'foo': foo, 'bar': bar, 'baz': baz} และคุณไม่ทราบว่าตัวแปรใดที่อยู่ในอาร์เรย์ ดังนั้นผู้ถามจึงถามว่าคุณรับชื่อตัวแปรเป็นสตริงในไพ ธ อนได้อย่างไร ตอนนี้หวังว่าผู้คนสามารถสำรวจคำตอบที่น่ากลัวเพื่อค้นหาสถานที่ไม่กี่แห่งที่คุณเรียนรู้ว่าทำไมนี่จึงไม่ใช่ความคิดที่ดีในงูหลาม
Jesse Sherlock

3
ซ้ำซ้อนที่เป็นไปได้: stackoverflow.com/questions/544919/…
Anderson Green

2
วิธีหนึ่งที่ใช้สำหรับเทคนิคคือการทำให้การจัดรูปแบบสตริงเป็นไปอย่างราบรื่น: '{var} {foo} {bar}' รูปแบบ (** ชื่อ (var, foo, bar)) โดยที่ "named" เป็นฟังก์ชันที่ส่งกลับค่า dict ( 'var': var) ตามที่อธิบายไว้
Gordon Bean

4
ฉันคิดว่านี่เป็นคำถามที่ไม่ดีเพราะชื่อถูกแมปกับวัตถุคุณสามารถมีชื่อหลายชื่อที่ชี้ไปที่วัตถุเดียวกันและฉันไม่เคยเห็นความต้องการใด ๆ ที่จะบรรลุเป้าหมายในการแปลงการแมปนั้น ดังนั้นความจริงที่ว่าคำตอบที่ผิดนั้นได้รับการยอมรับที่นี่จึงไม่มีความหมาย - ถ้ามีการค้นหาด้วยกูเกิ้ลนำคุณมาที่นี่คุณกำลังถามคำถามผิด ๆ อย่างชัดเจน
Aaron Hall

1
นี่เป็นแนวคิดที่ยอดเยี่ยมสำหรับการแก้ไขข้อบกพร่อง!
john ktejik

คำตอบ:


48

คุณกำลังพยายามทำสิ่งนี้อยู่หรือไม่?

dict( (name,eval(name)) for name in ['some','list','of','vars'] )

ตัวอย่าง

>>> some= 1
>>> list= 2
>>> of= 3
>>> vars= 4
>>> dict( (name,eval(name)) for name in ['some','list','of','vars'] )
{'list': 2, 'some': 1, 'vars': 4, 'of': 3}

1
rlotun นั้นอยู่ใกล้กับ "วิญญาณ" เริ่มต้นของมันเพราะมันช่วยให้ค้นพบชื่อ ฉันจะใช้ทั้งผู้ประกาศข่าวของคุณ หรืออาจแค่ใช้มือด่าของฉันเพื่อพิมพ์ บางสิ่งบางอย่างเป็นเพียงการไม่ได้ทำเพื่อจะว่า automatized ...
E-satis

7
@ e-Satis: เพื่อให้ @ rlotun ทำงานได้คุณต้องให้รายการตัวแปร หากคุณมีรายการตัวแปรอะไรคือจุดที่ "ค้นพบ" ชื่อของพวกเขา
S.Lott

4
เหตุใดจึงต้อง eval แทนที่จะใช้คนในท้องถิ่นและกลมกลืนกัน?

1
@Roger Pate: เพราะฉันไม่สามารถเข้าใจได้ว่าจุดประสงค์ของการออกกำลังกายทั้งหมดคืออะไร
S.Lott

242
คำตอบนี้ไม่ตอบคำถามที่ถาม หากคุณมีรายการตัวแปรอะไรคือจุดที่ "ค้นพบ" ชื่อของพวกเขา เพื่อหลีกเลี่ยงการทำซ้ำดังนั้นแทนที่จะprint('x: ' + x)เป็นหนึ่งสามารถเขียนmagic_print(x)และมีผลลัพธ์เดียวกันโดยไม่ต้องเขียนชื่อของตัวแปรสองครั้ง
Piotr Dobrogost

130

อย่างที่บอกไปแล้วนี่ไม่ใช่สิ่งที่คุณทำใน Python จริง ๆ แล้ว - ตัวแปรคือชื่อการแมปกับวัตถุ

อย่างไรก็ตามนี่เป็นวิธีหนึ่งในการลองทำ:

 >>> a = 1
 >>> for k, v in list(locals().iteritems()):
         if v is a:
             a_as_str = k
 >>> a_as_str
 a
 >>> type(a_as_str)
 'str'

14
แนวคิดนี้มีข้อดี แต่โปรดทราบว่าหากชื่อตัวแปรสองชื่ออ้างอิงค่าเดียวกัน (เช่นTrue) ชื่อตัวแปรอาจไม่ได้รับการส่งคืน
unutbu

14
ทำไมid(v) == id(a)แทนv is a? สิ่งนี้จะล้มเหลวสำหรับวัตถุที่ถูกผูกไว้กับตัวแปรหลายตัวเช่น ints, สายอักขระและชนิดที่ผู้ใช้กำหนดเช่นเดียวกัน

ใช่v is aจะเป็นทางเลือกที่ดีกว่า และใช่แน่นอนอันตรายเนื่องจากข้อผิดพลาดที่อาจเกิดขึ้น! ;-)
rlotun

16
@ e-Satisfaction ฉันประหลาดใจที่คุณไม่ได้ทำเครื่องหมายคำตอบนี้เป็นคำตอบที่ฉันเห็นด้วยกับความคิดเห็นของคุณที่พูด rlotun อยู่ใกล้กับเริ่มต้น "จิตวิญญาณ" ของมันเพราะมันจะช่วยให้การค้นพบชื่อ นอกจากนี้คำตอบของ S.Lott ไม่ได้รบกวนคำถามของคุณเลย ...
Piotr Dobrogost

2
"overkill และอันตราย" ... และการใช้ eval ไม่ใช่เหรอ
ข้อผิดพลาด

63

ฉันต้องการทำสิ่งนี้ค่อนข้างมาก แฮ็คนี้คล้ายกับข้อเสนอแนะของ rlotun มาก แต่มันเป็นแบบหนึ่งบรรทัดซึ่งสำคัญสำหรับฉัน:

blah = 1
blah_name = [ k for k,v in locals().iteritems() if v is blah][0]

Python 3+

blah = 1
blah_name = [ k for k,v in locals().items() if v is blah][0]

3
@ keflavich ฉันชอบวิธีนี้เป็นอย่างมากและได้ใช้มันเป็นครั้งคราวในขณะนี้ อย่างไรก็ตามฉันไม่สามารถใช้มันเพื่อทำงานภายในฟังก์ชั่น ฉันเดาว่ามีวิธีที่ "ดีกว่า" ที่จะทำ แต่ไม่มีใครดีเท่าที่ nbubis วางไว้ คุณสามารถใช้มันในฟังก์ชั่น keflavich ได้หรือไม่? นี่คือที่ฉันถามคำถามเกี่ยวกับเรื่องนี้
Leo

10
โปรดทราบว่าใน Python 3 iteritems()ถูกแทนที่ด้วยitems()
Jonathan Wheeler

สิ่งนี้ไม่น่าเชื่อถือ: spam = 1; blah = 1; blah_name = [ k for k,v in locals().items() if v is blah][0]; print(blah_name)เอาต์พุตspam
andreasdr

1
@andreasdr spam = 1, blah = 1; assert spam is blahว่าเป็นเพราะ วิธีการแก้ปัญหาแบ่งเมื่อเปรียบเทียบประเภทข้อมูลดั้งเดิม
JYun

17

นี่คือแฮ็ค มันจะไม่ทำงานกับการแจกแจงการใช้งาน Python ทั้งหมด (โดยเฉพาะอย่างยิ่งที่ไม่มีtraceback.extract_stack)

import traceback

def make_dict(*expr):
    (filename,line_number,function_name,text)=traceback.extract_stack()[-2]
    begin=text.find('make_dict(')+len('make_dict(')
    end=text.find(')',begin)
    text=[name.strip() for name in text[begin:end].split(',')]
    return dict(zip(text,expr))

bar=True
foo=False
print(make_dict(bar,foo))
# {'foo': False, 'bar': True}

โปรดทราบว่าแฮ็คนี้บอบบาง:

make_dict(bar,
          foo)

(การเรียก make_dict ที่ 2 บรรทัด) จะไม่ทำงาน

แทนที่จะพยายามสร้าง dict จากค่า fooและbarมันจะเป็น Pythonic มากกว่านี้ในการสร้าง dict จากชื่อตัวแปร สตริง'foo'และ'bar':

dict([(name,locals()[name]) for name in ('foo','bar')])

1
+1 สำหรับแฮ็คสมาร์ท แน่นอนว่าการติดตามกลับช้ามากดังนั้นจึงอาจใช้งานได้ช้า
E-satis

1
+1111111 !!!! ใช่มันช้า แต่เมื่อใช้เพื่อแทนที่print("a_very_long_name: {}'.format(a_very_long_name))ผู้ที่ใส่ใจ!
frnhr

14

สิ่งนี้ไม่สามารถทำได้ใน Python ซึ่งไม่มี "ตัวแปร" Python มีชื่อและสามารถมีได้มากกว่าหนึ่งชื่อสำหรับวัตถุเดียวกัน


ใช่ฉันรู้ฉันตั้งคำถามง่าย ๆ แต่ฉันคาดหวังอะไรมากกว่านี้เช่น "get_var_tags (var) [0]"
E-satis

10

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

def details(val):
  vn = val.__name__                 #  If such a thing existed
  vs = str(val)
  print("The Value of "+ str(vn) + " is " + vs)
  print("The data type of " + vn + " is " + str(type(val)))

ดังนั้นหากคุณมีสถานการณ์พจนานุกรม / list / tuple ที่ซับซ้อนบางอย่างมันจะมีประโยชน์มากหากล่ามส่งคืนชื่อตัวแปรที่คุณกำหนด ตัวอย่างเช่นนี่คือพจนานุกรมแปลก ๆ :

m = 'abracadabra'
mm=[]    
for n in m:
  mm.append(n)
mydic = {'first':(0,1,2,3,4,5,6),'second':mm,'third':np.arange(0.,10)}



details(mydic)

The Value of mydic is {'second': ['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a'], 'third': array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.]), 'first': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
The data type of mydic is <type 'dict'>

details(mydic['first'])
The Value of mydic['first'] is (0, 1, 2, 3, 4, 5, 6)]
The data type of mydic['first'] is <type 'list'>

details(mydic.keys())
The Value of mydic.keys() is ['second', 'third', 'first']
The data type of mydic.keys() is <type 'tuple'>

details(mydic['second'][0])
The Value of mydic['second'][0] is a
The data type of mydic['second'][0] is <type 'str'>

ฉันไม่แน่ใจว่าฉันใส่สิ่งนี้ไว้ในที่ที่ถูกต้องหรือไม่ แต่ฉันคิดว่ามันอาจช่วยได้ ฉันหวังว่ามันจะ


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

9

ฉันเขียนฟังก์ชั่นที่มีประโยชน์เล็ก ๆ น้อย ๆ ตามคำตอบของคำถามนี้ ฉันวางมันไว้ที่นี่ในกรณีที่มันมีประโยชน์

def what(obj, callingLocals=locals()):
    """
    quick function to print name of input and value. 
    If not for the default-Valued callingLocals, the function would always
    get the name as "obj", which is not what I want.    
    """
    for k, v in list(callingLocals.items()):
         if v is obj:
            name = k
    print(name, "=", obj)

การใช้งาน:

>> a = 4
>> what(a)
a = 4
>>|

6

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

import types
import math  # mainly showing that you could import what you will before d

# Everything after this counts
d = dict(globals())

def kv_test(k,v):
    return (k not in d and 
            k not in ['d','args'] and
            type(v) is not types.FunctionType)

def magic_print(*args):
    if len(args) == 0: 
        return {k:v for k,v in globals().iteritems() if kv_test(k,v)}
    else:
        return {k:v for k,v in magic_print().iteritems() if k in args}

if __name__ == '__main__':
    foo = 1
    bar = 2
    baz = 3
    print magic_print()
    print magic_print('foo')
    print magic_print('foo','bar')

เอาท์พุท:

{'baz': 3, 'foo': 1, 'bar': 2}
{'foo': 1}
{'foo': 1, 'bar': 2}

6

ใน python 3 มันง่ายมาก

myVariable = 5
for v in locals():
  if id(v) == id("myVariable"):
    print(v, locals()[v])

สิ่งนี้จะพิมพ์:

myVariable 5


สิ่งนี้คล้ายกับวิธีของ rlotun แต่ค่อนข้างง่ายกว่า
ทางการ

10
-1 for v in locals()เปิดหน้าต่างล่ามใหม่และลอง
อากาศ

ฉันไม่แน่ใจว่าคุณหมายถึงอะไร?
เป็นทางการ

4
สิ่งนี้จะทำให้เกิดข้อผิดพลาด: RuntimeError: ขนาดพจนานุกรมเปลี่ยนแปลงระหว่างการวนซ้ำ ...
Nizar B.

2
แต่คุณสามารถทำได้for v in list(locals()):
ฟิลลิด้า

5

Python3 ใช้การตรวจสอบเพื่อจับภาพเนมสเปซในการโทรจากนั้นใช้แนวคิดที่แสดงไว้ที่นี่ สามารถส่งคืนมากกว่าหนึ่งคำตอบตามที่ได้อธิบายไว้

def varname(var):
  import inspect
  frame = inspect.currentframe()
  var_id = id(var)
  for name in frame.f_back.f_locals.keys():
    try:
      if id(eval(name)) == var_id:
        return(name)
    except:
      pass

คำตอบที่ดี แต่สำหรับฉันมันดีกว่ากับ: ... id (eval (ชื่อ, ไม่มี, frame.f_back.f_locals)) == ...
Emmanuel DUMAS

5

นี่คือฟังก์ชั่นที่ฉันสร้างขึ้นเพื่ออ่านชื่อตัวแปร เป็นเรื่องทั่วไปมากขึ้นและสามารถใช้ในแอปพลิเคชันต่างๆ

def get_variable_name(*variable):
    '''gets string of variable name
    inputs
        variable (str)
    returns
        string
    '''
    if len(variable) != 1:
        raise Exception('len of variables inputed must be 1')
    try:
        return [k for k, v in locals().items() if v is variable[0]][0]
    except:
        return [k for k, v in globals().items() if v is variable[0]][0]

หากต้องการใช้ในคำถามที่ระบุ:

>>> foo = False
>>> bar = True
>>> my_dict = {get_variable_name(foo):foo, 
               get_variable_name(bar):bar}
>>> my_dict
{'bar': True, 'foo': False}

4

ในการอ่านด้ายฉันเห็นแรงเสียดทานมากมาย มันง่ายพอที่จะให้คำตอบที่ไม่ดีจากนั้นให้ใครบางคนให้คำตอบที่ถูกต้อง อย่างไรก็ตามนี่คือสิ่งที่ฉันพบ

จาก: [effbot.org] ( http://effbot.org/zone/python-objects.htm#names )

ชื่อนั้นต่างออกไปเล็กน้อย - พวกมันไม่ใช่คุณสมบัติของวัตถุจริงๆและตัววัตถุเองก็ไม่รู้ว่ามันถูกเรียกว่าอะไร

วัตถุสามารถมีชื่อจำนวนเท่าใดก็ได้หรือไม่มีชื่อเลยก็ได้

ชื่อถ่ายทอดสดในเนมสเปซ (เช่นโมดูลเนมสเปซ, เนมสเปซอินสแตนซ์, เนมสเปซท้องถิ่นของฟังก์ชัน)

หมายเหตุ: มันบอกว่าวัตถุเองไม่รู้ว่ามันถูกเรียกว่าอะไรนั่นคือเบาะแส วัตถุ Python ไม่ได้อ้างอิงตนเอง จากนั้นก็กล่าวว่ารายชื่ออยู่ใน namespaces เรามีสิ่งนี้ใน TCL / TK ดังนั้นคำตอบของฉันอาจจะช่วยได้ (แต่มันก็ช่วยฉันได้)

    jj = 123
    พิมพ์ eval ("'" + str (id (jj)) + "'")
    พิมพ์ dir ()

166707048
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']

ดังนั้นจึงมี 'jj' อยู่ท้ายรายการ

เขียนรหัสใหม่เป็น:

    jj = 123
    พิมพ์ eval ("'" + str (id (jj)) + "'")
    สำหรับ x ใน dir ():
        พิมพ์ id (eval (x))

161922920
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']
3077447796
136515736
3077408320
3077656800
136515736
161922920

รหัสประจำตัวที่น่ารังเกียจนี้เป็นชื่อของตัวแปร / วัตถุ / อะไรก็ตามที่คุณอวดรู้ - เรียกมัน

ดังนั้นจึงเป็น ที่อยู่หน่วยความจำของ 'jj' จะเหมือนกันเมื่อเราค้นหาโดยตรงเช่นเมื่อเราค้นหาพจนานุกรมในพื้นที่ชื่อส่วนกลาง ฉันแน่ใจว่าคุณสามารถสร้างฟังก์ชันนี้ได้ เพียงจำไว้ว่าเนมสเปซตัวแปร / วัตถุ / wypci ของคุณอยู่ในระบบ

QED


6
คุณมีการใช้ eval สองครั้งที่นี่ ตัวแรกนั้นเหมือนกับ: print id(jj). vars()อย่างที่สองก็เงยหน้าขึ้นชื่อและสามารถทำได้อย่างง่ายดายมากขึ้นด้วย
Ned Batchelder

2

บางทีฉันอาจจะคิดถึงเรื่องนี้ แต่ ..

str_l = next((k for k,v in locals().items() if id(l) == id(v)))


>>> bar = True
>>> foo = False
>>> my_dict=dict(bar=bar, foo=foo)
>>> next((k for k,v in locals().items() if id(bar) == id(v)))
'bar'
>>> next((k for k,v in locals().items() if id(foo) == id(v)))
'foo'
>>> next((k for k,v in locals().items() if id(my_dict) == id(v)))
'my_dict'

ที่ดี! นี่คือสิ่งที่ฉันกำลังมองหา ขอบคุณ @ rh0dium ... \ nvariable = 1 \n [k for k,v in locals().items() if id(variable) == id(v)] \n Out[14]: ['variable']
Majdi

2
import re
import traceback

pattren = re.compile(r'[\W+\w+]*get_variable_name\((\w+)\)')
def get_variable_name(x):
    return pattren.match( traceback.extract_stack(limit=2)[0][3]) .group(1)

a = 1
b = a
c = b
print get_variable_name(a)
print get_variable_name(b)
print get_variable_name(c)

2

ฉันได้อัปโหลดวิธีการแก้pypi มันเป็นโมดูลที่กำหนดnameofฟังก์ชั่นที่เทียบเท่ากับ C #

มันวนซ้ำตามคำสั่ง bytecode สำหรับเฟรมที่เรียกใช้เรียกชื่อตัวแปร / แอ็ตทริบิวต์ผ่านไป ชื่อที่พบใน.argreprของLOADคำแนะนำต่อไปนี้ชื่อของฟังก์ชัน



1

วัตถุส่วนใหญ่ไม่มีชื่อ__แอตทริบิวต์(คลาส, ฟังก์ชั่นและโมดูลต่าง ๆ ; ประเภทบิวอินอื่น ๆ ที่มีอยู่แล้ว?)

อะไรที่คุณจะคาดหวังสำหรับprint(my_var.__name__)อื่น ๆ มากกว่าprint("my_var") ? คุณสามารถใช้สตริงได้โดยตรงหรือไม่

คุณสามารถ "หั่น" คำสั่ง:

def dict_slice(D, keys, default=None):
  return dict((k, D.get(k, default)) for k in keys)

print dict_slice(locals(), ["foo", "bar"])
# or use set literal syntax if you have a recent enough version:
print dict_slice(locals(), {"foo", "bar"})

อีกวิธีหนึ่งคือ:

throw = object()  # sentinel
def dict_slice(D, keys, default=throw):
  def get(k):
    v = D.get(k, throw)
    if v is not throw:
      return v
    if default is throw:
      raise KeyError(k)
    return default
  return dict((k, get(k)) for k in keys)

2
+1 แต่ฉันรู้ว่าชื่อนั้นไม่มีอยู่ทำไมทุกคนถึงใช้ "สิ่งที่คล้าย" ครอก? วิธีการแก้ปัญหาของคุณไม่สามารถแก้ปัญหาได้เนื่องจากฉันไม่ต้องการใส่รหัสให้ชัดเจนฉันจะใช้วิธีแก้ปัญหาแบบ dict ที่ฉันให้มาในคำถาม
E-satis

3
@ e-Satisfaction: หากใช้ทุกอย่างในท้องถิ่น () เพื่อแก้ปัญหาของคุณฉันไม่รู้ว่าคุณกำลังถามอะไร ฉันเดาว่าคุณโอเคกับการโทรsome_func(var)ดังนั้นฉันพยายามที่จะชี้ให้เห็นว่าไม่ไกลจากsome_func("var")นั้นด้วย dictsliceช่วยให้คุณได้รับการจับคู่ชื่อ - ค่าสำหรับตัวแปรหลายตัวพร้อมกัน

1

ดีฉันพบเดียวกันมากจำเป็นไม่กี่วันที่ผ่านมาและจะต้องได้รับตัวแปรของชื่อซึ่งชี้ไปที่วัตถุตัวเอง

และทำไมมันถึงจำเป็น?

ในระยะสั้นฉันถูกสร้าง Plug-in สำหรับมายา ปลั๊กอินหลักถูกสร้างขึ้นโดยใช้ C ++ แต่ GUI ถูกวาดผ่าน Python (เนื่องจากไม่ได้ใช้ตัวประมวลผลมาก) ตั้งแต่ฉันยังไม่รู้วิธีการreturnหลายค่าจากปลั๊กอินยกเว้นค่าเริ่มต้นMStatusดังนั้นการปรับปรุงพจนานุกรมใน Python ฉันต้องผ่านชื่อของตัวแปรชี้ไปที่วัตถุที่ใช้ GUI และสิ่งที่ มีพจนานุกรมตัวเองไปยังปลั๊กอินแล้วใช้MGlobal::executePythonCommand()เพื่ออัปเดตพจนานุกรมจากขอบเขตทั่วโลกของมายามายา

เมื่อต้องการทำสิ่งที่ฉันทำคือสิ่งที่ชอบ:

import time

class foo(bar):

    def __init__(self):
        super(foo, self).__init__()
        self.time = time.time() #almost guaranteed to be unique on a single computer

    def name(self):
        g = globals()
        for x in g:
            if isinstance(g[x], type(self)):
                if g[x].time == self.time:
                    return x
                    #or you could:
                    #return filter(None,[x if g[x].time == self.time else None for x in g if isinstance(g[x], type(self))])
                    #and return all keys pointing to object itself

ฉันรู้ว่ามันไม่ได้เป็นโซลูชั่นที่สมบูรณ์แบบในglobalsหลาย ๆ ปุ่มสามารถชี้ไปที่วัตถุเดียวกันเช่น:

a = foo()
b = a
b.name()
>>>b
or
>>>a

และวิธีการนั้นไม่ปลอดภัยสำหรับเธรด ถูกต้องฉันถ้าฉันผิด

อย่างน้อยวิธีการนี้แก้ไขปัญหาของฉันโดยรับชื่อของตัวแปรใด ๆ ในขอบเขตส่วนกลางซึ่งชี้ไปที่วัตถุนั้นและส่งผ่านไปยังปลั๊กอินเป็นอาร์กิวเมนต์เพื่อใช้ภายใน

ฉันลองทำสิ่งนี้int(คลาสจำนวนเต็มดั้งเดิม) แต่ปัญหาคือคลาสดั้งเดิมเหล่านี้ไม่ได้ข้ามไป (โปรดแก้ไขคำศัพท์ทางเทคนิคที่ใช้ถ้ามันผิด) คุณสามารถนำกลับมาใช้ใหม่ได้intแล้วทำint = fooแต่a = 3จะไม่เป็นวัตถุของfooดั้งเดิม แต่อย่างใด ที่จะเอาชนะที่คุณจะต้องa = foo(3)ที่จะได้รับa.name()ในการทำงาน


1

ด้วย python 2.7 และใหม่กว่านั้นยังมีความเข้าใจในพจนานุกรมซึ่งทำให้สั้นลงเล็กน้อย ถ้าเป็นไปได้ฉันจะใช้ getattr แทน eval (eval is evil) เหมือนในคำตอบด้านบน ตัวเองสามารถเป็นวัตถุใด ๆ ที่มีบริบทของคุณดู มันอาจเป็นวัตถุหรือคนในท้องถิ่น = ชาวบ้าน () ฯลฯ

{name: getattr(self, name) for name in ['some', 'vars', 'here]}

1

ฉันกำลังทำงานกับปัญหาที่คล้ายกัน @ S.Lott พูดว่า "หากคุณมีรายการตัวแปรอะไรคือจุดที่" ค้นพบ "ชื่อของพวกเขา? และคำตอบของฉันคือเพื่อดูว่าสามารถทำได้หรือไม่และด้วยเหตุผลบางอย่างที่คุณต้องการจัดเรียงตัวแปรตามประเภทลงในรายการ ดังนั้นต่อไปในการวิจัยของฉันฉันได้พบกับเธรดนี้และโซลูชันของฉันมีการขยายตัวเล็กน้อยและขึ้นอยู่กับโซลูชัน @rlotun อีกอย่างหนึ่ง @unutbu กล่าวว่า "ความคิดนี้มีข้อดี แต่โปรดทราบว่าหากชื่อตัวแปรสองตัวอ้างอิงค่าเดียวกัน (เช่น True) แล้วชื่อตัวแปรที่ไม่ได้ตั้งใจอาจถูกส่งคืน" ในแบบฝึกหัดนี้ที่เป็นจริงดังนั้นฉันจึงจัดการกับมันโดยใช้รายการความเข้าใจที่คล้ายกับสิ่งนี้สำหรับแต่ละความเป็นไปได้: isClass = [i for i in isClass if i != 'item']. หากไม่มี "รายการ" จะปรากฏในแต่ละรายการ

__metaclass__ = type

from types import *

class Class_1: pass
class Class_2: pass
list_1 = [1, 2, 3]
list_2 = ['dog', 'cat', 'bird']
tuple_1 = ('one', 'two', 'three')
tuple_2 = (1000, 2000, 3000)
dict_1 = {'one': 1, 'two': 2, 'three': 3}
dict_2 = {'dog': 'collie', 'cat': 'calico', 'bird': 'robin'}
x = 23
y = 29
pie = 3.14159
eee = 2.71828
house = 'single story'
cabin = 'cozy'

isClass = []; isList = []; isTuple = []; isDict = []; isInt = []; isFloat = []; isString = []; other = []

mixedDataTypes = [Class_1, list_1, tuple_1, dict_1, x, pie, house, Class_2, list_2, tuple_2, dict_2, y, eee, cabin]

print '\nMIXED_DATA_TYPES total count:', len(mixedDataTypes)

for item in mixedDataTypes:
    try:
        # if isinstance(item, ClassType): # use this for old class types (before 3.0)
        if isinstance(item, type):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isClass.append(mapping_as_str)
            isClass = [i for i in isClass if i != 'item']

        elif isinstance(item, ListType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isList.append(mapping_as_str)
            isList = [i for i in isList if i != 'item']

        elif isinstance(item, TupleType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isTuple.append(mapping_as_str)
            isTuple = [i for i in isTuple if i != 'item']

        elif isinstance(item, DictType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isDict.append(mapping_as_str)
            isDict = [i for i in isDict if i != 'item']

        elif isinstance(item, IntType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isInt.append(mapping_as_str)
            isInt = [i for i in isInt if i != 'item']

        elif isinstance(item, FloatType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isFloat.append(mapping_as_str)
            isFloat = [i for i in isFloat if i != 'item']

        elif isinstance(item, StringType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isString.append(mapping_as_str)
            isString = [i for i in isString if i != 'item']

        else:
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    other.append(mapping_as_str)
            other = [i for i in other if i != 'item']

    except (TypeError, AttributeError), e:
        print e

print '\n isClass:', len(isClass), isClass
print '  isList:', len(isList), isList
print ' isTuple:', len(isTuple), isTuple
print '  isDict:', len(isDict), isDict
print '   isInt:', len(isInt), isInt
print ' isFloat:', len(isFloat), isFloat
print 'isString:', len(isString), isString
print '   other:', len(other), other

# my output and the output I wanted
'''
MIXED_DATA_TYPES total count: 14

 isClass: 2 ['Class_1', 'Class_2']
  isList: 2 ['list_1', 'list_2']
 isTuple: 2 ['tuple_1', 'tuple_2']
  isDict: 2 ['dict_1', 'dict_2']
   isInt: 2 ['x', 'y']
 isFloat: 2 ['pie', 'eee']
isString: 2 ['house', 'cabin']
   other: 0 []
'''

ปัญหาที่ฉันจะใช้กับสิ่งนี้คือชื่อไม่ใช่คุณสมบัติของวัตถุ วัตถุเดียวอาจมีหลายชื่อหรือไม่มีชื่อเลย ตัวอย่างเช่นคุณเพิ่มpi = pieรหัสของคุณคุณจะได้รับรายการพิเศษในisFloatรายการของคุณ หากคุณเพิ่มลงtuple_1[0]ในmixedDataTypesรายการของคุณจะไม่พบชื่อใด ๆ แม้ว่าจะมี "หนึ่ง" อยู่ในรหัสของคุณสองครั้ง (แต่ต้องขอบคุณการใช้สตริง
Blckknght

1
@Blckknght --- ฉันเห็นด้วย นี่เป็นอีกวิธีหนึ่งในการทำสิ่งที่ไม่ได้ตั้งใจทำ ฉันไม่ได้บอกว่ามันให้ผลลัพธ์ที่เป็นเอกลักษณ์หรือไม่ผิดพลาด ในการทำเช่นนี้ฉันพบว่าการใช้piและeเป็นตัวแปรทำให้เกิดผลลัพธ์ที่ไม่ต้องการและนั่นเป็นเพราะทั้งคู่เป็นส่วนหนึ่งของmathไลบรารี สำหรับฉันนี่เป็นเพียงการออกกำลังกายเพื่อดูว่ามันสามารถทำได้แม้ว่าผลลัพธ์สุดท้ายจะไม่สมบูรณ์แบบ ในการเรียนรู้ของฉันเกี่ยวกับภาษานี้ผ่านหนังสือเท่านั้นจนถึงตอนนี้ ในความคิดของฉันถ้าคุณต้องการเรียนรู้ภาษาจริงๆคุณต้องเล่น "จะเกิดอะไรขึ้นถ้า" และดูว่าคุณเกิดอะไรขึ้น
Michael Swartz

1

คุณสามารถใช้ easydict

>>> from easydict import EasyDict as edict
>>> d = edict({'foo':3, 'bar':{'x':1, 'y':2}})
>>> d.foo
3
>>> d.bar.x
1
>>> d = edict(foo=3)
>>> d.foo
3

ตัวอย่างอื่น:

>>> d = EasyDict(log=False)
>>> d.debug = True
>>> d.items()
[('debug', True), ('log', False)]

1

ใน python3 ฟังก์ชั่นนี้จะได้รับชื่อนอกสุดในสแต็ค:

import inspect


def retrieve_name(var):
        """
        Gets the name of var. Does it from the out most frame inner-wards.
        :param var: variable to get name from.
        :return: string
        """
        for fi in reversed(inspect.stack()):
            names = [var_name for var_name, var_val in fi.frame.f_locals.items() if var_val is var]
            if len(names) > 0:
                return names[0]

มันมีประโยชน์ทุกที่ในรหัส สำรวจสแต็กที่กลับด้านเพื่อค้นหาคู่แรก


0

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

import inspect
def getVarName(getvar):
  frame = inspect.currentframe()
  callerLocals = frame.f_back.f_locals
  for k, v in list(callerLocals.items()):
    if v is getvar():
      callerLocals.pop(k)
      try:
        getvar()
        callerLocals[k] = v
      except NameError:
        callerLocals[k] = v
        del frame
        return k
  del frame

คุณเรียกว่าแบบนี้:

bar = True
foo = False
bean = False
fooName = getVarName(lambda: foo)
print(fooName) # prints "foo"

0

ควรได้รับรายชื่อแล้วส่งคืน

def get_var_name(**kwargs):
    """get variable name
        get_var_name(var = var)
    Returns:
        [str] -- var name
    """
    return list(kwargs.keys())[0]

0

มันจะไม่ส่งคืนชื่อของตัวแปร แต่คุณสามารถสร้างพจนานุกรมจากตัวแปรทั่วโลกได้อย่างง่ายดาย

class CustomDict(dict):
    def __add__(self, other):
        return CustomDict({**self, **other})

class GlobalBase(type):
    def __getattr__(cls, key):
        return CustomDict({key: globals()[key]})

    def __getitem__(cls, keys):
        return CustomDict({key: globals()[key] for key in keys})

class G(metaclass=GlobalBase):
    pass

x, y, z = 0, 1, 2

print('method 1:', G['x', 'y', 'z']) # Outcome: method 1: {'x': 0, 'y': 1, 'z': 2}
print('method 2:', G.x + G.y + G.z) # Outcome: method 2: {'x': 0, 'y': 1, 'z': 2}

0

ด้วยpython-varnameคุณสามารถทำได้อย่างง่ายดาย:

pip install python-varname

from varname import Wrapper

foo = Wrapper(True)
bar = Wrapper(False)

your_dict = {val.name: val.value for val in (foo, bar)}

print(your_dict)

# {'foo': True, 'bar': False}

ข้อจำกัดความรับผิดชอบ: ฉันเป็นผู้เขียนห้องสมุด python-varname


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.