Python: How to rename public available variable? - python

Imagine having this class:
class Foo:
def __init__(self):
self.nr = 0
Imagine further Foo being widely used. Several scripts and users use the variable Foo.nr to read and write its value.
Now suppose the developer wants to change the name of .nr to .val.
class Foo:
def __init__(self):
self.val = 0
In order to not force the users to update their code, is it somehow possible to make them access .val by writing .nr? Like this:
f1 = Foo()
print(f1.nr)
I came up with properties and getter and setter methods but I don't see how they might help.

class Foo:
def __init__(self):
self.val = 0
#property
def nr(self):
return self.val
#nr.setter
def nr(self, value):
self.val = value
f1 = Foo()
print(f1.nr)
would give 0 as expected.

Related

How to access class attributes within a class variable?

I want to reference a class attribute from class variable but it gives me error 'self is not defined'
class Test:
def __init__(self, val):
self.val = val
data = self.val
def main(self):
print(self.data)
When you say data = self.val outside __init__, you are defining a class variable, not an instance variable. This line affects all objects of type Test. However, self is not recognized in this scope.
If you want val to update all instances of this class,
class Test:
data = None
def __init__(self, val):
self.val = val
Test.data = self.val
In this case,
test1 = Test(1)
print(test1.data) # prints 1
print(Test.data) # prints 1
test2 = Test(2)
print(test1.data) # prints 2
print(test2.data) # prints 2
print(Test.data) # prints 2

What is the difference between readable property method and a callable function that is just returns the data as a property can?

I have a property that returns list of names with "ash" in it
class BaseClass(object):
def __init__(self):
self.filter_key = ""
self.name = ""
def filter_names(self, filter_key):
self.filter_key = filter_key
#property
def student_names(self):
return self.names
def callable_function_names(self):
return names
and then student class that inherits BaseClass
class StudentClass(BaseClass):
#property
def student_names(self):
names = super(StudentClass, self).student_names
return [name for name in names if self.filter_students in name]
#property
def filter_key(self):
"""Gets """
return self.filter_key
#slot_key.setter
def filter_key(self, key):
"""Sets name filter"""
self.filter_names(key)
# or by doing :
def callable_function_names(self):
names = super(StudentClass, self).callable_function_names()
return [name for name in names if self.filter_students in name]
So if I create obj of the student class.
studentclsObj = StudentClass()
studentclsObj.filter_key = "ash"
print studentclsObj.student_names
print studentclsObj.callable_function_names()
I can achieve the same result with both above prints, is there any difference and what is preferred and right way to do ?
One use case of properties is not breaking API. This is one of main strengths of python IMO. You can take a function, make transform it in a callable object, add new functionality without breaking old code, now the property
I see three main uses of properties over attributes,
Read only attributes
Is easy to create read only attributes with properties. They are non verbose, self documenting and simple
class Foo:
def __init__(self, bar):
self._bar = bar
#property
def bar(self):
return self._bar
Validation on writable properties
class Foo:
def __init__(self, bar):
self._bar = bar
#property
def bar(self):
return self._bar
#bar.setter
def bar(self, val):
if valid(val):
self._bar = val
This is a kind of defensive programming
Keep API compatibility
Imagine that you have a class for a bank account, with
a balance property
class BankAccount:
def __init__(self):
self.balance = 0
You have this code and it works fine. But know your client
says, I need you to log every balance lookup. You can replace
the attribute by a property without breaking old code
class BankAccount:
def __init__(self):
self._balance = 0
#property
def balance(self):
self.log_balance_read()
return self._balance
There is no difference between a property and a method which return the same value. Go for the simpler, use method for actions and state changes and attributes for real attributes, if you need to add logic to attribute lookup, python will let you do it

Importing class variable python

I have two python classes, one uses the other's variable
class A:
class A(object):
variable = None
#classmethod
def init_variable(cls):
cls.variable = something
class B:
variable = __import__('module').A.variable
class B(object):
#staticmethod
def method():
return variable
I simplified my problem as much as possible. So my question is why I still have B.method() returning NoneType even if I update A.variable class variable with something using init_variable
I changed your code a bit so that it'd actually do what you want:
your_package/klass_A.py
class A(object):
variable = None
#classmethod
def init_variable(cls, something):
cls.variable = something
your_package/klass_B.py
from your_package.klass_A import A
class B(object):
#staticmethod
def method():
return A.variable
Now, you can actually update A.variable and use the updated variable in B as well. For example this:
print B.method()
A.init_variable('123')
print B.method()
returns:
None
123

Issue with class variable in Python

I am new to python.I was doing following code and I met an undesired outcome. Please look onto my code and let me know what am I doing wrong:
class TestClass(object):
#classmethod
def __init__(self, val):
self.val = val
#classmethod
def value(self):
return self.val
def Test():
a = TestClass(9)
b = TestClass(8)
c = TestClass(7)
print(a.value(), b.value(), c.value())
expecting output as
9 8 7
but getting output as
7 7 7
what is wrong with my code.
Setting __init__ as a classmethod means you're actually passing the class to __init__ and self.val is actually set as a class variable, not an instance variable.
The final "initialization" you perform will override all the other values you've set.
Removing the #classmethods fixes the issue.
You have attached #classmethod to the __init__ function. As a result, if you call the __init__ (something you do at construction), self will not reference to the object you are about to construct, but to the class, so TestClass. Therefore there is only one value: attached to TestClass.
So TestClass(3) will be equivalent to something like TestClass.__init__(TestClass,3)...
You can solve the issue by removing the #classmethod decorator:
class TestClass(object):
def __init__(self, val): # no #classmethod
self.val = val
def value(self): # no #classmethod
return self.val
def Test():
a = TestClass(9)
b = TestClass(8)
c = TestClass(7)
print(a.value(), b.value(), c.value())
It is actually rather weird to use a #classmethod on an __init__ method. If you want to add attributes to the class, you can use type(..). So:
#classmethod
def __init__(cls, val):
cls.val = val
Is equivalent to:
def __init__(self, val):
type(self).val = val

Python : Set method attribute from within method

I am trying to make a python decorator that adds attributes to methods of a class so that I can access and modify those attributes from within the method itself. The decorator code is
from types import MethodType
class attribute(object):
def __init__(self, **attributes):
self.attributes = attributes
def __call__(self, function):
class override(object):
def __init__(self, function, attributes):
self.__function = function
for att in attributes:
setattr(self, att, attributes[att])
def __call__(self, *args, **kwargs):
return self.__function(*args, **kwargs)
def __get__(self, instance, owner):
return MethodType(self, instance, owner)
retval = override(function, self.attributes)
return retval
I tried this decorator on the toy example that follows.
class bar(object):
#attribute(a=2)
def foo(self):
print self.foo.a
self.foo.a = 1
Though I am able to access the value of attribute 'a' from within foo(), I can't set it to another value. Indeed, when I call bar().foo(), I get the following AttributeError.
AttributeError: 'instancemethod' object has no attribute 'a'
Why is this? More importantly how can I achieve my goal?
Edit
Just to be more specific, I am trying to find a simple way to implement static variable that are located within class methods. Continuing from the example above, I would like instantiate b = bar(), call both foo() and doo() methods and then access b.foo.a and b.doo.a later on.
class bar(object):
#attribute(a=2)
def foo(self):
self.foo.a = 1
#attribute(a=4)
def doo(self):
self.foo.a = 3
The best way to do this is to not do it at all.
First of all, there is no need for an attribute decorator; you can just assign it yourself:
class bar(object):
def foo(self):
print self.foo.a
self.foo.a = 1
foo.a = 2
However, this still encounters the same errors. You need to do:
self.foo.__dict__['a'] = 1
You can instead use a metaclass...but that gets messy quickly.
On the other hand, there are cleaner alternatives.
You can use defaults:
def foo(self, a):
print a[0]
a[0] = 2
foo.func_defaults = foo.func_defaults[:-1] + ([2],)
Of course, my preferred way is to avoid this altogether and use a callable class ("functor" in C++ words):
class bar(object):
def __init__(self):
self.foo = self.foo_method(self)
class foo_method(object):
def __init__(self, bar):
self.bar = bar
self.a = 2
def __call__(self):
print self.a
self.a = 1
Or just use classic class attributes:
class bar(object):
def __init__(self):
self.a = 1
def foo(self):
print self.a
self.a = 2
If it's that you want to hide a from derived classes, use whatever private attributes are called in Python terminology:
class bar(object):
def __init__(self):
self.__a = 1 # this will be implicitly mangled as __bar__a or similar
def foo(self):
print self.__a
self.__a = 2
EDIT: You want static attributes?
class bar(object):
a = 1
def foo(self):
print self.a
self.a = 2
EDIT 2: If you want static attributes visible to only the current function, you can use PyExt's modify_function:
import pyext
def wrap_mod(*args, **kw):
def inner(f):
return pyext.modify_function(f, *args, **kw)
return inner
class bar(object):
#wrap_mod(globals={'a': [1]})
def foo(self):
print a[0]
a[0] = 2
It's slightly ugly and hackish. But it works.
My recommendation would be just to use double underscores:
class bar(object):
__a = 1
def foo(self):
print self.__a
self.__a = 2
Although this is visible to the other functions, it's invisible to anything else (actually, it's there, but it's mangled).
FINAL EDIT: Use this:
import pyext
def wrap_mod(*args, **kw):
def inner(f):
return pyext.modify_function(f, *args, **kw)
return inner
class bar(object):
#wrap_mod(globals={'a': [1]})
def foo(self):
print a[0]
a[0] = 2
foo.a = foo.func_globals['a']
b = bar()
b.foo() # prints 1
b.foo() # prints 2
# external access
b.foo.a[0] = 77
b.foo() # prints 77
While You can accomplish Your goal by replacing self.foo.a = 1 with self.foo.__dict__['a'] = 1 it is generally not recommended.
If you are using Python2 - (and not Python3) - whenever you retrieve a method from an instance, a new instance method object is created which is a wrapper to the original function defined in the class body.
The instance method is a rather transparent proxy to the function - you can retrieve the function's attributes through it, but not set them - that is why setting an item in self.foo.__dict__ works.
Alternatively you can reach the function object itself using: self.foo.im_func - the im_func attribute of instance methods point the underlying function.
Based on other contributors's answers, I came up with the following workaround. First, wrap a dictionnary in a class resolving non-existant attributes to the wrapped dictionnary such as the following code.
class DictWrapper(object):
def __init__(self, d):
self.d = d
def __getattr__(self, key):
return self.d[key]
Credits to Lucas Jones for this code.
Then implement a addstatic decorator with a statics attribute that will store the static attributes.
class addstatic(object):
def __init__(self, **statics):
self.statics = statics
def __call__(self, function):
class override(object):
def __init__(self, function, statics):
self.__function = function
self.statics = DictWrapper(statics)
def __call__(self, *args, **kwargs):
return self.__function(*args, **kwargs)
def __get__(self, instance, objtype):
from types import MethodType
return MethodType(self, instance)
retval = override(function, self.statics)
return retval
The following code is an example of how the addstatic decorator can be used on methods.
class bar(object):
#attribute(a=2, b=3)
def foo(self):
self.foo.statics.a = 1
self.foo.statics.b = 2
Then, playing with an instance of the bar class yields :
>>> b = bar()
>>> b.foo.statics.a
2
>>> b.foo.statics.b
3
>>> b.foo()
>>> b.foo.statics.a
3
>>> b.foo.statics.b
5
The reason for using this statics dictionnary follows jsbueno's answer which suggest that what I want would require overloading the dot operator of and instance method wrapping the foo function, which I am not sure is possible. Of course, the method's attribute could be set in self.foo.__dict__, but since it not recommended (as suggested by brainovergrow), I came up with this workaround. I am not certain this would be recommended either and I guess it is up for comments.

Categories

Resources