How to tell a class method which variable should be processed - python

sorry for the noob question. Lets say i have a class which holds 3 lists and a method to combine one of the lists to a string. How can i tell the method which list it should take ? or should i move the method out of the class into a function ?
Here is what i mean:
class images():
def __init__(self, lista, listb, listc):
self.lista=lista
self.listb=listb
self.listc=listc
def makelist(self):
items = ""
for item in self.whateverListIWant:
items=items+item
return items
test=images([1,2,3],["b"],["c"])
print (test.makelist(WhichListIWant))

You can do this
class images():
def __init__(self, lista, listb, listc):
self.lista=lista
self.listb=listb
self.listc=listc
def makelist(self, param):
items = ""
for item in param:
items= items + str(item)
return items
test=images([1,2,3],["b"],["c"])
print (test.makelist(test.lista))

Be aware that "class method" (indicated by the decorator #classmethod) is not what you have in your example. Yours is a standard object method that acts on the object you create, as highlighted by your use of "self" as the first parameter.
The object method acts on the object, and can refer to the data contained within self. A "class method" would act only on a class, and only use parameters available to that class.
Use of a class method would be something like this:
class ClassyImages():
lista = []
listb = []
listc = []
#classmethod
def makelist(cls, which):
if which == 'a':
the_list = cls.lista
elif which == 'b':
the_list = cls.listb
elif which == 'c':
the_list = cls.listc
else:
raise ValueError("Invalid value " + str(which))
return the_list[:] # returns a soft copy of the list
And you would use it as follows:
ClassyImages.lista.extend([1,2,3])
ClassyImages.listb.add("b")
ClassyImages.listc.add("c")
print(ClassyImages.makelist("a"))
See the difference? In your example, you're using methods on the instance of an object, which you create. In this case, we're only using class-level variables, and never using an instance of an object.
However, the nice feature of the #classmethod decorator, is you still can use the class method on an object. So you can also do this:
my_classy_object_1 = ClassyImages()
my_classy_object_2 = ClassyImages()
print(my_classy_object_1.makelist("b")) # prints: ['b']
ClassyImages.listb.add("bb")
print(my_classy_object_1.makelist("b")) # prints: ['b', 'bb']
print(my_classy_object_2.makelist("b")) # prints: ['b', 'bb']
My answer glossed over what you may really be asking - how to tell it which list to look at. You can inject the list into the argument, as suggested by sjaymj64. Or you can pass a string or a number into the function, similar to how I did for the class-level makelist. It's largely up to you - provide whatever way seems most fitting and convenient for letting the logic of makelist choose which of its components to look at.

Related

(Python) How to override list's method python?

well, i want to add method in list.
So, i made new child class like this.
class list(list):
def findAll(self,position):
data = []
for i in range(len(self)):
if(self[i] == position):
data.append(i)
return data
k = list()
k.append(1)
k.append(2)
k.append(3)
k.append(4)
print(k.findAll(10))
but i want to make code like this.
class list(list):
def findAll(self,position):
data = []
for i in range(len(self)):
if(self[i] == position):
data.append(i)
return data
k = [10,1,2,3,4,5,10,10,10,10,10] #when i make list, i want use '[' and ']'
print(k.findAll(10))#it occur AttributeError: 'list' object has no attribute 'findAll'
how can i make this?
when i make list, i want use '[' and ']'
i tried this code
class list(list):
def findAll(self,position):
data = []
for i in range(len(self)):
if(self[i] == position):
data.append(i)
return data
k = [10,1,2,3,4,5,10,10,10,10,10]
k = list(k)
print(k.findAll(10))
Usually a child class shouldn't have the same name as the parent, especially when it's a standard class, it can lead to lots of confusion down the road.
you could use the same name, but it should be in a particular package, so when it's used, to be sure it's not confused with the other one.
Another thing here, when you want to use your list class, you need to instantiate it.
With this k = [10,1,2,3,4,5,10,10,10,10,10]you instantiate the standard list, also with `k = list(k)' because you use the same name, instead of package.class to distinguish, also because in your class you have no overwritten method that takes a list as argument, no conversion method etc.
The answer already given by the other user should be ok, but so you understand what is what and why I wrote this
You can't override built in type's method.
You can create a new class, that "extends" class "list" (inheritance).
class ExtendedList(list):
def find_all(self, num):
return [i for i in range(len(self)) if self[i] == num]
k = ExtendedList([1, 2, 3, 3, 3, 4, 3])
print(k.find_all(3))
# [2, 3, 4, 6]

python class instance variables and class variables

I'm having a problem understanding how class / instance variables work in Python. I don't understand why when I try this code the list variable seems to be a class variable
class testClass():
list = []
def __init__(self):
self.list.append('thing')
p = testClass()
print p.list
f = testClass()
print f.list
Output:
['thing']
['thing', 'thing']
and when I do this it seems to be an instance variable
class testClass():
def __init__(self):
self.list = []
self.list.append('thing')
p = testClass()
print p.list
f = testClass()
print f.list
Output:
['thing']
['thing']
This is because of the way Python resolves names with the .. When you write self.list the Python runtime tries to resolve the list name first by looking for it in the instance object, and if it is not found there, then in the class instance.
Let's look into it step by step
self.list.append(1)
Is there a list name into the object self?
Yes: Use it! Finish.
No: Go to 2.
Is there a list name into the class instance of object self?
Yes: Use it! Finish
No: Error!
But when you bind a name things are different:
self.list = []
Is there a list name into the object self?
Yes: Overwrite it!
No: Bind it!
So, that is always an instance variable.
Your first example creates a list into the class instance, as this is the active scope at the time (no self anywhere). But your second example creates a list explicitly in the scope of self.
More interesting would be the example:
class testClass():
list = ['foo']
def __init__(self):
self.list = []
self.list.append('thing')
x = testClass()
print x.list
print testClass.list
del x.list
print x.list
That will print:
['thing']
['foo']
['foo']
The moment you delete the instance name the class name is visible through the self reference.
Python has interesting rules about looking up names. If you really want to bend your mind, try this code:
class testClass():
l = []
def __init__(self):
self.l = ['fred']
This will give each instance a variable called l that masks the class variable l. You will still be able to get at the class variable if you do self.__class__.l.
The way I think of it is this... Whenever you do instance.variable (even for method names, they're just variables who's values happen to be functions) it looks it up in the instance's dictionary. And if it can't find it there, it tries to look it up in the instance's class' dictionary. This is only if the variable is being 'read'. If it's being assigned to, it always creates a new entry in the instance dictionary.
In your first example, list is an attribute of the class, shared by all instances of it. This means that you can even access it without having an object of type testClass:
>>> class testClass():
... list = []
... def __init__(self):
... self.list.append("thing")
...
>>> testClass.list
[]
>>> testClass.list.append(1)
>>> testClass.list
[1]
But all objects share the list attribute with the class and each other:
>>> testObject = testClass()
>>> testObject.list
[1, 'thing']
>>> testClass.list
[1, 'thing']
>>>
>>> testObject2 = testClass()
>>> testClass.list
[1, 'thing', 'thing']
>>> testObject2.list
[1, 'thing', 'thing']
When you instantiate a class, __init__ method is automatically executed.
In the first case your list is a class attribute and is shared by all its instances. You got two 'thing's because you appended one when instantitating p and another when instantiated f (the first one was already appended at the first call).

Accessing list items with getattr/setattr in Python

Trying to access/assign items in a list with getattr and setattr funcions in Python.
Unfortunately there seems to be no way of passing the place in the list index along with the list name.
Here's some of my tries with some example code:
class Lists (object):
def __init__(self):
self.thelist = [0,0,0]
Ls = Lists()
# trying this only gives 't' as the second argument. Python error results.
# Interesting that you can slice a string to in the getattr/setattr functions
# Here one could access 'thelist' with with [0:7]
print getattr(Ls, 'thelist'[0])
# tried these two as well to no avail.
# No error message ensues but the list isn't altered.
# Instead a new variable is created Ls.'' - printed them out to show they now exist.
setattr(Lists, 'thelist[0]', 3)
setattr(Lists, 'thelist\[0\]', 3)
print Ls.thelist
print getattr(Ls, 'thelist[0]')
print getattr(Ls, 'thelist\[0\]')
Also note in the second argument of the attr functions you can't concatenate a string and an integer in this function.
Cheers
getattr(Ls, 'thelist')[0] = 2
getattr(Ls, 'thelist').append(3)
print getattr(Ls, 'thelist')[0]
If you want to be able to do something like getattr(Ls, 'thelist[0]'), you have to override __getattr__ or use built-in eval function.
You could do:
l = getattr(Ls, 'thelist')
l[0] = 2 # for example
l.append("bar")
l is getattr(Ls, 'thelist') # True
# so, no need to setattr, Ls.thelist is l and will thus be changed by ops on l
getattr(Ls, 'thelist') gives you a reference to the same list that can be accessed with Ls.thelist.
As you discovered, __getattr__ doesn't work this way. If you really want to use list indexing, use __getitem__ and __setitem__, and forget about getattr() and setattr(). Something like this:
class Lists (object):
def __init__(self):
self.thelist = [0,0,0]
def __getitem__(self, index):
return self.thelist[index]
def __setitem__(self, index, value):
self.thelist[index] = value
def __repr__(self):
return repr(self.thelist)
Ls = Lists()
print Ls
print Ls[1]
Ls[2] = 9
print Ls
print Ls[2]

Inspect python class attributes

I need a way to inspect a class so I can safely identify which attributes are user-defined class attributes. The problem is that functions like dir(), inspect.getmembers() and friends return all class attributes including the pre-defined ones like: __class__, __doc__, __dict__, __hash__. This is of course understandable, and one could argue that I could just make a list of named members to ignore, but unfortunately these pre-defined attributes are bound to change with different versions of Python therefore making my project volnerable to changed in the python project - and I don't like that.
example:
>>> class A:
... a=10
... b=20
... def __init__(self):
... self.c=30
>>> dir(A)
['__doc__', '__init__', '__module__', 'a', 'b']
>>> get_user_attributes(A)
['a','b']
In the example above I want a safe way to retrieve only the user-defined class attributes ['a','b'] not 'c' as it is an instance attribute. So my question is... Can anyone help me with the above fictive function get_user_attributes(cls)?
I have spent some time trying to solve the problem by parsing the class in AST level which would be very easy. But I can't find a way to convert already parsed objects to an AST node tree. I guess all AST info is discarded once a class has been compiled into bytecode.
Below is the hard way. Here's the easy way. Don't know why it didn't occur to me sooner.
import inspect
def get_user_attributes(cls):
boring = dir(type('dummy', (object,), {}))
return [item
for item in inspect.getmembers(cls)
if item[0] not in boring]
Here's a start
def get_user_attributes(cls):
boring = dir(type('dummy', (object,), {}))
attrs = {}
bases = reversed(inspect.getmro(cls))
for base in bases:
if hasattr(base, '__dict__'):
attrs.update(base.__dict__)
elif hasattr(base, '__slots__'):
if hasattr(base, base.__slots__[0]):
# We're dealing with a non-string sequence or one char string
for item in base.__slots__:
attrs[item] = getattr(base, item)
else:
# We're dealing with a single identifier as a string
attrs[base.__slots__] = getattr(base, base.__slots__)
for key in boring:
del attrs['key'] # we can be sure it will be present so no need to guard this
return attrs
This should be fairly robust. Essentially, it works by getting the attributes that are on a default subclass of object to ignore. It then gets the mro of the class that's passed to it and traverses it in reverse order so that subclass keys can overwrite superclass keys. It returns a dictionary of key-value pairs. If you want a list of key, value tuples like in inspect.getmembers then just return either attrs.items() or list(attrs.items()) in Python 3.
If you don't actually want to traverse the mro and just want attributes defined directly on the subclass then it's easier:
def get_user_attributes(cls):
boring = dir(type('dummy', (object,), {}))
if hasattr(cls, '__dict__'):
attrs = cls.__dict__.copy()
elif hasattr(cls, '__slots__'):
if hasattr(base, base.__slots__[0]):
# We're dealing with a non-string sequence or one char string
for item in base.__slots__:
attrs[item] = getattr(base, item)
else:
# We're dealing with a single identifier as a string
attrs[base.__slots__] = getattr(base, base.__slots__)
for key in boring:
del attrs['key'] # we can be sure it will be present so no need to guard this
return attrs
Double underscores on both ends of 'special attributes' have been a part of python before 2.0. It would be very unlikely that they would change that any time in the near future.
class Foo(object):
a = 1
b = 2
def get_attrs(klass):
return [k for k in klass.__dict__.keys()
if not k.startswith('__')
and not k.endswith('__')]
print get_attrs(Foo)
['a', 'b']
Thanks aaronasterling, you gave me the expression i needed :-)
My final class attribute inspector function looks like this:
def get_user_attributes(cls,exclude_methods=True):
base_attrs = dir(type('dummy', (object,), {}))
this_cls_attrs = dir(cls)
res = []
for attr in this_cls_attrs:
if base_attrs.count(attr) or (callable(getattr(cls,attr)) and exclude_methods):
continue
res += [attr]
return res
Either return class attribute variabels only (exclude_methods=True) or also retrieve the methods.
My initial tests og the above function supports both old and new-style python classes.
/ Jakob
If you use new style classes, could you simply subtract the attributes of the parent class?
class A(object):
a = 10
b = 20
#...
def get_attrs(Foo):
return [k for k in dir(Foo) if k not in dir(super(Foo))]
Edit: Not quite. __dict__,__module__ and __weakref__ appear when inheriting from object, but aren't there in object itself. You could special case these--I doubt they'd change very often.
Sorry for necro-bumping the thread. I'm surprised that there's still no simple function (or a library) to handle such common usage as of 2019.
I'd like to thank aaronasterling for the idea. Actually, set container provides a more straightforward way to express it:
class dummy: pass
def abridged_set_of_user_attributes(obj):
return set(dir(obj))-set(dir(dummy))
def abridged_list_of_user_attributes(obj):
return list(abridged_set_of_user_attributes(obj))
The original solution using list comprehension is actually two level of loops because there are two in keyword compounded, despite having only one for keyword made it look like less work than it is.
This worked for me to include user defined attributes with __ that might be be found in cls.__dict__
import inspect
class A:
__a = True
def __init__(self, _a, b, c):
self._a = _a
self.b = b
self.c = c
def test(self):
return False
cls = A(1, 2, 3)
members = inspect.getmembers(cls, predicate=lambda x: not inspect.ismethod(x))
attrs = set(dict(members).keys()).intersection(set(cls.__dict__.keys()))
__attrs = {m[0] for m in members if m[0].startswith(f'_{cls.__class__.__name__}')}
attrs.update(__attrs)
This will correctly yield: {'_A__a', '_a', 'b', 'c'}
You can update to clean the cls.__class__.__name__ if you wish

How do I get the string representation of a variable in python?

I have a variable x in python. How can i find the string 'x' from the variable. Here is my attempt:
def var(v,c):
for key in c.keys():
if c[key] == v:
return key
def f():
x = '321'
print 'Local var %s = %s'%(var(x,locals()),x)
x = '123'
print 'Global var %s = %s'%(var(x,locals()),x)
f()
The results are:
Global var x = 123
Local var x = 321
The above recipe seems a bit un-pythonesque. Is there a better/shorter way to achieve the same result?
Q: I have a variable x in python. How can i find the string 'x' from the variable.
A: If I am understanding your question properly, you want to go from the value of a variable to its name. This is not really possible in Python.
In Python, there really isn't any such thing as a "variable". What Python really has are "names" which can have objects bound to them. It makes no difference to the object what names, if any, it might be bound to. It might be bound to dozens of different names, or none.
Consider this example:
foo = 1
bar = foo
baz = foo
Now, suppose you have the integer object with value 1, and you want to work backwards and find its name. What would you print? Three different names have that object bound to them, and all are equally valid.
print(bar is foo) # prints True
print(baz is foo) # prints True
In Python, a name is a way to access an object, so there is no way to work with names directly. You might be able to search through locals() to find the value and recover a name, but that is at best a parlor trick. And in my above example, which of foo, bar, and baz is the "correct" answer? They all refer to exactly the same object.
P.S. The above is a somewhat edited version of an answer I wrote before. I think I did a better job of wording things this time.
I believe the general form of what you want is repr() or the __repr__() method of an object.
with regards to __repr__():
Called by the repr() built-in function
and by string conversions (reverse
quotes) to compute the “official”
string representation of an object.
See the docs here: object.repr(self)
stevenha has a great answer to this question. But, if you actually do want to poke around in the namespace dictionaries anyway, you can get all the names for a given value in a particular scope / namespace like this:
def foo1():
x = 5
y = 4
z = x
print names_of1(x, locals())
def names_of1(var, callers_namespace):
return [name for (name, value) in callers_namespace.iteritems() if var is value]
foo1() # prints ['x', 'z']
If you're working with a Python that has stack frame support (most do, CPython does), it isn't required that you pass the locals dict into the names_of function; the function can retrieve that dictionary from its caller's frame itself:
def foo2():
xx = object()
yy = object()
zz = xx
print names_of2(xx)
def names_of2(var):
import inspect
callers_namespace = inspect.currentframe().f_back.f_locals
return [name for (name, value) in callers_namespace.iteritems() if var is value]
foo2() # ['xx', 'zz']
If you're working with a value type that you can assign a name attribute to, you can give it a name, and then use that:
class SomeClass(object):
pass
obj = SomeClass()
obj.name = 'obj'
class NamedInt(int):
__slots__ = ['name']
x = NamedInt(321)
x.name = 'x'
Finally, if you're working with class attributes and you want them to know their names (descriptors are the obvious use case), you can do cool tricks with metaclass programming like they do in the Django ORM and SQLAlchemy declarative-style table definitions:
class AutonamingType(type):
def __init__(cls, name, bases, attrs):
for (attrname, attrvalue) in attrs.iteritems():
if getattr(attrvalue, '__autoname__', False):
attrvalue.name = attrname
super(AutonamingType,cls).__init__(name, bases, attrs)
class NamedDescriptor(object):
__autoname__ = True
name = None
def __get__(self, instance, instance_type):
return self.name
class Foo(object):
__metaclass__ = AutonamingType
bar = NamedDescriptor()
baaz = NamedDescriptor()
lilfoo = Foo()
print lilfoo.bar # prints 'bar'
print lilfoo.baaz # prints 'baaz'
There are three ways to get "the" string representation of an object in python:
1: str()
>>> foo={"a":"z","b":"y"}
>>> str(foo)
"{'a': 'z', 'b': 'y'}"
2: repr()
>>> foo={"a":"z","b":"y"}
>>> repr(foo)
"{'a': 'z', 'b': 'y'}"
3: string interpolation:
>>> foo={"a":"z","b":"y"}
>>> "%s" % (foo,)
"{'a': 'z', 'b': 'y'}"
In this case all three methods generated the same output, the difference is that str() calls dict.__str__(), while repr() calls dict.__repr__(). str() is used on string interpolation, while repr() is used by Python internally on each object in a list or dict when you print the list or dict.
As Tendayi Mawushe mentiones above, string produced by repr isn't necessarily human-readable.
Also, the default implementation of .__str__() is to call .__repr__(), so if the class does not have it's own overrides to .__str__(), the value returned from .__repr__() is used.

Categories

Resources