member or class variables in python - python

I come from Java, so I'm getting confused here.
class Sample(object):
x = 100 # class var?
def __init__(self, value):
self.y = value # instance var?
z = 300 # private var? how do we access this outside Sample?
What is the difference between the 3 variable declarations?

class Sample(object):
x = 100
_a = 1
__b = 11
def __init__(self, value):
self.y = value
self._c = 'private'
self.__d = 'more private'
z = 300
In this example:
x is class variable,
_a is private class variable (by naming convention),
__b is private class variable (mangled by interpreter),
y is instance variable,
_c is private instance variable (by naming convention),
__d is private instance variable (mangled by interpreter),
z is local variable within scope of __init__ method.
In case of single underscore in names, it's strictly a convention. It is still possible to access these variables. In case of double underscore names, they are mangled. It's still possible to circumvent that.

#vartec is spot on. Since you come from Java, however, some clarification is in order:
Java has public and private members. Access to private members is strictly forbidden, and this is enforced by the language.
Python only has public members. There is no way to enforce something like java's private keyword.
If you want to declare that something is an implementation detail only and shouldn't be relied on by other code, you prefix it with a single underscore - _variable, _function(). This is a hint to other programmers that they shouldn't use that variable or that function, but it is not enforced.
It might seem like a feature has been omitted from Python, but the culture in Python is "everyone is a consenting adult". If you tell other programmers that something is "private" by prefixing it with an underscore, they will generally take the hint.

You seem to be getting the hang of it. The only one that you were completely wrong about is z = 300. This is a name that is local to the __init__ method. Python never inserts self for you in the same manner that C++ and Java will assume this where it can.
One thing to remember as you continue learning Python is that member functions can always be executed as class members. Consider the following:
>>> class Sample(object):
... def __init__(self, value):
... self.value = value
... def get_value(self):
... return self.value
...
>>> s = Sample(1)
>>> t = Sample(2)
>>> s.get_value()
1
>>> Sample.get_value(s)
1
>>> t.__class__.get_value(s)
1
The last three examples all call the member function of the s object. The last two use the fact that get_value is just an attribute of the Sample class that expects to receive an instance of Sample as the argument.

Related

How to return a variable using another one Python

After working a lot with swift, I got used to the following syntax:
private var __privateVar = 100 // Not accessible from outside the Class
public var public_var: Int = {
return __privateVar // Returns __privateVar, and is get-only variable
}
Is there a way to reproduce this in python 3?
Thanks a lot
Python doesn't even have the concept of access modifiers - so if you mean you want a private variable, that's not something you can do. You can, however, use a read-only property:
class Test:
def __init__(self):
self._var = 'some string'
#property
def var(self):
return self._var
Then, use it as such:
obj = Test()
obj.var # works
obj.var = 'whatever' # raises AttributeError
obj._var = 'whatever' # still works
It's noteworthy that you can somewhat emulate the behavior of a private variable by prefixing your variable with a double underscore (such as in __var), which introduces name mangling if used in a class scope. This is not foolproof, though, and you can always get around it if you really want to. Generally, however, Python developers know not to assign to variables starting in one or two underscores.

"Private" attribute properties in Python

I'm relatively new to Python so I hope I haven't missed something, but here goes...
I'm trying to write a Python module, and I'd like to create a class with a "private" attribute that can (or maybe 'should') only be modified through one or more functions within the module. This is in an effort to make the module more robust, since setting of this attribute outside of these functions could lead to unwanted behaviour. For example, I might have:
A class that stores x and y values for a scatter plot, Data
A function to read x and y values from a file and store them in the class, read()
A function to plot them, plot()
In this case, I would prefer if the user wasn't able to do something like this:
data = Data()
read("file.csv", data)
data.x = [0, 3, 2, 6, 1]
plot(data)
I realise that adding a single leading underscore to the name indicates to the user that the attribute should not be changed, i.e. rename to _x and add a property decorator so that the user can access the value without feeling guilty. However, what if I wanted to add a setter property as well:
class Data(object):
_x = []
_y = []
#property
def x(self):
return self._x
#x.setter
def x(self, value):
# Do something with value
self._x = value
I'm now in the same position as I was before - the user can no longer directly access the attribute _x, but they can still set it using:
data.x = [0, 3, 2, 6, 1]
Ideally I'd rename the property function definitions to _x(), but this leads to confusion about what self._x actually means (depending on the order in which they are declared, this seems to result in either the setter being called recursively or the setter being ignored in favour of the attribute).
A couple of solutions I can think of:
Add a double leading underscore to the attribute, __x, so that the name becomes mangled and does not get confused with the setter function. As I understand it, this should be reserved for attributes that a class does not wish to share with possible subclasses, so I'm not sure if this is a legitimate use.
Rename the attribute, e.g. _x_stored. While this solves the problem completely, it makes the code harder to read and introduces naming convention issues - which attributes do I rename? just the ones that are relevant? just the ones that have properties? just the ones within this class?
Are either of the above solutions applicable? And if not, is there a better way to solve this problem?
Edit
Thanks for the responses so far. A few points thrown up by the comments:
I want to retain the extra logic that the setter property gives me - the # Do something with value section in the above example - so internally setting the attribute through direct access of self._x doesn't solve the problem.
Removing the setter property and creating a separate function _set_x() does solve the problem, but is not a very neat solution since it allows setting of _x in two different ways - either by calling that function or through direct access of self._x. I'd then have to keep track of which attributes should be set by their own (non-property) setter function and which should be modified through direct access. I'd probably rather use one of the solutions I suggested above, because even though they make a mess of the naming conventions within the class they are at least consistent in their use outside of the class, i.e. they all use the syntactical sugar of properties. If there's no way of doing this in a neater way then I guess I just have to choose the one that causes the least disruption.
If you want to discourage users from changing a property, but want it to be clear that they can read it, I'd use #property without providing a setter, similar to what you described earlier:
class Data(object):
def __init__(self):
self._x = []
self._y = []
#property
def x(self):
return self._x
#property
def y(self):
return self._x
I know you mention "What if I wanted to add a setter to the property?", but I guess I would counter that with: Why add the setter if you don't want your clients to be able to set the property? Internally, you can access self._x directly.
As for a client directly accessing _x or _y, any variable with an '_' prefix is understood to be "private" in Python, so you should trust your clients to obey that. If they don't obey that, and end up screwing things up, that's their own fault. This kind of mindset is counter to a many other languages (C++, Java, etc.) where keeping data private is considered very important, but Python's culture is just different in this regard.
Edit
One other note, since your private properties in this particular case are lists, which are mutable (unlike strings or ints, which are immutable), a client could end up changing them somewhat accidentally:
>>> d = Data()
>>> print d.x
['1', '2']
>>> l = d.x
>>> print l
['1', '2']
>>> l.append("3")
>>> print d.x
['1', '2', '3'] # Oops!
If you want to avoid this, you'd need your property to return a copy of the list:
#property
def x(self):
return list(self._x)
If you want less convoluted properties, that manage their own storage without leaving it open to "under the hood" alteration, you can define a class (similar to property) and use it to declare your class member:
I called mine 'Field':
class Field:
def __init__(self,default=None):
self.valueName = None # actual attribute name
self.default = default # type or value or lambda
if not callable(default): self.default = lambda:default
self._didSet = None # observers
self._willSet = None
def findName(self,owner): # find name of field
if self.valueName: return # once per field for class
for name,attr in owner.__dict__.items():
if attr is self:
self.valueName = f"<{name}>" # actual attribute name
break
def __get__(self,obj,owner=None): # generic getter
if not obj: return self
self.findName(owner or type(obj))
value = getattr(obj,self.valueName,self) # attribute from instance
if value is self:
value = self.default() # default value
setattr(obj,self.valueName,value) # set at 1st reference
return value
def __set__(self,obj,value): # generic setter
self.findName(type(obj))
if self._willSet: value = self._willSet(obj,value)
if self._didSet: oldValue = self.__get__(obj)
setattr(obj,self.valueName,value) # attribute in instance
if self._didSet: self._didSet(obj,oldValue)
def willSet(self,f): self._willSet = f
def didSet(self,f): self._didSet = f
usage:
class myClass:
lastName = Field("Doe")
firstName = Field("")
age = Field(int)
gender = Field("M")
relatives = Field(list)
#lastName.willSet
def _(self,newValue): # no function name needed
return newValue.capitalize()
#lastName.didSet
def _(self,oldValue): # no function name needed
print('last name changed from',oldValue,'to',self.lastName)
c = myClass()
c.firstName = "John"
c.lastName = "Smith"
# last name changed from Doe to Smith
c.relatives.extend(['Lucy','Frank'])
print(c.gender)
# M
print(c.__dict__)
# {'<lastName>': 'Smith', '<firstName>': 'John',
'<relatives>': ['Lucy', 'Frank'], '<gender>': 'M'}
Attributes added to the instance are not accessible from Python because they use identifiers that would not be valid in code.
Because you define default values at the class level, there is no need to set the field values in the constructor (although you could still do it as needed)
Field values are only added as instance attributes when they are referenced making the instance creation process more efficient.
Note that my actual Field class is a lot more sophisticated and supports change tracking, more observer functions, type checking, and read-only/calculated fields. I boiled it down to essentials for this response
For Private/Public method protection, you may want to look at this answer

Best way to publicize instance attributes

I'm new to Python, coming from C#. I know how to publicize class attributes and methods. I'd like to publicize my instance variables. Having intellisense detect them would be ideal. Also, please let me know if this is not pythonic or if I should be doing something else.
class MyClass(Object):
class_attribute = "Foo"
#This is the way I'm currently publicizing instance attributes.
#Basically I'm using properties instead of instance attributes.
#property
def instance_property(self):
return self._instance_property
#instance_property.setter
def instance_property_set(self, value):
self._instance_property = value
You are not required to do so. Python community uses a convention that any class member which name have:
leading underscore - considered private/protected,
double leading underscore considered class private - mimics private access by using name mangling. Member is not accessible by it's name outside the class, as it's prefixed with class name (but still accessible if you directly call it)
double leading underscore and double trailing underscore - overrides some behavior, closest C# analogue would be built-in interface implementations and overrides of Object methods. More info in the docs.
everything else considered public.
You can do properties, if you actually want to do some calculations upon acessing a member, but it's not considered/enforced as best practice.
class MyClass(Object):
class_attribute = "Foo"
def __init__(self,*args,**kwargs):
self.instance_property = "whatever"
often it(setting required values) is done in the init function ... or through documentation, or setting it to an invalid default value that you later check and inform consumer that they must set variable X before calling Calculate() or whatever ... getters and setters are not meant to inform a consumer what variables they should set
there is no reason to use getters/setters unless you actually need to do some work (not just pass it on to another variable)
a use case for a setter would be
class GPIO(object):
#property
def value(self):
return open("/sys/class/gpio/gpio141/value").read()
#value.setter
def set_value(self,val):
open("/sys/class/gpio/gpio141/value","w").write(val)

How should I choose between using instance vs. class attributes?

I tried this example code:
class testclass:
classvar = 'its classvariable LITERAL'
def __init__(self,x,y):
self.z = x
self.classvar = 'its initvariable LITERAL'
self.test()
def test(self):
print('class var',testclass.classvar)
print('instance var',self.classvar)
if __name__ == '__main__':
x = testclass(2,3)
I need some clarification. In both cases, I'm able to access the class attribute and instance in the test method.
So, suppose if I have to define a literal that needs to be used across all function, which would be the better way to define it: an instance attribute or a class attribute?
I found this in an old presentation made by Guido van Rossum in 1999 ( http://legacy.python.org/doc/essays/ppt/acm-ws/sld001.htm ) and I think it explains the topic beautifully:
Instance variable rules
On use via instance (self.x), search order:
(1) instance, (2) class, (3) base classes
this also works for method lookup
On assigment via instance (self.x = ...):
always makes an instance variable
Class variables "default" for instance variables
But...!
mutable class variable: one copy shared by all
mutable instance variable: each instance its own
Class variables are quite good for "constants" used by all the instances (that's all methods are technically). You could use module globals, but using a class variable makes it more clearly associated with the class.
There are often uses for class variables that you actually change, too, but it's usually best to stay away from them for the same reason you stay away from having different parts of your program communicate by altering global variables.
Instance variables are for data that is actually part of the instance. They could be different for each particular instance, and they often change over the lifetime of a single particular instance. It's best to use instance variables for data that is conceptually part of an instance, even if in your program you happen to only have one instance, or you have a few instances that in practice always have the same value.
It's good practice to only use class attributes if they are going to remain fixed, and one great thing about them is that they can be accessed outside of an instance:
class MyClass():
var1 = 1
def __init__(self):
self.var2 = 2
MyClass.var1 # 1 (you can reference var1 without instantiating)
MyClass.var2 # AttributeError: class MyClass has no attribute 'var2'
If MyClass.var is defined, it should be the same in every instance of MyClass, otherwise you get the following behaviour which is considered confusing.
a = MyClass()
b = MyClass()
a.var1, a.var2 # (1,2)
a.var1, a.var2 = (3,4) # you can change these variables
a.var1, a.var2 # (3,4)
b.var1, b.var2 # (1,2) # but they don't change in b
MyClass.var1 # 1 nor in MyClass
You should define it as a class attribute if you want it to be shared among all instances. You should define it as an instance variable if you want a separate one for each instance (e.g., if different instances might have different values for the variable).

"public" or "private" attribute in Python ? What is the best way?

In Python, I have the following example class :
class Foo:
self._attr = 0
#property
def attr(self):
return self._attr
#attr.setter
def attr(self, value):
self._attr = value
#attr.deleter
def attr(self):
del self._attr
As you can see, I have a simple "private" attribute "_attr" and a property to access it. There is a lot of codes to declare a simple private attribute and I think that it's not respecting the "KISS" philosophy to declare all attributes like that.
So, why not declare all my attributes as public attributes if I don't need a particular getter/setter/deleter ?
My answer will be :
Because the principle of encapsulation (OOP) says otherwise!
What is the best way ?
Typically, Python code strives to adhere to the Uniform Access Principle. Specifically, the accepted approach is:
Expose your instance variables directly, allowing, for instance, foo.x = 0, not foo.set_x(0)
If you need to wrap the accesses inside methods, for whatever reason, use #property, which preserves the access semantics. That is, foo.x = 0 now invokes foo.set_x(0).
The main advantage to this approach is that the caller gets to do this:
foo.x += 1
even though the code might really be doing:
foo.set_x(foo.get_x() + 1)
The first statement is infinitely more readable. Yet, with properties, you can add (at the beginning, or later on) the access control you get with the second approach.
Note, too, that instance variables starting with a single underscore are conventionally private. That is, the underscore signals to other developers that you consider the value to be private, and they shouldn't mess with it directly; however, nothing in the language prevents them from messing with it directly.
If you use a double leading underscore (e.g., __x), Python does a little obfuscation of the name. The variable is still accessible from outside the class, via its obfuscated name, however. It's not truly private. It's just kind of ... more opaque. And there are valid arguments against using the double underscore; for one thing, it can make debugging more difficult.
The "dunder" (double underscore, __) prefix prevents access to attribute, except through accessors.
class Foo():
def __init__(self):
self.__attr = 0
#property
def attr(self):
return self.__attr
#attr.setter
def attr(self, value):
self.__attr = value
#attr.deleter
def attr(self):
del self.__attr
Some examples:
>>> f = Foo()
>>> f.__attr # Not directly accessible.
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__attr'
>>> '__attr' in f.__dir__() # Not listed by __dir__()
False
>>> f.__getattribute__('__attr') # Not listed by __getattribute__()
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__attr'
>>> f.attr # Accessible by implemented getter.
0
>>> f.attr = 'Presto' # Can be set by implemented setter.
>>> f.attr
'Presto'
>>> f.__attr = 'Tricky?' # Can we set it explicitly?
>>> f.attr # No. By doing that we have created a
'Presto' # new but unrelated attribute, same name.
However, you can access this type of attribute through name mangling (_classname__attribute), which Python does in the background:
>>> f._Foo__attr
0
>>> f.__getattribute__('_Foo__attr')
0
Quite simply, the OOP principles are wrong. Why this is is a long discussion which leads to flamewars and is probably off topic for this site. :-)
In Python there is not private attributes, you can't protect them, and this is never a real problem. So don't. Easy! :)
Then comes the question: Should you have a leading underscore or not. And in the example you have here you should definitely not. A leading underscore in Python is a convention to show that something is internal, and not a part of the API, and that you should use it on your own risk. This is obviously not the case here, but it's a common and useful convention.
Python doesn't have public OR private attributes. All attributes are accessible to all code.
self.attr = 0 #Done
Your method isn't in any way making _attr private, it's just a bit of obfuscation.
See this link:https://docs.python.org/2/tutorial/classes.html
9.6. Private Variables and Class-local References
“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.
Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling. Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.
As others have said, private attributes in Python are merely a convention. The use of property syntax should be used for special processing when attributes are bound, modified or deleted. The beauty of Python is that you can start off by just using normal attribute binding, e.g., self.attr = 0 and if at some later date you decide you want to restrict the value of attr to say 0 <= attr <=100, you can make attr a property and define a method to make sure this condition is true without ever having to change any user code.
To make an attribute private, you just have to do self.__attr
class Foo:
self.__attr = 0
#property
def attr(self):
return self._attr
#attr.setter
def attr(self, value):
self._attr = value
#attr.deleter
def attr(self):
del self._attr
In Python, unless you need special behavior out of an attribute, there's no need to hide it behind accessor methods. If an attribute is for internal use only, prepend it with an underscore.
The nice thing about properties is that they given you a really cool interface to work with. Sometimes it's handy to derive a property based on some other (ie. BMI is defined by weight and height). The user of the interface doesn't have to know this of course.
I prefer this way over having explicit getters and setters like in Java ie. Way nicer. :)

Categories

Resources