Need help on creating object with class - python

I need help on creating an object (a sequence of numbers) in respect to some parameters of a class. Lets say I typed in to the Python IDLE shell:
SuperLotto = make_lottery_set_type('SuperLotto', 6, (1,50))
#means user can create a 'SuperLotto' with 6 numbers in range of 1 to 50
It would make 'SuperLotto' as a new class instance of a class called 'LotteryGameType'.
This is using the code so far:
class LotterySetError(Exception):
pass
def make_lottery_set_type(name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
name = LotteryGameType(name, size, minmax[0], minmax[1])
return name
class LotteryGameType:
def __init__(self, name, set_size, min_set_number, max_set_number):
self.name = name
self.set_size = set_size
self.min_set_number = min_set_number
self.max_set_number = max_set_number
I want to be able to create a sequence of numbers and storing it for later use so I can use it with things like overload operators (e.g. eq and ne).
I want to be able to type into the Python IDLE shell:
SuperLotto([3, 4, 19, 23, 46, 27])
This would create an object under the parameters of SuperLotto, if not under parameters of 'SuperLotto' (say more than 6 numbers), it would raise an error. Any approach would be fine. Does anyone have any ideas on how to approach this?

It sounds like what you want is for make_lottery_set_type to return a new class, presumably one that's a subclass of LotteryGameType, rather than returning an instance of that type.
This is actually pretty easy to do in Python. Class definitions are just normal code, that you can run anywhere, even in the middle of a function. And they have access to the local environment while they're running. And classes themselves are "first-class values", meaning you can pass them around and return them from functions. So:
def make_lottery_set_type(name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
class NewLotteryGameType(LotteryGameType):
def __init__(self, numbers):
super().__init__(name, size, minmax[0], minmax[1])
self.numbers = numbers
return NewLotteryGameType
If you want to add other methods, that's the same as adding methods to any other class. For example:
def make_lottery_set_type(name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
class NewLotteryGameType(LotteryGameType):
def __init__(self, numbers):
super().__init__(name, size, minmax[0], minmax[1])
self.numbers = numbers
def __eq__(self, rhs):
return set(self.numbers) == set(rhs.numbers)
return NewLotteryGameType
So:
>>> SuperLotto = make_lottery_set_type('SuperLotto', 6, (1,50))
>>> super1 = SuperLotto([1,2,3,4,5,6])
>>> super2 = SuperLotto([6,5,4,3,2,1])
>>> super3 = SuperLotto([7,8,9,10,11,12])
>>> super1 == super2
True
>>> super1 == super3
False
(Obviously you can define __eq__ however you want, if set-equality isn't the right rule for your use.)
If you try to inspect the values you're generating, they don't look quite as pretty as you might like. For example, you'd probably rather see SuperLotto rather than NewLotteryGameType in places like this:
>>> super1
<__main__.NewLotteryGameType at 0x10259e490>
>>> SuperLotto.__name__
'NewLotteryGameType'
For that, just add NewLotteryGameType.__name__ = name. You might also want to copy over the docstring from the parent class, or various other things.
More generally, look at functools.update_wrapper (which is designed for wrapping up functions, not classes, but many of the details are the same) for inspiration, and the inspect module docs from your Python version for all of the attributes that classes can have.
In a comment, you ask:
The only problem is that I want NewLotteryGameType to inherit the parameters such as name, set_size, min_set_number, max_set_number from LotteryGameType. So lets say I wanted to type in NewLotteryGameType.set_size in to the Python Shell. I want it to return back to me 6.
That's contradictory. If you want to inherit the instance attributes of LotteryGameType… well, you already do. For example:
>>> super1.set_size
6
If you want them to be accessible off the class, then they can't be instance attributes, they have to be class attributes. And just changing set_size to a class attribute of LotteryGameType and inheriting it won't work, because the whole point of a class attribute is that the same value shared by all instances of the class or any of its subclasses, and the subclasses all need different values.
But you could do something like this:
class LotteryGameType:
def __init__(self, min_set_number, max_set_number):
self.min_set_number = min_set_number
self.max_set_number = max_set_number
def make_lottery_set_type(lottery_name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
class NewLotteryGameType(LotteryGameType):
name = lottery_name
set_size = size
def __init__(self, numbers):
super().__init__(minmax[0], minmax[1])
self.numbers = numbers
def __eq__(self, rhs):
return set(self.numbers) == set(rhs.numbers)
return NewLotteryGameType
(Notice that I had to rename the first make_ parameter to lottery_name so it was different from the class attribute name, because of the way scopes work.) Now, name and set_size are not instance attributes, nor are they class attributes of LotteryGameType—but they're class attributes of each NewLotteryGameType. So:
>>> SuperLotto = make_lottery_set_type('SuperLotto', 6, (1,50))
>>> SuperDuperLotto = make_lottery_set_type('SuperDuperLotto', 8, (1,100))
>>> SuperLotto.set_size
6
>>> SuperDuperLotto.set_size
8
What if you create instances of those types? Well, Python looks for attributes in the instance, then in the most-derived class, and then the base classes. So as long as you don't create instance attributes with the same name (notice that I removed the extra params, and the code that set instance attributes, from the LotteryGameType.__init__ method), it does just what you'd want:
>>> super1 = SuperLotto([1,2,3,4,5,6])
>>> super1.set_size
6
>>> duper1 = SuperDuperLotto([1,2,3,4,5,6,7,8])
>>> duper1.set_size
8
Of course this means that LotteryGameType is no longer a usable type on its own; only its subclasses are usable. But that's probably what you wanted anyway, right? You could even consider making it explicitly an abstract base class to make sure nobody accidentally tries to use a direct LotteryGameType instance.
If you're feeling brave, you might want to read up on metaclasses and see how you could adapt this whole design into use a LotteryGameMetaclass, so each new class is an instance of that metaclass instead of a subclass of the (abstract) base class. The source for the new enum module in 3.4, or the near-equivalent external flufl.enum package, might make good sample code. Then you can play with both and see how similar and how different they are.

Related

how to dynamically generate a subclass in a function?

I'm attempting to write a function that creates a new subclass named with the string it gets passed as an argument. I don't know what tools would be best for this, but I gave it a shot in the code below and only managed to make a subclass named "x", instead of "MySubClass" as intended. How can I write this function correctly?
class MySuperClass:
def __init__(self,attribute1):
self.attribute1 = attribute1
def makeNewClass(x):
class x(MySuperClass):
def __init__(self,attribute1,attribute2):
self.attribute2 = attribute2
x = "MySubClass"
makeNewClass(x)
myInstance = MySubClass(1,2)
The safest and easiest way to do this would be to use the type builtin function. This takes an optional second argument (tuple of base classes), and third argument (dict of functions). My recommendation would be the following:
def makeNewClass(x):
def init(self,attribute1,attribute2):
# make sure you call the base class constructor here
self.attribute2 = attribute2
# make a new type and return it
return type(x, (MySuperClass,), {'__init__': init})
x = "MySubClass"
MySubClass = makeNewClass(x)
You will need to populate the third argument's dict with everything you want the new class to have. It's very likely that you are generating classes and will want to push them back into a list, where the names won't actually matter. I don't know your use case though.
Alternatively you could access globals and put the new class into that instead. This is a really strangely dynamic way to generate classes, but is the best way I can think of to get exactly what you seem to want.
def makeNewClass(x):
def init(self,attribute1,attribute2):
# make sure you call the base class constructor here
self.attribute2 = attribute2
globals()[x] = type(x, (MySuperClass,), {'__init__': init})
Ryan's answer is complete, but I think it's worth noting that there is at least one other nefarious way to do this besides using built-in type and exec/eval or whatever:
class X:
attr1 = 'some attribute'
def __init__(self):
print 'within constructor'
def another_method(self):
print 'hey, im another method'
# black magics
X.__name__ = 'Y'
locals()['Y'] = X
del X
# using our class
y = locals()['Y']()
print y.attr1
y.another_method()
Note that I only used strings when creating class Y and when initializing an instance of Y, so this method is fully dynamic.

are user defined classes mutable

Say I want to create a class for car, tractor and boat. All these classes have an instance of engine and I want to keep track of all the engines in a single list. If I understand correctly if the motor object is mutable i can store it as an attribute of car and also the same instance in a list.
I cant track down any solid info on whether user defined classes are mutable and if there is a choice to choose when you define them, can anybody shed some light?
User classes are considered mutable. Python doesn't have (absolutely) private attributes, so you can always change a class by reaching into the internals.
For using your class as a key in a dict or storing them in a set, you can define a .__hash__() method and a .__eq__() method, making a promise that your class is immutable. You generally design your class API to not mutate the internal state after creation in such cases.
For example, if your engines are uniquely defined by their id, you can use that as the basis of your hash:
class Engine(object):
def __init__(self, id):
self.id = id
def __hash__(self):
return hash(self.id)
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.id == other.id
return NotImplemented
Now you can use instances of class Engine in sets:
>>> eng1 = Engine(1)
>>> eng2 = Engine(2)
>>> eng1 == eng2
False
>>> eng1 == eng1
True
>>> eng1 == Engine(1)
True
>>> engines = set([eng1, eng2])
>>> engines
set([<__main__.Engine object at 0x105ebef10>, <__main__.Engine object at 0x105ebef90>])
>>> engines.add(Engine(1))
>>> engines
set([<__main__.Engine object at 0x105ebef10>, <__main__.Engine object at 0x105ebef90>])
In the above sample I add another Engine(1) instance to the set, but it is recognized as already present and the set didn't change.
Note that as far as lists are concerned, the .__eq__() implementation is the important one; lists don't care if an object is mutable or not, but with the .__eq__() method in place you can test if a given engine is already in a list:
>>> Engine(1) in [eng1, eng2]
True
All objects (with the exception of a few in the standard library, some that implement special access mechanisms using things like descriptors and decorators, or some implemented in C) are mutable. This includes instances of user defined classes, classes themselves, and even the type objects that define the classes. You can even mutate a class object at runtime and have the modifications manifest in instances of the class created before the modification. By and large, things are only immutable by convention in Python if you dig deep enough.
I think you're confusing mutability with how python keeps references -- Consider:
class Foo(object):
pass
t = (1,2,Foo()) # t is a tuple, :. t is immutable
b = a[2] # b is an instance of Foo
b.foo = "Hello" # b is mutable. (I just changed it)
print (hash(b)) # b is hashable -- although the default hash isn't very useful
d = {b : 3} # since b is hashable, it can be used as a key in a dictionary (or set).
c = t # even though t is immutable, we can create multiple references to it.
a = [t] # here we add another reference to t in a list.
Now to your question about getting/storing a list of engines globally -- There are a few different ways to do this, here's one:
class Engine(object):
def __init__(self, make, model):
self.make = make
self.model = model
class EngineFactory(object):
def __init__(self,**kwargs):
self._engines = kwargs
def all_engines(self):
return self._engines.values()
def __call__(self,make, model):
""" Return the same object every for each make,model combination requested """
if (make,model) in _engines:
return self._engines[(make,model)]
else:
a = self._engines[(make,model)] = Engine(make,model)
return a
engine_factory = EngineFactory()
engine1 = engine_factory('cool_engine',1.0)
engine2 = engine_factory('cool_engine',1.0)
engine1 is engine2 #True !!! They're the same engine. Changing engine1 changes engine2
The example above could be improved a little bit by having the EngineFactory._engines dict store weakref.ref objects instead of actually storing real references to the objects. In that case, you'd check to make sure the reference is still alive (hasn't been garbage collected) before you return a new reference to the object.
EDIT: This is conceptually wrong, The immutable object in python can shed some light as to why.
class Engine():
def __init__(self, sn):
self.sn = sn
a = Engine(42)
b = a
print (a is b)
prints True.

python: immutable private class variables?

Is there any way to translate this Java code into Python?
class Foo
{
final static private List<Thingy> thingies =
ImmutableList.of(thing1, thing2, thing3);
}
e.g. thingies is an immutable private list of Thingy objects that belongs to the Foo class rather than its instance.
I know how to define static class variables from this question Static class variables in Python but I don't know how to make them immutable and private.
In Python the convention is to use a _ prefix on attribute names to mean protected and a __ prefix to mean private. This isn't enforced by the language; programmers are expected to know not to write code that relies on data that isn't public.
If you really wanted to enforce immutability, you could use a metaclass[docs] (the class of a class). Just modify __setattr__ and __delattr__ to raise exceptions when someone attempts to modify it, and make it a tuple (an immutable list) [docs].
class FooMeta(type):
"""A type whose .thingies attribute can't be modified."""
def __setattr__(cls, name, value):
if name == "thingies":
raise AttributeError("Cannot modify .thingies")
else:
return type.__setattr__(cls, name, value)
def __delattr__(cls, name):
if name == "thingies":
raise AttributeError("Cannot delete .thingies")
else:
return type.__delattr__(cls, name)
thing1, thing2, thing3 = range(3)
class Foo(object):
__metaclass__ = FooMeta
thingies = (thing1, thing2, thing3)
other = [1, 2, 3]
Examples
print Foo.thingies # prints "(0, 1, 2)"
Foo.thingies = (1, 2) # raises an AttributeError
del Foo.thingies # raise an AttributeError
Foo.other = Foo.other + [4] # no exception
print Foo.other # prints "[1, 2, 3, 4]"
It would still technically be possible to modify these by going through the class's internal .__dict__ of attributes, but this should be enough to deter most users, it's very difficult to entirely secure Python objects.
You can't do either of those things in Python, not in the sense you do them in Java, anyway.
By convention, names prefixed with an underscore are considered private and should not be accessed outside the implementation, but nothing in Python enforces this convention. It's considered more of a warning that you're messing with an implementation detail that may change without warning in a future version of the code.
You can make it un-writeable (subtly different from immutable) by using properties, but there is no way to make it private -- that goes against Python's philosophy.
class Foo(object): # don't need 'object' in Python 3
#property
def thingies(self):
return 'thing1', 'thing2', 'thing3'
f = Foo()
print f.thingies
#('thing1', 'thing2', 'thing3')
f.thingies = 9
#Traceback (most recent call last):
# File "test.py", line 8, in <module>
# f.thingies = 9
#AttributeError: can't set attribute
Whether it's immutable or not depends on what you return; if you return a mutable object you may be able to mutate that and have those changes show up in the instance/class.
class FooMutable(object):
_thingies = [1, 2, 3]
#property
def thingies(self):
return self._thingies
foo = FooMutable()
foo.thingies.append(4)
print foo.thingies
# [1, 2, 3, 4]
This will let you mutate thingies, and because the object returned is the same object kept in the instance/class the changes will be reflected on subsequent access.
Compare that with:
class FooMutable(object):
#property
def thingies(self):
return [1, 2, 3]
foo = FooMutable()
foo.thingies.append(4)
print foo.thingies
# [1, 2, 3]
Because a brand new list is returned each time, changes to it are not reflected in subsequent accesses.
You want to look into the property() function. It allows you to define your own custom Getter and Setter for a member attribute of a class. It might look something like this:
class myClass(object):
_x = "Hard Coded Value"
def set_x(self, val): return
def get_x(self): return self._x
def del_x(self): return
x = property(get_x, set_x, del_x, "I'm an immutable property named 'x'")
I haven't used it enough to be certain whether it can be used to create something "private" so you'd have to delve into that yourself, but isinstance may help.
You can achieve the final part using type hints*. As others have said, __ achieves the private aspect well enough, so
from typing import List
from typing_extensions import Final
class Foo:
__thingies: Final[List[Thingy]] = ImmutableList.of(thing1, thing2, thing3)
I'll leave the definition of ImmutableList to you. A tuple will probably do.
*with the usual caveat that users can ignore them

How to dynamically compose and access class attributes in Python? [duplicate]

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>

Difference between defining a member in __init__ to defining it in the class body in python?

What is the difference between doing
class a:
def __init__(self):
self.val=1
to doing
class a:
val=1
def __init__(self):
pass
class a:
def __init__(self):
self.val=1
this creates a class (in Py2, a cruddy, legacy, old-style, don't do that! class; in Py3, the nasty old legacy classes have finally gone away so this would be a class of the one and only kind -- the **good* kind, which requires class a(object): in Py2) such that each instance starts out with its own reference to the integer object 1.
class a:
val=1
def __init__(self):
pass
this creates a class (of the same kind) which itself has a reference to the integer object 1 (its instances start out with no per-instance reference).
For immutables like int values, it's hard to see a practical difference. For example, in either case, if you later do self.val = 2 on one instance of a, this will make an instance reference (the existing answer is badly wrong in this respect).
The distinction is important for mutable objects, because they have mutator methods, so it's pretty crucial to know if a certain list is unique per-instance or shared among all instances. But for immutable objects, since you can never change the object itself but only assign (e.g. to self.val, which will always make a per-instance reference), it's pretty minor.
Just about the only relevant difference for immutables: if you later assign a.val = 3, in the first case this will affect what's seen as self.val by each instance (except for instances that had their own self.val assigned to, or equivalent actions); in the second case, it will not affect what's seen as self.val by any instance (except for instances for which you had performed del self.val or equivalent actions).
Others have explained the technical differences. I'll try to explain why you might want to use class variables.
If you're only instantiating the class once, then class variables effectively are instance variables. However, if you're making many copies, or want to share state among a few instances, then class variables are very handy. For example:
class Foo(object):
def __init__(self):
self.bar = expensivefunction()
myobjs = [Foo() for _ in range(1000000)]
will cause expensivefunction() to be called a million times. If it's going to return the same value each time, say fetching a configuration parameter from a database, then you should consider moving it into the class definition so that it's only called once and then shared across all instances.
I also use class variables a lot when memoizing results. Example:
class Foo(object):
bazcache = {}
#classmethod
def baz(cls, key):
try:
result = cls.bazcache[key]
except KeyError:
result = expensivefunction(key)
cls.bazcache[key] = result
return result
In this case, baz is a class method; its result doesn't depend on any instance variables. That means we can keep one copy of the results cache in the class variable, so that 1) you don't store the same results multiple times, and 2) each instance can benefit from results that were cached from other instances.
To illustrate, suppose that you have a million instances, each operating on the results of a Google search. You'd probably much prefer that all those objects share those results than to have each one execute the search and wait for the answer.
So I'd disagree with Lennart here. Class variables are very convenient in certain cases. When they're the right tool for the job, don't hesitate to use them.
As mentioned by others, in one case it's an attribute on the class on the other an attribute on the instance. Does this matter? Yes, in one case it does. As Alex said, if the value is mutable. The best explanation is code, so I'll add some code to show it (that's all this answer does, really):
First a class defining two instance attributes.
>>> class A(object):
... def __init__(self):
... self.number = 45
... self.letters = ['a', 'b', 'c']
...
And then a class defining two class attributes.
>>> class B(object):
... number = 45
... letters = ['a', 'b', 'c']
...
Now we use them:
>>> a1 = A()
>>> a2 = A()
>>> a2.number = 15
>>> a2.letters.append('z')
And all is well:
>>> a1.number
45
>>> a1.letters
['a', 'b', 'c']
Now use the class attribute variation:
>>> b1 = B()
>>> b2 = B()
>>> b2.number = 15
>>> b2.letters.append('z')
And all is...well...
>>> b1.number
45
>>> b1.letters
['a', 'b', 'c', 'z']
Yeah, notice that when you changed, the mutable class attribute it changed for all classes. That's usually not what you want.
If you are using the ZODB, you use a lot of class attributes because it's a handy way of upgrading existing objects with new attributes, or adding information on a class level that doesn't get persisted. Otherwise you can pretty much ignore them.

Categories