Let's say I want to implement some list class in python with extra structure, like a new constructor. I wrote:
import random
class Lis(list):
def __init__(self, n):
self = []
for i in range(n):
self.append(random.randint(0, 30))
Now doing Lis(3) gives me an empty list. I don't know where I did it wrong.
You are overriding the object with self = []
try the following
import random
class Lis(list):
def __init__(self, n):
for i in range(n):
self.append(random.randint(0, 30))
if you want to return a list from object call
class MyClass(object):
def __init__(self):
print "never called in this case"
def __new__(cls):
return [1,2,3]
obj = MyClass()
print(obj)
How to return a value from __init__ in Python?
or if you want an modified object try:
class MyClass:
def __getitem__(self, key):
not_self = []
for i in range(n):
not_self.append(random.randint(0, 30))
return not_self
myobj = MyClass()
myobj[3] #Output: 6
How to override the [] operator in Python?
I am not sure if using self like you did is healthy.
Related
Hy,
I have a small class with only one attribute, which is a list with four elements. I want to make attributes for each object of the list with the help of property, but I don't want to write a setter and a getter method for each element. Currently I implemented it in the following way.
class MyClass:
def __init__(self):
self.my_list = [None in range(4)]
def __get_my_list_x(self, x):
return self.my_list[x]
def __set_my_list_x(self, val, x):
self.my_list[x] = val
def get_my_list_0(self):
return self.__get_my_list_x(x=0)
def set_my_list_0(self, val):
self.__set_my_list_x(val, x=0)
# continue getter and setter methods for position 1, 2 and 3
# of my list
my_list_0 = property(get_my_list_0, set_my_list_0)
my_list_1 = property(get_my_list_1, set_my_list_1)
my_list_2 = property(get_my_list_2, set_my_list_2)
my_list_3 = property(get_my_list_3, set_my_list_3)
At the moment I'm violating the Don't repeat yourself principle, because I have to write the getter and setter methods for my_list_0 to my_list_3. Is there a way to directly call the methods __get_my_list_x and __set_my_list_x in property() and specify the x argument?
I hope you guys get my question.
Have a nice day.
There are a lot of different solutions possible depending on your exact situation outside of this probably oversimplified example.
The best solution if you need to use actual attributes is probably to define your own custom descriptors (e.g. what property does under the hood):
class MyListIndexer:
def __init__(self, index):
self.index = index
def __get__(self, instance, owner):
return instance.my_list[self.index]
def __set__(self, instance, value):
instance.my_list[self.index] = value
class MyClass:
def __init__(self):
self.my_list = [None for _ in range(4)]
my_list_0 = MyListIndexer(0)
my_list_1 = MyListIndexer(1)
You can also add another parameter to MyListIndexer specifying the name of the attribute with help of getattr.
However, consider not using attributes at all and instead providing something like direct item access with __getitem__/__setitem__:
class MyClass:
def __init__(self):
self.my_list = [None for _ in range(4)]
def __setitem__(self, key, value):
self.my_list[key] = value
def __getitem__(self, item):
return self.my_list[item]
The extreme general solution that might have unexpected consequences and should only be used if there is no other solution is to use the __getattr__/__setattr__ functions:
class MyClass:
def __init__(self):
self.my_list = [None for _ in range(4)]
def __getattr__(self, item):
if item.startswith("my_list_"):
val = int(item[8:])
return self.my_list[val]
else:
return super(MyClass, self).__getattr__(item)
def __setattr__(self, key, value):
if key.startswith("my_list_"):
ind = int(key[8:])
self.my_list[ind] = value
else:
super(MyClass, self).__setattr__(key, value)
I'm trying to create a Proxy class to another class. I want this class to be passed into the proxy in its constructor and then for the proxy to dynamically create all the same methods of this class on itself.
This is what I hvae so far which is not working:
import inspect
from optparse import OptionParser
class MyClass:
def func1(self):
print 'MyClass.func1'
def func2(self):
print 'MyClass.func1'
class ProxyClass:
def __init__(self):
myClass = MyClass()
members = inspect.getmembers(MyClass, predicate=inspect.ismethod)
for member in members:
funcName = member[0]
def fn(self):
print 'ProxyClass.' + funcName
return myClass[funcName]()
self.__dict__[funcName] = fn
proxyClass = ProxyClass()
proxyClass.func1()
proxyClass.func2()
I think it is the line self.__dict__[funcName] = fn that needs to be changed but am not sure what to?
I'm new to Python so if there is a completely different Pythonic way of doing this I would be happy to hear about that too.
I would not explicitly copy the methods of the wrapped class. You can use the magic method __getattr__ to control what happens when you call something on the proxy object, including decorating it as you like; __getattr__ has to return a callable object, so you can make that callable do whatever you need to (in addition to calling the original method).
I have included an example below.
class A:
def foo(self): return 42
def bar(self, n): return n + 5
def baz(self, m, n): return m ** n
class Proxy:
def __init__(self, proxied_object):
self.__proxied = proxied_object
def __getattr__(self, attr):
def wrapped_method(*args, **kwargs):
print("The method {} is executing.".format(attr))
result = getattr(self.__proxied, attr)(*args, **kwargs)
print("The result was {}.".format(result))
return result
return wrapped_method
proxy = Proxy(A())
proxy.foo()
proxy.bar(10)
proxy.baz(2, 10)
I'm working on a small personal project where I created many classes. Each class has its own register containing all its instances:
class IterReg(type):
# Register of all objects for iteration
def __iter__(cls):
return iter(cls._reg.values())
The "template" which I use for each class is
class Point(object):
# Point object
__metaclass__ = IterReg
_reg = dict()
counter = 0
# Initialize
def __init__(self, name):
self.name = name
self._reg[self.name] = self
Point.counter += 1
# Return register keys
#staticmethod
def get_reg_keys(cls):
return cls._reg.keys()
And some other (not important for a MWE) stuff.
If I initialize, e.g., a = Point("Point A"), I can then call:
>>> a.get_reg_keys()
['Point A']
which is (obviously) the same result that I get from
Point.get_reg_keys()
Now my question: is there a way to define this method once for all classes (i.e. somehow in the metaclass).
I first thought something like this had worked:
class IterReg(type):
# Register of all objects for iteration
def __iter__(cls):
return iter(cls._reg.values())
def get_reg_keys(cls):
return cls._reg.keys()
But then I can just call get_reg_keys() from the class (i.e. Point.get_reg_keys()) and not from any instance of it.
You can define a generic class that has .get_reg_keys() and subclass it when you want to use that method. In the below example, any class that inherits from Generic will have the .get_reg_keys() method.
class IterReg(type):
# Register of all objects for iteration
def __iter__(cls):
return iter(cls._reg.values())
class Generic(object):
#classmethod
def get_reg_keys(cls):
return cls._reg.keys()
class Point(Generic):
# Point object
__metaclass__ = IterReg
_reg = dict()
counter = 0
# Initialize
def __init__(self, name):
self.name = name
self._reg[self.name] = self
Point.counter += 1
a = Point('Point A')
a.get_reg_keys()
# returns:
['Point A']
I have a class with certain attributes.
I would like to define a method which sets other attributes based on the ones that have already been set. Something like this:
class Test:
def __init__(self, name):
self.name = name
self.list = []
max = None
def get_max(self)
self.max = max(list)
This doesn't work. I have a feeling I am doing something very wrong but I can't work out what. Please someone put me out of my misery.
Updated code gives me an Attribute error:
class Test:
def __init__(self, name):
self.name = name
self.lst = []
self.mx = None
def get_max(self)
self.mx = max(self.lst)
When I call the method, no exceptions are returned, but the self.mx attribute are not updated.
>>>t = Test('testname')
>>>t.lst = [1,2,3]
>>>t.get_max
>>>t.name
'testname'
>>>t.lst
[1,2,3]
>>>t.mx
AttributeError: Test instance has no attribute 'mx'
It would be self.list to refer to the attribute, list is referring to the python builtin list.
You would need to do something like:
class Test:
def __init__(self, name,lst):
self.name = name
self.lst = lst
self.mx = None # use self to create an attribute
def get_max(self):
self.mx = max(self.lst)
You can also simply just call max on the list whenever you want to get the max, you don't need to create an attribute and method simply to return or get the max of the list.
You should simply return the max of the list in the method if you really wanted to use a method to get the max:
class Test:
def __init__(self, name, lst):
self.name = name
self.lst = lst
def get_max(self):
return max(self.lst)
t = Test("foo", [1,2,3,4])
print(t.get_max())
4
The design of your class really depends on what exactly you want to do in it but you don't getters or setters in python.
If you want to do something based on the max element in the list you don't need an attribute:
class Test:
def __init__(self, name,lst):
self.name = name
self.lst = lst
def some_meth(self):
if max(self.lst) > 2:
# do something
I have a class A that can be generated from two different ways.
a = A(path_to_xml_file)
a = A(listA, listB)
The first method has file path as an input to parse from XML file to get listA, and listB. The second method is given two lists.
I can think of two ways to implement multiple constructor. What do you think? What method normally Python guys use for this case?
Check the type
class A():
def __init__(self, arg1, arg2 = None):
if isinstance(arg1, str):
...
elif isinstance(arg1, list):
...
a = A("abc")
b = A([1,2,3],[4,5,6])
Make different builders
class A2():
def __init__(self):
pass
def genFromPath(self, path):
...
def genFromList(self, list1, list2):
...
a = A2()
a.genFromPath("abc")
b = A2()
b.genFromList([1,2,3],[4,5,6])
Make the constructor take the two lists. Write a factory classmethod that parses the XML and returns the object.
Use classmethod for second one
class A(object):
#classmethod
def from_string(cls, string):
# ...
#classmethod
def from_lists(cls, list1, list2):
# ...
Use module's functions
def from_string(string):
# ...
def from_lists(list1, list2):
# ...
class A(object):
pass
Since the number of arguments passed to the initializer is different in each case, you can avoid type-checking by using the extended call syntax:
class A(object):
def __init__(self, *args):
if len(args) == 1:
path = args[0]
...
elif len(args) == 2:
list1 = args[0]
list2 = args[1]
...
else:
raise SomeException()
Looking at the problem more closely, I'd suggest having the class take two lists, and include a helper function in the module:
class A(object):
def __init__(self, list1, list2):
# Init from lists here
pass
def create_A_from_path(path):
list1, list2 = parse_xml_into_lists(path)
return A(list1, list2)
class A(object):
#staticmethod
def from_string(str):
obj =A()
obj.str = str
return obj
#staticmethod
def from_list(lis):
obj = A()
obj.lis = lis
return obj
>>>
(obj1, obj2) = A.from_string('hello'), A.from_list(['one', 'two'])