Aliasing python variables without dict - python

I'm just implementing a class that requires an attribute to store a reference of another attribute as a cursor. See the following:
class foo:
def __init__(self):
self.egg=[4,3,2,1,[4,3,2,1]]
self.spam=#some reference or pointer analog represent self.egg[4][2], for example
def process(self):
# do something on self.egg[self.spam]
pass
I don't want a dict because self.spam should only represent one item, and using a dict I would have to consume indefinite unnecessary memory. Is there some pythonic way to implement self.spam above?

You could store the indices in self.spam, and use a property to access the value from self.egg given the current value of self.spam:
class Foo(object):
def __init__(self):
self.egg = [4,3,2,1,[4,3,2,1]]
self.spam = (4,2)
def process(self):
# do something on self.egg[self.spam]
print(self.eggspam)
pass
#property
def eggspam(self):
result = self.egg
for item in self.spam:
result = result[item]
return result
f = Foo()
f.process()
# 2
f.spam = (1,)
f.process()
# 3

Related

How to print out a list used as a class attribute or instance attribute

I've been playing with this for a little while now and can't see to figure it out. I have a simple class and want to use a list as either a shared class attribute or even just a instance attribute. Obviously, at some point it would be nice to see what is in this list, but all I can get to return is the object info (<__main__.Testclass instance at 0x7ff2a18c>). I know that I need to override the __repr__ or __str__ methods, but I'm definitely not doing it correctly.
class TestClass():
someList = []
def __init__(self):
self.someOtherList = []
def addToList(self, data):
self.someOtherList.append(data)
TestClass.someList.append(data)
def __repr__(self):
#maybe a loop here? I've tried returning list comprehensions and everything.
pass
test = TestClass()
test.addToList(1)
test.addToList(2)
test.addToList(3)
print(test.someList)
print(test.someOtherList)
I just want to see either [1,2,3] or 1 2 3 (hopefully choose either one).
With test.someList and test.someOtherList, you can already see what is inside those lists...
If you want to see those lists when printing the test object, you can either implement __str__ or __repr__ and delegate the representation of the instance to one of those. (either someList or someOtherList)
def __repr__(self):
return str(self.someOtherList)
Now whenever you print your test object, it shows the representation of self.someOtherList.
class TestClass:
someList = []
def __init__(self):
self.someOtherList = []
def addToList(self, data):
self.someOtherList.append(data)
TestClass.someList.append(data)
def __repr__(self):
return str(self.someOtherList)
test = TestClass()
test.addToList(1)
test.addToList(2)
test.addToList(3)
print(test)
output
[1, 2, 3]

Is it possible to monitor a list (or mutable sequence) for when a member of the list is modified?

Say I have a very simple data type:
class SimpleObject:
def __init__(self, property):
self.property = property
def update_property(self, value):
self.property = value
And I a special kind of list to store the data type:
class SimpleList(collections.MutableSequence):
def update_useful_property_of_list(self, value):
self.useful_property_of_list = value
And I store them:
simple1 = SimpleObject(1)
simple2 = SimpleObject(2)
simple_list = SimpleList([simple1, simple2])
Is there any way for the SimpleList object to know when one of the properties of its members changes? For example, how can I get simple_list to execute self.update_useful_property_of_list() when something like this happens:
simple1.update_property(3)
As noted in the comments, you are looking for the Observer design pattern. Simplest, way to do it in your example:
class SimpleObject:
def __init__(self, property, propertyChangeObserver = None):
self.property = property
self.propertyChangeObserver = propertyChangeObserver
def registerPropertyChangeObserver(self, propertyChangeObserver):
self.propertyChangeObserver = propertyChangeObserver
def update_property(self, value):
self.property = value
if self.propertyChangeObserver:
self.propertyChangeObserver.simpleObjectPropertyChanged(self)
and:
class SimpleList(collections.MutableSequence):
def __init__(self, collection):
super(SimpleList, self).__init__(collection)
for e in collection:
e.registerPropertyChangeObserver(self)
def simpleObjectPropertyChanged(self, simpleObject):
pass # react to simpleObject.property being changed
Because you've called your property "property" it's hard to demonstrate low coupling here :) I've called the method simpleObjectPropertyChanged for clarity, but in fact, SimpleList doesn't have to know that it stores SimpleObject instances - it only needs to know that they are observable instances. In a similar manner, SimpleObject doesn't know about SimpleList - it only knows about some class that needs to observe its state (an observer - hence the name of the pattern).

Python referencing instance list variable

I just started to learn Python and I"m struggling a little with instance variables. So I create an instance variable in a method that's of a list type. Later on, I want to call and display that variable's contents. However, I'm having issues doing that. I read some online, but I still can't get it to work. I was thinking of something along the following (this is a simplified version):
What would the proper way of doing this be?
class A:
def _init_(self):
self.listVar = [B("1","2","3"), B("1","2","3")]
def setListVal():
#Is this needed? Likewise a "get" method"?
def randomMethod():
A.listVar[0] #something like that to call/display it right? Or would a for
#for loop style command be needed?
Class B:
def _init_(self):
self.a = ""
self.b = ""
self.c = ""
Is the list something you'll be passing to the instance when you create it (i.e. will it be different each time)?
If so, try this:
class A:
def __init__(self, list):
self.listVar = list
Now, when you instantiate (read: create an instance) of a class, you can pass a list to it and it will be saved as the listVar attribute for that instance.
Example:
>>> first_list = [B("1","2","3"), B("1","2","3")]
>>> second_list = [C("1","2","3"), C("1","2","3")]
>>> first_instance = A(first_list) # Create your first instance and pass it your first_list. Assign it to variable first_instance
>>> first_instance.listVar # Ask for the listVar attribute of your first_instance
[B("1","2","3"), B("1","2","3")] # Receive the list you passed
>>> second_instance = A(second_list) # Create your second instance and pass it your second_list. Assign it to variable second_instance
>>> second_instance.listVar # Ask for the listVar attribute of your second_instance
[C("1","2","3"), C("1","2","3")] # Receive the list you passed second instance
Feel free to ask if anything is not clear.
class A:
def __init__(self):
self.listVar = [B("1","2","3"), B("1","2","3")]
def setListVal(self, val):
self.listVar[0] = val # example of changing the first entry
def randomMethod(self):
print self.listVar[0].a # prints 'a' from the first entry in the list
class B:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
I made several changes. You need to use self as the first argument to all the methods. That argument is the way that you reference all the instance variables. The initialization function is __init__ note that is 2 underscores before and after. You are passing three arguments to initialize B, so you need to have 3 arguments in addition to self.

Can I iterate over a class in Python?

I have a class that keeps track of its instances in a class variable, something like this:
class Foo:
by_id = {}
def __init__(self, id):
self.id = id
self.by_id[id] = self
What I'd like to be able to do is iterate over the existing instances of the class. I can do this with:
for foo in Foo.by_id.values():
foo.do_something()
but it would look neater like this:
for foo in Foo:
foo.do_something()
is this possible? I tried defining a classmethod __iter__, but that didn't work.
If you want to iterate over the class, you have to define a metaclass which supports iteration.
x.py:
class it(type):
def __iter__(self):
# Wanna iterate over a class? Then ask that class for iterator.
return self.classiter()
class Foo:
__metaclass__ = it # We need that meta class...
by_id = {} # Store the stuff here...
def __init__(self, id): # new isntance of class
self.id = id # do we need that?
self.by_id[id] = self # register istance
#classmethod
def classiter(cls): # iterate over class by giving all instances which have been instantiated
return iter(cls.by_id.values())
if __name__ == '__main__':
a = Foo(123)
print list(Foo)
del a
print list(Foo)
As you can see in the end, deleting an instance will not have any effect on the object itself, because it stays in the by_id dict. You can cope with that using weakrefs when you
import weakref
and then do
by_id = weakref.WeakValueDictionary()
. This way the values will only kept as long as there is a "strong" reference keeping it, such as a in this case. After del a, there are only weak references pointing to the object, so they can be gc'ed.
Due to the warning concerning WeakValueDictionary()s, I suggest to use the following:
[...]
self.by_id[id] = weakref.ref(self)
[...]
#classmethod
def classiter(cls):
# return all class instances which are still alive according to their weakref pointing to them
return (i for i in (i() for i in cls.by_id.values()) if i is not None)
Looks a bit complicated, but makes sure that you get the objects and not a weakref object.
Magic methods are always looked up on the class, so adding __iter__ to the class won't make it iterable. However the class is an instance of its metaclass, so the metaclass is the correct place to define the __iter__ method.
class FooMeta(type):
def __iter__(self):
return self.by_id.iteritems()
class Foo:
__metaclass__ = FooMeta
...
Try this:
You can create a list with a global scope, define a list in the main module as follows:
fooList = []
Then add:
class Foo:
def __init__(self):
fooList.append(self)
to the init of the foo class
Then everytime you create an instance of the Foo class it will be added to the fooList list.
Now all you have to do is iterate through the array of objects like this
for f in fooList:
f.doSomething()
You can create a comprehension list and then call member methods as follows:
class PeopleManager:
def __init__(self):
self.People = []
def Add(self, person):
self.People.append(person)
class Person:
def __init__(self,name,age):
self.Name = name
self.Age = age
m = PeopleManager()
[[t.Name,t.Age] for t in m.People]
call to fill the object list:
m = PeopleManager()
m.Add( Person("Andy",38))
m.Add( Person("Brian",76))
You can create a class list and then call append in the init method as follows:
class Planet:
planets_list = []
def __init__(self, name):
self.name = name
self.planets_list.append(self)
Usage:
p1 = Planet("earth")
p2 = Planet("uranus")
for i in Planet.planets_list:
print(i.name)

Most elegant way to configure a class in Python?

I'm simulating a distributed system in which all nodes follow some protocol. This includes assessing some small variations in the protocol. A variation means alternative implementation of a single method. All nodes always follow the same variation, which is determined by experiment configuration (only one configuration is active at any given time). What is the clearest way to do it, without sacrificing performance?
As an experiment can be quite extensive, I clearly don't want any conditionals. Before I've just used inheritance, like:
class Node(object):
def dumb_method(self, argument):
# ...
def slow_method(self, argument):
# ...
# A lot more methods
class SmarterNode(Node):
def dumb_method(self, argument):
# A somewhat smarter variant ...
class FasterNode(SmarterNode):
def slow_method(self, argument):
# A faster variant ...
But now I need to test all possible variants and don't want an exponential number of classes cluttering the source. I also want other people peeping at the code to understand it with minimal effort. What are your suggestions?
Edit: One thing I failed to emphasize enough: for all envisioned use cases, it seems that patching the class upon configuration is good. I mean: it can be made to work by simple Node.dumb_method = smart_method. But somehow it didn't feel right. Would this kind of solution cause major headache to a random smart reader?
You can create new subtypes with the type function. You just have to give it the subclasses namespace as a dict.
# these are supposed to overwrite methods
def foo(self):
return "foo"
def bar(self):
return "bar"
def variants(base, methods):
"""
given a base class and list of dicts like [{ foo = <function foo> }]
returns types T(base) where foo was overwritten
"""
for d in methods:
yield type('NodeVariant', (base,), d)
from itertools import combinations
def subdicts(**fulldict):
""" returns all dicts that are subsets of `fulldict` """
items = fulldict.items()
for i in range(len(items)+1):
for subset in combinations(items, i):
yield dict(subset)
# a list of method variants
combos = subdicts(slow_method=foo, dumb_method=bar)
# base class
class Node(object):
def dumb_method(self):
return "dumb"
def slow_method(self):
return "slow"
# use the base and our variants to make a number of types
types = variants(Node, combos)
# instantiate each type and call boths methods on it for demonstration
print [(var.dumb_method(), var.slow_method()) for var
in (cls() for cls in types)]
# [('dumb', 'slow'), ('dumb', 'foo'), ('bar', 'slow'), ('bar', 'foo')]
You could use the __slots__ mechanism and a factory class. You would need to instantiate a NodeFactory for each experiment, but it would handle creating Node instances for you from there on. Example:
class Node(object):
__slots__ = ["slow","dumb"]
class NodeFactory(object):
def __init__(self, slow_method, dumb_method):
self.slow = slow_method
self.dumb = dumb_method
def makenode(self):
n = Node()
n.dumb = self.dumb
n.slow = self.slow
return n
an example run:
>>> def foo():
... print "foo"
...
>>> def bar():
... print "bar"
...
>>> nf = NodeFactory(foo, bar)
>>> n = nf.makenode()
>>> n.dumb()
bar
>>> n.slow()
foo
I'm not sure if you're trying to do something akin to this (allows swap-out runtime "inheritance"):
class Node(object):
__methnames = ('method','method1')
def __init__(self, type):
for i in self.__methnames:
setattr(self, i, getattr(self, i+"_"+type))
def dumb_method(self, argument):
# ...
def slow_method(self, argument):
# ...
n = Node('dumb')
n.method() # calls dumb_method
n = Node('slow')
n.method() # calls slow_method
Or if you're looking for something like this (allows running (and therefore testing) of all methods of the class):
class Node(object):
#do something
class NodeTest(Node):
def run_tests(self, ending = ''):
for i in dir(self):
if(i.endswith(ending)):
meth = getattr(self, i)
if(callable(meth)):
meth() #needs some default args.
# or yield meth if you can
You can use a metaclass for this.
If will let you create a class on the fly with method names according to every variations.
Should the method to be called be decided when the class is instantiated or after? Assuming it is when the class is instantiated, how about the following:
class Node():
def Fast(self):
print "Fast"
def Slow(self):
print "Slow"
class NodeFactory():
def __init__(self, method):
self.method = method
def SetMethod(self, method):
self.method = method
def New(self):
n = Node()
n.Run = getattr(n, self.method)
return n
nf = NodeFactory("Fast")
nf.New().Run()
# Prints "Fast"
nf.SetMethod("Slow")
nf.New().Run()
# Prints "Slow"

Categories

Resources