Python equivalent to VB “with” block

前端 未结 4 394
北海茫月
北海茫月 2020-12-22 08:46

VB (and C99 and C#, actually) have a way to set multiple attributes on one object with a contracted syntax where you don\'t have to repeat the object name before \".\" . Is

相关标签:
4条回答
  • 2020-12-22 09:33

    Let's write a function!

    def update_attr(obj, **kw):
        for key, value in kw.iteritems():
            setattr(obj, key, value)
    

    Let's use the function!

    class X:
        pass
    
    x = X()
    
    update_attr(x, blue=3, red=5)
    update_attr(x, **{'yellow': 6})
    
    print vars(x)
    

    The output!

    {'blue': 3, 'yellow': 6, 'red': 5}
    
    0 讨论(0)
  • 2020-12-22 09:37

    If your objective is just to avoid repetition and you are working with your own objects, you could use a fluent interface like this:

    obj.set_attr1('foo')
       .set_attr2('bar')
    
    0 讨论(0)
  • 2020-12-22 09:39

    First, keep in mind that you're really not saving much space—and you could save a lot more space, and make your style more Pythonic, by just temporarily binding the object to a shorter name:

    _ = obj
    _.attr1 = 'foo'
    _.attr2 = 'bar'
    

    Compare that to VB-ish syntax:

    vbwith obj:
        .attr1 = 'foo'
        .attr2 = 'bar'
    

    You're really only typing and reading one extra character per line. Is that too much of a burden?

    This wouldn't work in languages with C-style variables with value-copying semantics, because you'd just be setting attributes on a copy of obj. But in Python, a = b makes a into another name for the value that b names, it doesn't copy anything. (If you're coming from a C background, it may help to think of this as _ = &obj followed by a bunch of lines starting _->.)


    If you really want to do this, the safest way is to write update_attr as a loop around setattr:

    def update_attrs(obj, **attrs):
        for attr, value in attrs.items():
            setattr(obj, attr, value)
    
    update_attr(obj,
        attr1='foo',
        attr2='bar'
    )
    

    The reason you want to use setattr rather than modifying the object's __dict__ or vars() is that not all attributes are stored in the object's __dict__. They may be stored in __slots__, or @property descriptors on the class, or get-set methods on a C extension object, or some custom thing provided by the metaclass. So, modifying the __dict__ may fail in some cases, or may appear to work but do nothing, or, worst of all, do the wrong thing in a way that's very hard to tell (like hiding a property instead of setting it). setattr is guaranteed to work whenever direct access would work, and to fail whenever direct access would fail.


    While much of the Python community thinks actual VB-style with syntax is a bad thing (although I can't find the link to Guido's blog post about it), your more explicit syntax seems readable and not at all misleading to me, so if you really want to use this function, go ahead. But again, I don't think there's much need.

    0 讨论(0)
  • 2020-12-22 09:47

    Perhaps this is unpythonic but VB-style With blocks can help make the program structure clearer. This is useful when setting up hierarchical structures, such as GUI layouts.

    The "quick, dirty and perhaps unpythonic" way to do this is:

    for x in [my_object_with_a_long_name]:
        x.my_method()
        x.another_method()
        ...
    
    0 讨论(0)
提交回复
热议问题