This is a bit of a silly thing, but I want to know if there is concise way in Python to define class variables that contain string representations of their own names. For example, one can define:
class foo(object):
bar = 'bar'
baz = 'baz'
baf = 'baf'
Probably a more concise way to write it in terms of lines consumed is:
class foo(object):
bar, baz, baf = 'bar', 'baz', 'baf'
Even there, though, I still have to type each identifier twice, once on each side of the assignment, and the opportunity for typos is rife.
What I want is something like what sympy provides in its var method:
sympy.var('a,b,c')
The above injects into the namespace the variables a, b, and c, defined as the corresponding sympy symbolic variables.
Is there something comparable that would do this for plain strings?
class foo(object):
[nifty thing]('bar', 'baz', 'baf')
EDIT: To note, I want to be able to access these as separate identifiers in code that uses foo:
>>> f = foo(); print(f.bar)
bar
ADDENDUM: Given the interest in the question, I thought I'd provide more context on why I want to do this. I have two use-cases at present: (1) typecodes for a set of custom exceptions (each Exception subclass has a distinct typecode set); and (2) lightweight enum. My desired feature set is:
Only having to type the typecode / enum name (or value) once in the source definition. class foo(object): bar = 'bar' works fine but means I have to type it out twice in-source, which gets annoying for longer names and exposes a typo risk.
Valid typecodes / enum values exposed for IDE autocomplete.
Values stored internally as comprehensible strings:
For the Exception subclasses, I want to be able to define myError.__str__ as just something like return self.typecode + ": " + self.message + " (" + self.source + ")", without having to do a whole lot of dict-fu to back-reference an int value of self.typecode to a comprehensible and meaningful string.
For the enums, I want to just be able to obtain widget as output from e = myEnum.widget; print(e), again without a lot of dict-fu.
I recognize this will increase overhead. My application is not speed-sensitive (GUI-based tool for driving a separate program), so I don't think this will matter at all.
Straightforward membership testing, by also including (say) a frozenset containing all of the typecodes / enum string values as myError.typecodes/myEnum.E classes. This addresses potential problems from accidental (or intentional.. but why?!) use of an invalid typecode / enum string via simple sanity checks like if not enumVal in myEnum.E: raise(ValueError('Invalid enum value: ' + str(enumVal))).
Ability to import individual enum / exception subclasses via, say, from errmodule import squirrelerror, to avoid cluttering the namespace of the usage environment with non-relevant exception subclasses. I believe this prohibits any solutions requiring post-twiddling on the module level like what Sinux proposed.
For the enum use case, I would rather avoid introducing an additional package dependency since I don't (think I) care about any extra functionality available in the official enum class. In any event, it still wouldn't resolve #1.
I've already figured out implementation I'm satisfied with for all of the above but #1. My interest in a solution to #1 (without breaking the others) is partly a desire to typo-proof entry of the typecode / enum values into source, and partly plain ol' laziness. (Says the guy who just typed up a gigantic SO question on the topic.)
I recommend using collections.namedtuple:
Example:
>>> from collections import namedtuple as nifty_thing
>>> Data = nifty_thing("Data", ["foo", "bar", "baz"])
>>> data = Data(foo=1, bar=2, baz=3)
>>> data.foo
1
>>> data.bar
2
>>> data.baz
3
Side Note: If you are using/on Python 3.x I'd recommend Enum as per #user2357112's comment. This is the standardized approach going forward for Python 3+
Update: Okay so if I understand the OP's exact requirement(s) here I think the only way to do this (and presumably sympy does this too) is to inject the names/variables into the globals() or locals() namespaces. Example:
#!/usr/bin/env python
def nifty_thing(*names):
d = globals()
for name in names:
d[name] = None
nifty_thing("foo", "bar", "baz")
print foo, bar, bar
Output:
$ python foo.py
None None None
NB: I don't really recommend this! :)
Update #2: The other example you showed in your question is implemented like this:
#!/usr/bin/env python
import sys
def nifty_thing(*names):
frame = sys._getframe(1)
locals = frame.f_locals
for name in names:
locals[name] = None
class foo(object):
nifty_thing("foo", "bar", "baz")
f = foo()
print f.foo, f.bar, f.bar
Output:
$ python foo.py
None None None
NB: This is inspired by zope.interface.implements().
current_list = ['bar', 'baz', 'baf']
class foo(object):
"""to be added"""
for i in current_list:
setattr(foo, i, i)
then run this:
>>>f = foo()
>>>print(f.bar)
bar
>>>print(f.baz)
baz
This doesn't work exactly like what you asked for, but it seems like it should do the job:
class AutoNamespace(object):
def __init__(self, names):
try:
# Support space-separated name strings
names = names.split()
except AttributeError:
pass
for name in names:
setattr(self, name, name)
Demo:
>>> x = AutoNamespace('a b c')
>>> x.a
'a'
If you want to do what SymPy does with var, you can, but I would strongly recommend against it. That said, here's a function based on the source code of sympy.var:
def var(names):
from inspect import currentframe
frame = currentframe().f_back
try:
names = names.split()
except AttributeError:
pass
for name in names:
frame.f_globals[name] = name
Demo:
>>> var('foo bar baz')
>>> bar
'bar'
It'll always create global variables, even if you call it from inside a function or class. inspect is used to get at the caller's globals, whereas globals() would get var's own globals.
How about you define the variable as emtpy string and then get their name:
class foo(object):
def __getitem__(self, item):
return item
foo = foo()
print foo['test']
Here's an extension of bman's idea. This has its advantages and disadvantages, but at least it does work with some autocompleters.
class FooMeta(type):
def __getattr__(self, attr):
return attr
def __dir__(self):
return ['bar', 'baz', 'baf']
class foo:
__metaclass__ = FooMeta
This allows access like foo.xxx → 'xxx' for all xxx, but also guides autocomplete through __dir__.
Figured out what I was looking for:
>>> class tester:
... E = frozenset(['this', 'that', 'the', 'other'])
... for s in E:
... exec(str(s) + "='" + str(s) + "'") # <--- THIS
...
>>> tester()
<__main__.tester instance at 0x03018BE8>
>>> t = tester()
>>> t.this
'this'
>>> t.that in tester.E
True
Only have to define the element strings once, and I'm pretty sure it will work for all of my requirements listed in the question. In actual implementation, I plan to encapsulate the str(s) + "='" + str(s) + "'" in a helper function, so that I can just call exec(helper(s)) in the for loop. (I'm pretty sure that the exec has to be placed in the body of the class, not in the helper function, or else the new variables would be injected into the (transitory) scope of the helper function, not that of the class.)
EDIT: Upon detailed testing, this DOES NOT WORK -- the use of exec prevents the introspection of the IDE from knowing of the existence of the created variables.
I think you can achieve a rather beautiful solution using metaclasses, but I'm not fluent enough in using those to present that as an answer, but I do have an option which seems to work rather nicely:
def new_enum(name, *class_members):
"""Builds a class <name> with <class_members> having the name as value."""
return type(name, (object, ), { val : val for val in class_members })
Foo = new_enum('Foo', 'bar', 'baz', 'baf')
This should recreate the class you've given as example, and if you want you can change the inheritance by changing the second parameter of the call to class type(name, bases, dict).
so I've been reading up on getattr, and was wondering what the equivalent of
example = val1.val2.val3(item)
would be.
So I get that you have to use nested getattr to implement multiple levels attributes
example = getattr(getattr(val1, "val2"), "val3")
but how do I represent the object being passed in?
Or you can use a neat function from the standard library operator.attrgetter. Here a little example on how to use it.
from operator import attrgetter
from collections import namedtuple
# Define some objects
Foo = namedtuple('Foo', 'attr')
Bar = namedtuple('Bar', 'subattr1')
instance = Foo(attr=Bar('this_is_my_value'))
retriever = attrgetter('attr.subattr1')
result = retriever(instance)
print(result)
This executed will give you
this_is_my_value
You're almost there:
val3 = getattr(getattr(val1, "val2"), "val3")
example = val3(item)
# Or simply:
example = getattr(getattr(val1, "val2"), "val3")(item)
This can be worked out with safe eval. If the nested attributes are available, this will work.
fn_pointer = eval("val1.val2.val3", {}, {"val1": val1})
fn_pointer(item)
I want to create instance objects automatically as I explained in the following:
Class MyClass:
def __init__(self,x):
self.x = x
list = ["A","B"]
I want to create the following but automatically, means to loop through the list and create identical object for each element:
A = MyClass(text)
B = MyClass(text)
e.g. like the following which doesn't work:
# this doesn't work but explains more what I need
for i in list:
i = MyClass(text)
Thanks to all of your help!
In general, you can't and shouldn't shove things into your namespace like that. It's better to store those instances in a dict or a list
Class MyClass:
def __init__(self,x):
self.x = x
lst = ["A","B"] # don't use list as an identifier
myclasses = {k: MyClass(text) for k in lst}
Now your instances are
myclasses['A'], myclasses['B'] etc.
If you really want to create a handful of variables in your namespace:
A, B = (MyClass(text) for x in range(2))
note that this means you need to be explicit. You can't get the A,B from a file or user input etc.
Don't be tempted to use exec to pull this off. It's probably the wrong way to go about solving your problem. Tell us why you think you need to do it instead.
How can I iterate over an object and assign all it properties to a list
From
a = []
class A(object):
def __init__(self):
self.myinstatt1 = 'one'
self.myinstatt2 = 'two'
to
a =['one','two']
Don't create a full fledged class if you just want to store a bunch of attributes and return a list so that your API can consume it. Use a namedtuple instead. Here is an example.
>>> import collections
>>> Point = collections.namedtuple('Point', ['x', 'y'])
>>> p = Point(1, 2)
>>> p
Point(x=1, y=2)
If your API just expects a sequence (not specifically a list), you can pass p directly. If it needs a list specifically, it is trivial to convert the Point object to a list.
>>> list(p)
[1, 2]
You can even subclass the newly created Point class and add more methods (documentation has details). If namedtuple doesn't meet your needs, consider sub-classing abc.Sequence Abstract Base Class or using it as a mixin.
One approach is to make your class behave like a list by implementing some or all of the container API. Depending on how the external API you're using works, you might only need to implement __iter__. If it needs more, you could always pass it list(a), which will build a list using an iterator.
Here's an example of how easy it can be to add an __iter__ method:
class A(object):
def __init__(self):
self.myAttr1 = "one"
self.myAttr2 = "two"
def __iter__(self):
yield self.myAttr1
yield self.myAttr2
What I want to do in my code:
myobj = <SomeBuiltinClass>()
myobj.randomattr = 1
print myobj.randomattr
...
I can implement a custom SomeClass that implements __setattr__ __getattr__.
But I wonder if there is already a built-in Python class or simple way to do this?
You can just use an empty class:
class A(object): pass
a = A()
a.randomattr = 1
I like using the Bunch idiom for this. There are list of variations and some discussion here.
One solution is to use mock's:
from mock import Mock
myobj = Mock()
myobj.randomattr = 1
print myobj.randomattr
Second solution is to use namedtuple:
from collections import namedtuple
myobj = namedtuple('MyObject', '')
myobj.randomattr = 1
print myobj.randomattr