Python extremely dynamic class properties

2019-06-28 07:17发布

To create a property in a class you simply do self.property = value. I want to be able to have the properties in this class completely dependent on a parameter. Let us call this class Foo.

instances of the Foo class would take a list of tuples:

l = [("first","foo"),("second","bar"),("anything","you get the point")]
bar = Foo(l)

now the instance of the Foo class we assigned to bar would have the following properties:

bar.first
#foo
bar.second
#bar
bar.anything
#you get the point

Is this even remotely possible? How?

标签: python class
5条回答
迷人小祖宗
2楼-- · 2019-06-28 07:31

There are two ways to do this:

  • Use setattr like this. This approach is feasible if you only need to process the initial list once, when the object is constructed.

    class Foo:
      def __init__(self, l):
        for (a, b) in l:
          setattr(self, a, b)
    
  • Define a custom __getattr__ method. Preferably, you would store the properties in a dict for faster lookup, but you can also search the original list. This is better if you want to later modify the list and want this to be reflected in the attributes of the object.

    class Foo:
      def __init__(self, l):
        self.l = l
      def __getattr__(self, name):
        for a in self.l:
          if a[0] == name:
            return a[1]
        return None
    
查看更多
手持菜刀,她持情操
3楼-- · 2019-06-28 07:35

setattr works.

>>> class Foo:
...   def __init__(self,yahoo):
...     for k,v in yahoo:
...       setattr(self,k,v)
...
>>> l = [("first","foo"),("second","bar"),("anything","you get the point")]
>>> bar = Foo(l)
>>> print bar.first
foo
>>> print bar.second
bar
>>> print bar.anything
you get the point
查看更多
再贱就再见
4楼-- · 2019-06-28 07:39

These are called attributes, rather than properties. With that in mind, the method setattr() becomes more obvious:

class Foo(object):
    def __init__(self, l):
        for k, v in l:
            setattr(self, k, v)

This takes each key-value pair in l and sets the attribute k on the new instance of Foo (self) to v.

Using your example:

l = [("first","foo"),("second","bar"),("anything","you get the point")]
bar = Foo(l)

print bar.first
#foo
print bar.second
#bar
print bar.anything
#you get the point
查看更多
叛逆
5楼-- · 2019-06-28 07:44

Something like this?

>>> class Foo:
...     def __init__(self, mylist):
...         for k, v in mylist:
...             setattr(self, k, v)
... 
>>> l = [("first","foo"),("second","bar"),("anything","you get the point")]
>>> bar = Foo(l)
>>> bar.first
'foo'
>>> bar.second
'bar'
>>> bar.anything
'you get the point'

Using setattr you can do this by passing in the list and just iterating through it.

查看更多
干净又极端
6楼-- · 2019-06-28 07:52

I thought of another answer you could use using type(). It's completely different to my current answer so I've added a different answer:

>>> bar = type('Foo', (), dict(l))()
>>> bar.first
'foo'
>>> bar.second
'bar'
>>> bar.anything
'you get the point'

type() returns a class, not an instance, hence the extra () at the end.

查看更多
登录 后发表回答