I have the following code:
def f():
class XYZ:
# ...
cls = type('XXX', (XYZ, ), {})
# ...
return cls
I am now using it as follows:
C1 = f()
C2 = f()
and it seems to work fine: C1 is C2 returns False, there's no conflict between the class attributes of the two classes, etc.
Question 1
Why is that? How is it possible that C1 and C2 are both shown as class
<'__main__.XXX'>
and yet not the same class?
Question 2
Is there some problem with the fact that I have two identical names for two different classes?
Question 3
I would like to be able to write instead:
f('C1')
f('C2')
with the same effect. Is it possible?
Question 4
If I want C1 to look like a regular class, not main.XXX, is it ok to say:
C1.__name__ = '__main__.C1'
Question 3
To have cls.__name__ be anything you want, (with a nod to delnan's suggestion)
def f(clsname):
class XYZ:
# ...
XYZ.__name__ = XYZ
# ...
return XYZ
Question 1
The reason that c1 is not c2 is that they are two different objects stored at two different locations in memory.
Question 4
Try an answer to question 1 and see how it works out for you
Question 2
It can complicate debugging that their class attributes __name__ share a common value and this is bad enough to take pains to avoid. (see question 3). I would maintain though that they don't have the same name. One is named C1 and the other is named C2 (at least in the scope you are showing. If you were to pass them to a function, then there name in that scope would be the same as the name of parameter that they were passed through)
In fact, I'm so sure that they don't have the same name that trying to tell me otherwise is likely to cause me to turn the music up louder and pretend I can't hear you.
In response to comment
It can be done but it's just wrong. I'll illustrate anyway because it's illuminating:
def f(clsname):
class XYZ(object):
pass
XYZ.__name__ = clsname
globals()[clsname] = XYZ
f('C1')
f('C2')
print C1
print C2
This just works by sticking the class in the globals dict keyed by clsname. But what's the point? You can stick it in the globals dict under any name in fact because this is just another assignment. You are best off just returning the class from the function and letting the caller decide what name to give the class in it's own scope. You still have the __name__ attribute of the class set to the string you pass to the function for debugging purposes.
Actually, you don't need to the cls = ... line at all.
>>> def f():
... class C:
... pass
... return C
...
>>> f() is f()
False
Reason: class (as well as e.g. def) defines a new class each time it is encountered = each time the function is called.
As for cls.__name__, it's really no semantic difference. The name is useful for debugging (you don't expose it directly to the user, do you?) and introspection, but it shouldn't be an issue. But if you absolutely want to have different names, you can change cls.__name__ before returning (also note that after C.__name__ = 'foo', C.__name__ == '__main__.foo'!).
At question 3: It would be possible to inject it directly into global namespace... don't do this. It has no advantages, only disatvantages: nonobvious side effects, bad style, the fact it's a hack at all, etc!
Related
This question already has answers here:
How to access (get or set) object attribute given string corresponding to name of that attribute
(3 answers)
Closed 3 years ago.
I have a Python class that have attributes named: date1, date2, date3, etc.
During runtime, I have a variable i, which is an integer.
What I want to do is to access the appropriate date attribute in run time based on the value of i.
For example,
if i == 1, I want to access myobject.date1
if i == 2, I want to access myobject.date2
And I want to do something similar for class instead of attribute.
For example, I have a bunch of classes: MyClass1, MyClass2, MyClass3, etc. And I have a variable k.
if k == 1, I want to instantiate a new instance of MyClass1
if k == 2, I want to instantiate a new instance of MyClass2
How can i do that?
EDIT
I'm hoping to avoid using a giant if-then-else statement to select the appropriate attribute/class.
Is there a way in Python to compose the class name on the fly using the value of a variable?
You can use getattr() to access a property when you don't know its name until runtime:
obj = myobject()
i = 7
date7 = getattr(obj, 'date%d' % i) # same as obj.date7
If you keep your numbered classes in a module called foo, you can use getattr() again to access them by number.
foo.py:
class Class1: pass
class Class2: pass
[ etc ]
bar.py:
import foo
i = 3
someClass = getattr(foo, "Class%d" % i) # Same as someClass = foo.Class3
obj = someClass() # someClass is a pointer to foo.Class3
# short version:
obj = getattr(foo, "Class%d" % i)()
Having said all that, you really should avoid this sort of thing because you will never be able to find out where these numbered properties and classes are being used except by reading through your entire codebase. You are better off putting everything in a dictionary.
For the first case, you should be able to do:
getattr(myobject, 'date%s' % i)
For the second case, you can do:
myobject = locals()['MyClass%s' % k]()
However, the fact that you need to do this in the first place can be a sign that you're approaching the problem in a very non-Pythonic way.
OK, well... It seems like this needs a bit of work. Firstly, for your date* things, they should be perhaps stored as a dict of attributes. eg, myobj.dates[1], so on.
For the classes, it sounds like you want polymorphism. All of your MyClass* classes should have a common ancestor. The ancestor's __new__ method should figure out which of its children to instantiate.
One way for the parent to know what to make is to keep a dict of the children. There are ways that the parent class doesn't need to enumerate its children by searching for all of its subclasses but it's a bit more complex to implement. See here for more info on how you might take that approach. Read the comments especially, they expand on it.
class Parent(object):
_children = {
1: MyClass1,
2: MyClass2,
}
def __new__(k):
return object.__new__(Parent._children[k])
class MyClass1(Parent):
def __init__(self):
self.foo = 1
class MyClass2(Parent):
def __init__(self):
self.foo = 2
bar = Parent(1)
print bar.foo # 1
baz = Parent(2)
print bar.foo # 2
Thirdly, you really should rethink your variable naming. Don't use numbers to enumerate your variables, instead give them meaningful names. i and k are bad to use as they are by convention reserved for loop indexes.
A sample of your existing code would be very helpful in improving it.
to get a list of all the attributes, try:
dir(<class instance>)
I agree with Daenyth, but if you're feeling sassy you can use the dict method that comes with all classes:
>>> class nullclass(object):
def nullmethod():
pass
>>> nullclass.__dict__.keys()
['__dict__', '__module__', '__weakref__', 'nullmethod', '__doc__']
>>> nullclass.__dict__["nullmethod"]
<function nullmethod at 0x013366A8>
While learning about how classes work in Python I came across a class definition example which behaved kind of strangely in my eyes.
The purpose of the example was to demonstrate how the behaviour of a static variable can be achieved in Python. The example was written as follows:
class MemberCounter:
members = 0
def init(self):
MemberCounter.members += 1
m1 = MemberCounter()
m1.init()
m2 = MemberCounter()
m2.init()
after setting up the class and creating the objects, I printed the values of the 'members' attribute. These were the results:
MemberCounter.members = 2
m1.members = 2
m2.members = 2
And that's when I got confused. While I was expecting for 'MemberCounter.members = 2' the two other results made no sense to me - why would both of 'm1' and 'm2' objects' 'members' value be equal to 2? I thought that both of the values should have been 0 - if the only attribute that was chaged is the 'members' attribute which was attached to the MemberCounter class why would it cause any change to the own unique 'members' value of each of the class' objects. It looks like the fact that the 'members' attribute is addresed like 'MemberCounter.members += 1' in the init() function of each object, completely overrides the unique values which m1.members and m2.members refer to and redirects their pointers to the MemberCounter.members value making all the three pointers point at the same value
==> m1.members = m2.members = MemberCounter.members.
Moreover, I have tried defining the class in an opossite way (Increasing self.members instead of MemberCounter.members):
class MemberCounter:
members = 0
def init(self):
self.members += 1
m1 = MemberCounter()
m1.init()
m2 = MemberCounter()
m2.init()
This definition yielded logical results (which got me curious about the above mentioned strange behaviour even more):
MemberCounter.members = 0
m1.members = 1
m2.members = 1
In short, I was curious about why the first class definition behaves in such a strange way? Why the mere 'MemberCounter.members += 1' statement completely erased 'm1.members' and 'm2.members' own unique value and made it equal to the MemberCounter.members value.
I hope I was able to clearly present my problem and I will be extremly happy to get an insight about this strange behaviour :)
That you can read a static attribute with instance.attribute notation as alternative to the more natural class.attribute notation, is an intended feature in Python.
From the documentation:
Both static data and static methods (in the sense of C++ or Java) are supported in Python.
For static data, simply define a class attribute. To assign a new
value to the attribute, you have to explicitly use the class name in
the assignment:
class C:
count = 0 # number of times C.__init__ called
def __init__(self):
C.count = C.count + 1
def getcount(self):
return C.count # or return self.count
c.count also refers to C.count for any c such that
isinstance(c, C) holds, unless overridden by c itself or by some
class on the base-class search path from c.__class__ back to C.
Caution: within a method of C, an assignment like self.count = 42
creates a new and unrelated instance named “count” in self’s own dict.
Rebinding of a class-static data name must always specify the class
whether inside a method or not:
C.count = 314
The paragraph just below the first code block explains your doubts. The "Caution" paragraph explains what you found logical.
I have a general question about Python best practices.
Tried googling for an answer, but didn't find anything relevant.
The question is : is it best practice to explicitly pass a globally known parameter to a function?
So, is this best practice?
a = 1
def add_one(a):
b = a + 1
or this?
a = 1
def add_one():
b = a + 1
Here is an answer to expand on my comment regarding setting a as a class attribute, rather than using a global.
The Short Answer:
Use globals with controlled caution; or the safe play ... just don't. There's usually a better way.
Ref 1: PEP-8
Ref 2: This interesting post on SO, emphasising the need for caution
Passing variables is OK
Use a class at any (applicable) opportunity
Class Example:
Here is a simple, stripped down class structure with no frills. You'll notice the absence of any global variables, along with no passed variables.
This is not saying that passed variables are discouraged, they are useful, if not necessary. However, this is to show that globals are not needed, and there's usually a better way. For what it's worth ... (personally speaking, I've never seen the use for them in Python).
class Demo():
"""Class attribute demonstration class."""
def __init__(self):
"""Demo class initialiser."""
self._a = 73
def add_one(self):
"""Add one to the `a` attribute."""
self._a += 1
def times_two(self):
"""Multiply the `a` attribute by two."""
self._a *= 2
Use Case:
I'll be the first to point out that this example is all but useless in the real world due to 1) externally accessing a 'private' class attribute and 2) the continued updating of _a; this is only an example specific to your question.
Note that each call to a different function has a different, yet continued affect on _a; noting the variable (class attribute) is neither global, nor passed.
demo = Demo()
print(f'Value of _a: {demo._a}')
>>> Value of _a: 73
demo.add_one()
print(f'Value of _a plus one: {demo._a}')
>>> Value of _a plus one: 74
demo.times_two()
print(f'Value of _a plus one, times two: {demo._a}')
>>> Value of _a plus one, times two: 148
I have a class
class MyClass():
def __init__(self):
self.a = 7
self.b = 2
#property
def aAndB(self):
return self.a + self.b
I would like a function that iterates over all properties and returns only class instances having a certain property.
My goal is a function like this:
def findInstances(listOfInstances, instanceVariable, instanceValue):
#return all instances in listOfInstances where instanceVariable==instanceValue
Using instance.__dict__ only gives me a and b, but not aAndB. I would like to have a dict of all properties/methods with their values to loop over, so I can search for instances where a certain property (or method decorated with #property) has a certain value.
Currently, calling the function like this
findInstances(someListOfInstances, 'aAndB', '23')
makes Python complain that aAndB is not in instance.__dict__.
Maybe all of you are right and the answers are there, but I still don't get it. All the answers in the mentioned questions get lists, not dictionaries. I want all the properties (including methods with the #property decorator) and their values. Is there a way to iterate over the values of the keys in dir(myClass)? The dir command only contains the names of the attributes, not their values.
I need something like
for a in dir(myClass):
print a, myClass.(a) # get the value for an attribute stored in a variable
To be even more clear: The following achieves exactly what I want but there is probably a better way that I don't know.
for a in dir(myClass):
print a, eval("myClass.{}".format(a))
There's actually a very simple way to do this, using getattr in place of eval:
myClass = MyClass()
for a in dir(myClass):
if(a[:2] != "__"): #don't print double underscore methods
print a, getattr(myClass, a)
Output:
a 7
aAndB 9
b 2
This has the very big advantage of not needing to hard code in the name of your instance into the string, as is required using eval("myClass.{}".format(a))
Suppose you have two classes, A and B. Class B is defined inside the class A. I want to access the variables and methods of the outer class while inside the inner class. The code here is a toy example but has the essentials of what I want to demonstrate:
class A:
a = 'even'
b = 'odd'
class B:
def __init__(self, n):
if n%2 == 0: self.num = a
if n%2 == 1: self.num = b
self.description = A.desc()
def __getitem__(self, i):
return self.B(i)
def desc(self):
return a + '-' + b
>>> c = A()
>>> d = c[4]
>>> TypeError: unbound method desc() must be called with A instance as first argument (got nothing instead)
Here the method desc does some work on the variables of the class A and produces output. Class A is initialized correctly and you can access the variables a and b, even from the inner scope, given that you don't define the description variable. However, I cannot find a way to call the outer scope class methods desc. Is it possible to use the method desc in B without instantiating class A?
Explanation on why I use such a pattern:
Variables a and b in my program are rather big. I only need to initialize them once. In addition, I don't want these variables to float around in the program but to be only accessible to the inner class. Adding to all these is the fact that I can use the A.__getitem__ to extract 'slices' of the big data when needed. So the outer class provides me with hiding/encapsulation of the data, the indexing operator (through __getitem__) and all the routines required for extraction of slices of data (here the method desc. The inner class, B, provides the bundling of useful information from the big data for each index. This, most likely, is not the optimal design for achieving the described task. I am open and eager to hear your opinion regarding the alternative patterns.
I can't see any reason for you to be using classes here, let alone nested ones. In any case, there is almost never a reason to nest classes in Python, since inner classes don't get any special access to the outer class.
However if you want to allow anything to access a method without instantiating the object, you can make it a classmethod:
#classmethod
def desc(self):
return a + '-' + b
But I can't see why you would do any of this. Also, nothing here is a closure.